l3.c (1367583B)
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: l3.c 8 * Purpose: Firebolt L3 function implementations 9 */ 10 #include <shared/bsl.h> 11 12 #include <soc/defs.h> 13 #ifdef INCLUDE_L3 14 15 #include <assert.h> 16 #include <sal/core/libc.h> 17 #include <shared/util.h> 18 #if defined(BCM_FIREBOLT_SUPPORT) 19 #include <soc/cm.h> 20 #include <soc/drv.h> 21 #include <soc/scache.h> 22 #include <soc/register.h> 23 #include <soc/memory.h> 24 #include <soc/l3x.h> 25 #include <soc/lpm.h> 26 #include <soc/defragment.h> 27 #include <soc/mcm/memregs.h> 28 #include <soc/format.h> 29 30 #ifdef ALPM_ENABLE 31 #include <soc/alpm.h> 32 #include <soc/esw/alpm_int.h> 33 #endif /* ALPM_ENABLE */ 34 #include <soc/tnl_term.h> 35 36 #include <bcm/l3.h> 37 #include <bcm/error.h> 38 39 #include <bcm_int/esw/mbcm.h> 40 #include <bcm_int/esw/firebolt.h> 41 #if defined(BCM_TRX_SUPPORT) 42 #include <bcm_int/esw/trx.h> 43 #include <bcm_int/esw/virtual.h> 44 #endif /* BCM_TRX_SUPPORT */ 45 #ifdef BCM_TRIUMPH_SUPPORT 46 #include <bcm_int/esw/triumph.h> 47 #include <bcm_int/esw/mpls.h> 48 #endif /* BCM_TRIUMPH_SUPPORT*/ 49 #ifdef BCM_SCORPION_SUPPORT 50 #include <bcm_int/esw/scorpion.h> 51 #endif /* BCM_SCORPION_SUPPORT*/ 52 #if defined(BCM_TRIUMPH2_SUPPORT) 53 #include <bcm_int/esw/triumph2.h> 54 #endif /* BCM_TRIUMPH2_SUPPORT */ 55 #if defined(BCM_TRIUMPH3_SUPPORT) 56 #include <bcm_int/esw/triumph3.h> 57 #endif /* BCM_TRIUMPH2_SUPPORT */ 58 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 59 #include <bcm_int/esw/hurricane.h> 60 #endif /* BCM_HURRICANE_SUPPORT*/ 61 #if defined(BCM_HURRICANE2_SUPPORT) 62 #include <soc/hurricane2.h> 63 #include <bcm_int/esw/hurricane2.h> 64 #endif /* BCM_HURRICANE2_SUPPORT*/ 65 #if defined(BCM_TRIDENT_SUPPORT) 66 #include <bcm_int/esw/trident.h> 67 #endif /* BCM_TRIDENT_SUPPORT*/ 68 #if defined(BCM_TRIDENT2_SUPPORT) 69 #include <soc/trident2.h> 70 #include <soc/mem.h> 71 #include <bcm_int/esw/trident2.h> 72 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 73 #include <bcm_int/esw/trident3.h> 74 #endif 75 #if defined(BCM_TRIDENT3_SUPPORT) 76 #include <bcm_int/esw/flow.h> 77 #include <soc/esw/flow_db.h> 78 #endif /* BCM_TRIDENT3_SUPPORT*/ 79 #include <bcm_int/esw/nat.h> 80 #include <bcm_int/esw/qos.h> 81 #endif /* BCM_TRIDENT_SUPPORT*/ 82 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 83 #include <soc/esw/ecmp.h> 84 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 85 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 86 #include <bcm_int/esw/trident2plus.h> 87 #endif /* BCM_TRIDENT2PLUS_SUPPORT*/ 88 #if defined(BCM_TRIUMPH3_SUPPORT) 89 #include <bcm_int/esw/triumph3.h> 90 #endif /* BCM_TRIUMPH3_SUPPORT*/ 91 #if defined(BCM_KATANA_SUPPORT) 92 #include <bcm_int/esw/katana.h> 93 #endif /* BCM_KATANA_SUPPORT */ 94 #if defined(BCM_KATANA2_SUPPORT) 95 #include <bcm_int/esw/katana2.h> 96 #endif 97 #if defined(BCM_SABER2_SUPPORT) 98 #include <bcm_int/esw/saber2.h> 99 #endif 100 #if defined(BCM_TOMAHAWK_SUPPORT) 101 #include <bcm_int/esw/tomahawk.h> 102 #endif /* BCM_TOMAHAWK_SUPPORT */ 103 #if defined(BCM_HURRICANE3_SUPPORT) 104 #include <bcm_int/esw/hurricane3.h> 105 #endif /* BCM_HURRICANE3_SUPPORT */ 106 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 107 #include <soc/trident2.h> 108 #include <bcm_int/esw/xgs5.h> 109 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 110 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 111 #include <bcm_int/esw/tomahawk2.h> 112 #endif /* BCM_TOMAHAWK2_SUPPORT */ 113 #if defined(BCM_TOMAHAWK3_SUPPORT) 114 #include <soc/tomahawk3.h> 115 #include <bcm_int/esw/tomahawk3.h> 116 #include <bcm_int/esw/alpm_th3_acc.h> 117 #endif /* BCM_TOMAHAWK3_SUPPORT */ 118 #if defined(BCM_GREYHOUND2_SUPPORT) 119 #include <bcm_int/esw/greyhound2.h> 120 #endif /* BCM_GREYHOUND2_SUPPORT */ 121 122 #include <bcm_int/esw/l3.h> 123 #ifdef ALPM_ENABLE 124 #include <bcm_int/esw/alpm.h> 125 #include <bcm_int/esw/alpm_util.h> 126 #endif 127 #include <bcm_int/esw/xgs3.h> 128 #include <bcm_int/esw/stack.h> 129 #include <soc/lpm.h> 130 #ifdef BCM_WARM_BOOT_SUPPORT 131 #include <bcm_int/esw/switch.h> 132 #if defined(BCM_TRX_SUPPORT) 133 #include <bcm_int/esw/field.h> 134 #endif /* BCM_TRX_SUPPORT */ 135 #endif /* BCM_WARM_BOOT_SUPPORT */ 136 #include <bcm_int/common/multicast.h> 137 #include <bcm_int/esw_dispatch.h> 138 #include <bcm_int/esw/failover.h> 139 140 #include <bcm_int/esw/lpmv6.h> 141 #include <bcm_int/esw/ecn.h> 142 #include <bcm_int/esw/ipmc.h> 143 144 #if defined(BCM_KATANA_SUPPORT) 145 #define EH_TAG_TYPE_NONE 0 146 #define EH_TAG_TYPE_EXPLICT_QUEUE 1 147 #define EH_TAG_TYPE_ING_QUEUE_MAP 2 148 #endif 149 150 /* 16 internal prio * 4 internal colors */ 151 #define _BCM_TNL_DSCP_MAP_TBL_SIZE 64 152 153 #define L3_IF_ERROR_CLEANUP_ELSE_RETURN(op) \ 154 do {if ((err_code = (op)) < 0) {goto cleanup;} \ 155 else {return err_code;} } while(0) 156 157 #define L3_IF_ERROR_CLEANUP(op) \ 158 do {if ((err_code = (op)) < 0) {goto cleanup;} } while(0) 159 160 #define L3_ING_IF_MIN(_unit_, _idx_)\ 161 if (soc_feature(unit, soc_feature_l3_iif_under_4k)) {\ 162 /* L3_IIFm unable to reserved first 4K for mapping to 4K VLAN. */\ 163 if (soc_feature(unit, soc_feature_l3_iif_zero_invalid)) {\ 164 _idx_ = 1;\ 165 } else {\ 166 _idx_ = 0;\ 167 }\ 168 } else {\ 169 if (!BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(_unit_)) {\ 170 _idx_ = BCM_VLAN_MAX + 1;\ 171 } else {\ 172 if (soc_feature(unit, soc_feature_l3_iif_zero_invalid)) {\ 173 _idx_ = 1;\ 174 } else {\ 175 _idx_ = 0;\ 176 }\ 177 }\ 178 } 179 180 181 typedef uint32 l3_max_entry_t[SOC_MAX_MEM_WORDS]; 182 183 _bcm_l3_module_data_t *l3_module_data[BCM_MAX_NUM_UNITS] = { 0 }; 184 #define L3_INFO(_unit_) (&_bcm_l3_bk_info[_unit_]) 185 186 extern int ecmp_mode_hierarchical; 187 extern int ecmp_mode_single; 188 /* per ecmp group enhanced hashing enabled info */ 189 #ifdef BCM_TRIDENT3_SUPPORT 190 uint8 ecmp_grp_enhanced_hashing[BCM_MAX_NUM_UNITS][4096]; 191 #endif 192 193 #if defined(BCM_TRIDENT3_SUPPORT) && defined(BCM_WARM_BOOT_SUPPORT) 194 extern int _bcm_td3_l2_change_fields_reinit(int unit); 195 #endif 196 197 /* Functions prototypes. */ 198 STATIC int _bcm_xgs3_l3_hw_op_init(int unit); 199 STATIC int _bcm_xgs3_tnl_init_hash_calc(int unit, void *buf, uint16 *hash); 200 STATIC int _bcm_th3_lpm_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 201 uint32 *lpm_entry); 202 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 203 defined(BCM_HAWKEYE_SUPPORT) 204 STATIC int _bcm_rp_l3_deinit(int unit); 205 STATIC int _bcm_rp_l3_init(int unit); 206 #ifdef BCM_WARM_BOOT_SUPPORT 207 static int _bcm_rp_l3_group_reload(int unit, bcm_field_group_t group, 208 void *user_data); 209 #endif 210 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 211 #ifdef BCM_FIREBOLT_SUPPORT 212 STATIC int _bcm_fb_nh_intf_is_tnl_update(int unit, bcm_if_t intf, int 213 tunnel_id); 214 STATIC void _bcm_fb_l3_ipmc_ent_init(int unit, uint32 *buf_p, 215 _bcm_l3_cfg_t *l3cfg); 216 #ifdef BCM_TRIDENT2_SUPPORT 217 STATIC int _bcm_fb_l3_intf_nat_realm_id_set(int unit, 218 _bcm_l3_intf_cfg_t *intf_info); 219 STATIC int _bcm_fb_l3_intf_nat_realm_id_get(int unit, 220 _bcm_l3_intf_cfg_t *intf_info); 221 #endif /* BCM_TRIDENT2_SUPPORT */ 222 #endif /* BCM_FIREBOLT_SUPPORT */ 223 224 /* Forward declarations (defined below) */ 225 int _bcm_xgs3_l3_ingress_interface_add(int unit, _bcm_l3_ingress_intf_t *iif) ; 226 int _bcm_xgs3_l3_ingress_interface_delete(int unit, int intf_id) ; 227 int _bcm_xgs3_l3_ingress_interface_get(int unit, _bcm_l3_ingress_intf_t *iif); 228 STATIC void _bcm_fb_mem_ip6_defip_lwr_set(int unit, void *lpm_key, 229 _bcm_defip_cfg_t *lpm_cfg); 230 STATIC int _bcm_fb_lpm_upr_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 231 uint32 *lpm_entry); 232 233 #ifdef BCM_WARM_BOOT_SUPPORT 234 STATIC int _bcm_xgs3_l3_ecmp_reinit(int unit, int ecmp_max_paths, int *ecmp_grp_refcnt); 235 #endif /*BCM_WARM_BOOT_SUPPORT*/ 236 STATIC int _bcm_xgs3_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry, 237 bcm_tunnel_terminator_t *tnl_info); 238 239 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 240 defined(BCM_HAWKEYE_SUPPORT) 241 /* Forward declaration for rule shift. */ 242 STATIC int _bcm_rp_lpm_entry_remove(int unit, int rule_idx); 243 #endif 244 #ifdef BCM_TRIDENT3_SUPPORT 245 STATIC int _bcmi_l3_intf_overlay_valid(int unit, _bcm_l3_intf_cfg_t *intf_info); 246 #endif 247 248 soc_field_t nh_entry_type_field[SOC_MAX_NUM_DEVICES]; 249 extern soc_field_t defip_mode0_bit[]; 250 extern soc_field_t defip_mode1_bit[]; 251 extern soc_field_t defip_mode_mask0_bit[]; 252 extern soc_field_t defip_mode_mask1_bit[]; 253 254 #if defined(ALPM_ENABLE) 255 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 256 extern int _bcm_th_alpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data); 257 extern int _bcm_th_alpm_find(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_idx); 258 259 #endif 260 #endif 261 262 #if defined(BCM_TRIDENT3_SUPPORT) 263 static soc_profile_mem_t *_bcm_td3_tunnel_default_vlan_profile[BCM_MAX_NUM_UNITS]; 264 265 int 266 _bcm_td3_tunnel_default_vlan_profile_init(int unit) 267 { 268 int i; 269 soc_mem_t mem; 270 int entry_words[1]; 271 void *entries[1]; 272 uint32 temp_index = 0; 273 uint32 ent_sz; 274 tunnel_default_vlan_profile_entry_t l3_tunnel_default_vlan_profile; 275 soc_mem_t tunnel_mem = L3_TUNNELm; 276 277 /* Create profile table cache (or re-init if it already exists) */ 278 mem = L3_TUNNEL_DEFAULT_VLAN_PROFILEm; 279 ent_sz = sizeof(tunnel_default_vlan_profile_entry_t); 280 281 if (_bcm_td3_tunnel_default_vlan_profile[unit] == NULL) { 282 _bcm_td3_tunnel_default_vlan_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 283 "L3 TUNNEL DEFAULT VLAN Profile Mem"); 284 if (_bcm_td3_tunnel_default_vlan_profile[unit] == NULL) { 285 return BCM_E_MEMORY; 286 } 287 soc_profile_mem_t_init(_bcm_td3_tunnel_default_vlan_profile[unit]); 288 } 289 290 /* Create profile table cache (or re-init if it already exists) */ 291 entry_words[0] = ent_sz / sizeof(uint32); 292 SOC_IF_ERROR_RETURN 293 (soc_profile_mem_create(unit, &mem, entry_words, 1, 294 _bcm_td3_tunnel_default_vlan_profile[unit])); 295 296 /* Reserve index 0 in L3_TUNNEL_DEFAULT_VLAN_PROFILE */ 297 sal_memset(&l3_tunnel_default_vlan_profile, 0, ent_sz); 298 entries[0] = &l3_tunnel_default_vlan_profile; 299 SOC_IF_ERROR_RETURN 300 (soc_profile_mem_add(unit, _bcm_td3_tunnel_default_vlan_profile[unit], 301 (void *) &entries, 1, &temp_index)); 302 SOC_PROFILE_MEM_REFERENCE(unit, _bcm_td3_tunnel_default_vlan_profile[unit], 0, 1); 303 304 /* Recover ref-counts of L3_TUNNEL_DEFAULT_VLAN_PROFILE from L3_TUNNEL */ 305 if (SOC_WARM_BOOT(unit)) { 306 for (i = 0; i < soc_mem_index_count(unit, tunnel_mem); i++) { 307 uint32 idx; 308 uint32 entry_ptr[SOC_MAX_MEM_WORDS]; 309 310 BCM_IF_ERROR_RETURN( 311 soc_mem_read(unit, tunnel_mem, MEM_BLOCK_ANY, i, entry_ptr)); 312 313 idx = soc_mem_field32_get(unit, tunnel_mem, 314 entry_ptr, DEFAULT_VLAN_PROFILE_INDEXf); 315 if (idx) { 316 SOC_PROFILE_MEM_REFERENCE(unit, _bcm_td3_tunnel_default_vlan_profile[unit], 317 idx, soc_mem_index_count(unit, 1)); 318 } 319 } 320 } 321 return BCM_E_NONE; 322 } 323 #endif 324 325 /* 326 * Function: 327 * bcm_xgs3_l3_mask6_apply 328 * Purpose: 329 * Apply IPv6 mask on address 330 * Parameters: 331 * unit - (IN)SOC unit number. 332 * mask - (IN)IPv6 Mask 333 * addr - (IN/OUT)Address to apply the mask 334 * Returns: 335 * BCM_X_XXX 336 */ 337 int 338 bcm_xgs3_l3_mask6_apply(bcm_ip6_t mask, bcm_ip6_t addr) 339 { 340 uint8 *mask_iter; /* Mask bytes iterator. */ 341 uint8 *addr_iter; /* Mask bytes iterator. */ 342 int idx; /* IPv6 addresses iterator. */ 343 344 mask_iter = (uint8 *)mask; 345 addr_iter = (uint8 *)addr; 346 347 for (idx = 0; idx < 16; idx++) { 348 (*addr_iter) &= (*mask_iter); 349 addr_iter++; 350 mask_iter++; 351 } 352 return (BCM_E_NONE); 353 } 354 355 /* 356 * Function: 357 * bcm_xgs3_l3_egress_mode_set 358 * Purpose: 359 * Set unit l3 egress switching mode. 360 * Parameters: 361 * unit - (IN)SOC unit number. 362 * mode - (IN)Egress switching mode. 363 * Returns: 364 * BCM_X_XXX 365 */ 366 int 367 bcm_xgs3_l3_egress_mode_set(int unit, int mode) 368 { 369 /* Make sure module was initialized. */ 370 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 371 return (BCM_E_INIT); 372 } 373 374 /* Set mode flag. */ 375 switch(mode) { 376 case 0: 377 BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_EGRESS_MODE; 378 break; 379 case 1: 380 BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_EGRESS_MODE; 381 break; 382 default: 383 return (BCM_E_PARAM); 384 } 385 386 #ifdef BCM_WARM_BOOT_SUPPORT 387 SOC_CONTROL_LOCK(unit); 388 SOC_CONTROL(unit)->scache_dirty = 1; 389 SOC_CONTROL_UNLOCK(unit); 390 #endif 391 392 return (BCM_E_NONE); 393 } 394 395 396 /* 397 * Function: 398 * bcm_xgs3_l3_egress_mode_get 399 * Purpose: 400 * Get unit l3 egress switching mode. 401 * Parameters: 402 * unit - (IN)SOC unit number. 403 * mode - (IN)Egress switching mode. 404 * Returns: 405 * BCM_X_XXX 406 */ 407 int 408 bcm_xgs3_l3_egress_mode_get(int unit, int *mode) 409 { 410 /* Make sure module was initialized. */ 411 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 412 return (BCM_E_INIT); 413 } 414 415 /* Input parameters check */ 416 if (NULL == mode) { 417 return (BCM_E_PARAM); 418 } 419 420 *mode = (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) ? 1 : 0; 421 return (BCM_E_NONE); 422 } 423 424 425 /* 426 * Function: 427 * bcm_xgs3_l3_host_as_route_return_set 428 * Purpose: 429 * Set mode for bcmSwitchL3HostAsRouteReturnValue 430 * Application controls the return value setting for bcm_l3_host_add API 431 * with BCM_L3_HOST_AS_ROUTE flag. If prefix gets added to HOST table, 432 * then return value=0. If prefix gets added to DEFIP table, 433 * then return value = ret_val 434 * Parameters: 435 * unit - (IN)SOC unit number. 436 * ret_val - (IN) Return Value 437 * Returns: 438 * BCM_X_XXX 439 */ 440 441 int 442 bcm_xgs3_l3_host_as_route_return_set(int unit, int ret_val) 443 { 444 ing_l3_next_hop_entry_t in_entry; /* Buffer for ingress nh entry. */ 445 446 /* Make sure module was initialized. */ 447 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 448 return (BCM_E_INIT); 449 } 450 451 /* Set mode */ 452 if (soc_mem_is_valid(unit, ING_L3_NEXT_HOPm)) { 453 if (ret_val == 0) { 454 BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_HOST_ADD_MODE; 455 } else if ((ret_val > 0) && (ret_val <= 0xFF)) { 456 BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_HOST_ADD_MODE; 457 /* Zero buffers. */ 458 sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh)); 459 /* Read entry of ingress Black-Hole Next-Hop. */ 460 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 461 ING_L3_NEXT_HOPm, 0, &in_entry)); 462 /* Store RETURN_VALUE within unused field of Black-Hole Next-Hop */ 463 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &in_entry, 464 VLAN_IDf, ret_val); 465 /* Write ingress next hop entry. */ 466 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, 467 ING_L3_NEXT_HOPm, 0, &in_entry)); 468 } else { 469 return (BCM_E_PARAM); 470 } 471 472 #ifdef BCM_WARM_BOOT_SUPPORT 473 SOC_CONTROL_LOCK(unit); 474 SOC_CONTROL(unit)->scache_dirty = 1; 475 SOC_CONTROL_UNLOCK(unit); 476 #endif 477 } 478 479 return (BCM_E_NONE); 480 481 } 482 483 /* 484 * Function: 485 * bcm_xgs3_l3_host_as_route_return_get 486 * Purpose: 487 * Get mode for bcmSwitchL3HostAsRouteReturnValue 488 * Parameters: 489 * unit - (IN)SOC unit number. 490 * ret_val - (IN)Return Value 491 * Returns: 492 * BCM_X_XXX 493 */ 494 int 495 bcm_xgs3_l3_host_as_route_return_get(int unit, int *ret_val) 496 { 497 int state; 498 ing_l3_next_hop_entry_t in_entry; /* Buffer for ingress nh entry. */ 499 500 /* Make sure module was initialized. */ 501 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 502 return (BCM_E_INIT); 503 } 504 505 /* Input parameters check */ 506 if (NULL == ret_val) { 507 return (BCM_E_PARAM); 508 } 509 510 if (soc_mem_is_valid(unit, ING_L3_NEXT_HOPm)) { 511 state = (BCM_XGS3_L3_HOST_AS_ROUTE_MODE_ISSET(unit)); 512 if (state == 0) { 513 *ret_val = 0; 514 } else { 515 /* Zero buffers. */ 516 sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh)); 517 /* Read ingress next hop entry. */ 518 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 519 ING_L3_NEXT_HOPm, 0, &in_entry)); 520 /* Obtain RETURN_VALUE within unused field of Black-Hole Next-Hop */ 521 *ret_val = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 522 &in_entry, VLAN_IDf); 523 } 524 } else { 525 *ret_val = 0; 526 } 527 528 return (BCM_E_NONE); 529 } 530 531 #if defined(BCM_TRIUMPH_SUPPORT) 532 /* 533 * Function: 534 * bcm_xgs3_l3_ingress_mode_set 535 * Purpose: 536 * Set unit l3 ingress switching mode. 537 * Parameters: 538 * unit - (IN)SOC unit number. 539 * mode - (IN)Ingress switching mode. 540 * Returns: 541 * BCM_X_XXX 542 */ 543 int 544 bcm_xgs3_l3_ingress_mode_set(int unit, int mode) 545 { 546 /* Make sure module was initialized. */ 547 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 548 return (BCM_E_INIT); 549 } 550 551 /* Set mode flag. */ 552 switch(mode) { 553 case 0: 554 BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_INGRESS_MODE; 555 break; 556 case 1: 557 BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_INGRESS_MODE; 558 break; 559 default: 560 return (BCM_E_PARAM); 561 } 562 563 #ifdef BCM_WARM_BOOT_SUPPORT 564 SOC_CONTROL_LOCK(unit); 565 SOC_CONTROL(unit)->scache_dirty = 1; 566 SOC_CONTROL_UNLOCK(unit); 567 #endif 568 569 return (BCM_E_NONE); 570 } 571 572 573 /* 574 * Function: 575 * bcm_xgs3_l3_ingress_mode_get 576 * Purpose: 577 * Get unit l3 ingress switching mode. 578 * Parameters: 579 * unit - (IN)SOC unit number. 580 * mode - (OUT)Ingress switching mode. 581 * Returns: 582 * BCM_X_XXX 583 */ 584 int 585 bcm_xgs3_l3_ingress_mode_get(int unit, int *mode) 586 { 587 588 /* Input parameters check */ 589 if (NULL == mode) { 590 return (BCM_E_PARAM); 591 } 592 593 *mode = (BCM_XGS3_L3_INGRESS_MODE_ISSET(unit)) ? 1 : 0; 594 return (BCM_E_NONE); 595 } 596 597 /* 598 * Function: 599 * bcm_xgs3_l3_ingress_intf_map_set 600 * Purpose: 601 * Set unit l3 ingress interface map mode 602 * Parameters: 603 * unit - (IN)SOC unit number. 604 * mode - (IN)ingress interface map mode 605 * Returns: 606 * BCM_X_XXX 607 */ 608 int 609 bcm_xgs3_l3_ingress_intf_map_set(int unit, int mode) 610 { 611 612 if (soc_feature(unit, soc_feature_l3_iif_under_4k)) { 613 /* Chip with this feature means table size of L3_IIFm under 4096 614 * - can never support mode=0 for VLAN_ID 1:1 mapping to L3_IIFm. 615 * - This SW info flag will be set during L3 init. 616 */ 617 if (mode == 0){ 618 return BCM_E_UNAVAIL; 619 } 620 } else { 621 /* Make sure module was initialized. */ 622 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 623 return (BCM_E_INIT); 624 } 625 } 626 627 628 /* Set mode flag. */ 629 switch(mode) { 630 case 0: 631 BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_INGRESS_INTF_MAP; 632 break; 633 case 1: 634 BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_INGRESS_INTF_MAP; 635 break; 636 default: 637 return (BCM_E_PARAM); 638 } 639 640 #ifdef BCM_WARM_BOOT_SUPPORT 641 SOC_CONTROL_LOCK(unit); 642 SOC_CONTROL(unit)->scache_dirty = 1; 643 SOC_CONTROL_UNLOCK(unit); 644 #endif 645 646 return (BCM_E_NONE); 647 } 648 649 650 /* 651 * Function: 652 * bcm_xgs3_l3_ingress_intf_map_get 653 * Purpose: 654 * Get unit ll3 ingress interface map mode 655 * Parameters: 656 * unit - (IN)SOC unit number. 657 * mode - (OUT))ingress interface map mode 658 * Returns: 659 * BCM_X_XXX 660 */ 661 int 662 bcm_xgs3_l3_ingress_intf_map_get(int unit, int *mode) 663 { 664 /* Do not fail if uninitialized as this function is used by VLAN module */ 665 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 666 *mode = 0; 667 return (BCM_E_NONE); 668 } 669 670 /* Input parameters check */ 671 if (NULL == mode) { 672 return (BCM_E_PARAM); 673 } 674 675 *mode = (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) ? 1 : 0; 676 return (BCM_E_NONE); 677 } 678 #endif /* BCM_TRIUMPH_SUPPORT */ 679 680 /* 681 * Function: 682 * _bcm_xgs3_l3_ecmp_group_alloc 683 * Purpose: 684 * Allocate l3 ecmp group members array. 685 * Parameters: 686 * unit - (IN) BCM device number. 687 * ptr - (IN) Allocated group pointer 688 * Returns: 689 * BCM_X_XXX 690 */ 691 STATIC int 692 _bcm_xgs3_l3_ecmp_group_alloc(int unit, int **ptr) 693 { 694 int alloc_size; 695 696 /* Make sure module was initialized. */ 697 if (NULL == ptr) { 698 return (BCM_E_NONE); 699 } 700 701 702 alloc_size = sizeof(int) * BCM_XGS3_L3_ECMP_MAX(unit); 703 704 *ptr = NULL; 705 BCM_XGS3_L3_ALLOC((*ptr), alloc_size, "ecmp group next hops array"); 706 707 /* Input parameters check */ 708 if (NULL == *ptr) { 709 return (BCM_E_MEMORY); 710 } 711 return (BCM_E_NONE); 712 } 713 714 /* 715 * Function: 716 * _bcm_xgs3_nh_hash_calc 717 * Purpose: 718 * Calculate next hop entry hash(signature). 719 * Parameters: 720 * unit - (IN)SOC unit number. 721 * buf - (IN)Next hop entry information. 722 * hash - (OUT) Hash(signature) calculated value. 723 * Returns: 724 * BCM_X_XXX 725 */ 726 STATIC int 727 _bcm_xgs3_nh_hash_calc(int unit, void *buf, uint16 *hash) 728 { 729 uint32 sw_buf[10]; 730 bcm_l3_egress_t *nh_entry; 731 uint32 mac_field[2]; 732 733 /* Input parameters check. */ 734 if ((NULL == buf) || (NULL == hash)) { 735 return (BCM_E_PARAM); 736 } 737 sal_memset (sw_buf, 0, 10 * sizeof(uint32)); 738 nh_entry = (bcm_l3_egress_t *) buf; 739 740 /* 741 * Copy entry information to a temporary buffer, so we can 742 * mask some fields we don't want to include in hash calculation. 743 */ 744 sw_buf[0] = nh_entry->intf; 745 SAL_MAC_ADDR_TO_UINT32(nh_entry->mac_addr, mac_field); 746 sw_buf[1] = mac_field[0]; 747 /* 748 * NH entry is overlayed on VLAN_ID and L3_OIF fields. 749 * The VLAN_ID is the default active field by default. 750 * Once the L3_INTF_VLAN_SPLIT_EGRESS_MODE been set through config 751 * file with "l3_intf_vlan_split_egress=1", the active field is 752 * L3_OIF. And nh_entry->vlan should not be the key to built 753 * NH entry hash while VLAN_ID is not the active field. 754 */ 755 if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) { 756 sw_buf[2] = ((mac_field[1] << 16) | nh_entry->vlan); 757 } 758 sw_buf[3] = nh_entry->module; 759 sw_buf[4] = nh_entry->port; 760 sw_buf[5] = nh_entry->trunk; 761 #ifdef BCM_MPLS_SUPPORT 762 if (soc_feature(unit, soc_feature_mpls) && 763 !(nh_entry->flags2 & BCM_L3_MPLS_GRE_LABEL)) { 764 /* Include mpls info only if label is valid. */ 765 if (BCM_XGS3_L3_MPLS_LBL_VALID(nh_entry->mpls_label)) { 766 sw_buf[6] = nh_entry->mpls_label; 767 sw_buf[7] = nh_entry->mpls_qos_map_id; 768 sw_buf[8] = nh_entry->mpls_ttl; 769 } 770 } 771 #endif /* BCM_MPLS_SUPPORT */ 772 sw_buf[9] = nh_entry->encap_id; 773 774 *hash = _shr_crc16(0, (uint8 *)&sw_buf[0], sizeof(uint32)*10); 775 776 return (BCM_E_NONE); 777 } 778 779 /* 780 * Function: 781 * _bcm_xgs3_cmp_int 782 * Purpose: 783 * Compare two integers. 784 * Parameters: 785 * b - first compared integer 786 * a - second compared integer 787 * Returns: 788 * a<=>b 789 */ 790 static INLINE int 791 _bcm_xgs3_cmp_int(void *a, void *b) 792 { 793 int first; /* First compared integer. */ 794 int second; /* Second compared integer. */ 795 796 first = *(int *)a; 797 second = *(int *)b; 798 799 if (first < second) { 800 return (BCM_L3_CMP_LESS); 801 } else if (first > second) { 802 return (BCM_L3_CMP_GREATER); 803 } 804 return (BCM_L3_CMP_EQUAL); 805 } 806 807 /* 808 * Function: 809 * _bcm_xgs3_cmp_ecmp_member 810 * Purpose: 811 * Compare two integers of ecmp member. 812 * Parameters: 813 * b - first compared ecmp member 814 * a - second compared ecmp member 815 * Returns: 816 * a<=>b 817 */ 818 static INLINE int 819 _bcm_xgs3_cmp_ecmp_member(void *a, void *b) 820 { 821 bcm_l3_ecmp_member_t first; /* First compared ecmp member. */ 822 bcm_l3_ecmp_member_t second; /* Second compared ecmp member. */ 823 824 first = *(bcm_l3_ecmp_member_t *)a; 825 second = *(bcm_l3_ecmp_member_t *)b; 826 827 /* Compare egress_if of ecmp member. */ 828 return _bcm_xgs3_cmp_int(&first.egress_if, &second.egress_if); 829 } 830 831 832 /* 833 * Function: 834 * _bcm_xgs3_nh_map_hw_data_to_api 835 * Purpose: 836 * Convert HW space nh entry format to API space nh entry. 837 * Currently service routine used to map hw port/trunk info 838 * to next hop entry port_tgid/modid format. 839 * Parameters: 840 * unit - (IN) SOC unit number. 841 * port - (IN) Port/Trunk. 842 * module - (IN) Module id. 843 * nh_entry - (IN/OUT) Updated next hop entry. 844 * Returns: 845 * BCM_E_XXX 846 */ 847 STATIC int 848 _bcm_xgs3_nh_map_hw_data_to_api(int unit, int port, 849 int mod, bcm_l3_egress_t *nh_entry) 850 { 851 int port_out; /* Calculated port value */ 852 int modid_out; /* Calculated module id. */ 853 854 if (nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP) { 855 return (BCM_E_NONE); 856 } 857 858 if (nh_entry->flags & BCM_L3_TGID) { 859 /* Port is trunk. */ 860 nh_entry->module = 0; 861 #ifdef BCM_TRX_SUPPORT 862 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 863 nh_entry->trunk = port; 864 } else 865 #endif /* BCM_TRIUMPH_SUPPORT */ 866 { 867 nh_entry->trunk = BCM_MODIDf_TGIDf_TO_TRUNK(unit, mod, port); 868 } 869 } else 870 #ifdef BCM_RIOT_SUPPORT 871 if (_bcm_vp_is_vfi_type(unit, nh_entry->port)) { 872 /* Send back the vp as it is. */ 873 nh_entry->port = port; 874 } else 875 #endif 876 { 877 /* Regular port. */ 878 BCM_IF_ERROR_RETURN 879 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 880 mod, port, &modid_out, &port_out)); 881 882 nh_entry->module = modid_out; 883 nh_entry->port = port_out; 884 } 885 return (BCM_E_NONE); 886 } 887 888 /* 889 * Function: 890 * _bcm_xgs3_nh_map_api_data_to_hw 891 * Purpose: 892 * Convert API space nh entry format to HW space nh entry. 893 * Parameters: 894 * unit - (IN)SOC unit number. 895 * nh_entry - (IN/OUT)Next hop entry data. 896 * Returns: 897 * BCM_E_XXX 898 */ 899 STATIC int 900 _bcm_xgs3_nh_map_api_data_to_hw(int unit, bcm_l3_egress_t *nh_entry) 901 { 902 int port_out; /* Calculated port value */ 903 int modid_out; /* Calculated module id. */ 904 905 if (NULL == nh_entry) 906 return (BCM_E_PARAM); 907 908 if (nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP) { 909 return (BCM_E_NONE); 910 } 911 912 /* convert API space numbers to HW space numbers */ 913 if ((nh_entry->flags & BCM_L3_TGID) == 0) { 914 #ifdef BCM_RIOT_SUPPORT 915 if (_bcm_vp_is_vfi_type(unit, nh_entry->port)) { 916 return BCM_E_NONE; 917 } 918 #endif 919 BCM_IF_ERROR_RETURN 920 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 921 nh_entry->module, nh_entry->port, 922 &modid_out, &port_out)); 923 if (!SOC_MODID_ADDRESSABLE(unit, modid_out)) { 924 return (BCM_E_BADID); 925 } 926 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 927 return (BCM_E_PORT); 928 } 929 } else { 930 #ifdef BCM_TRX_SUPPORT 931 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 932 modid_out = 0; 933 port_out = nh_entry->trunk; 934 } else 935 #endif /* BCM_TRX_SUPPORT */ 936 { 937 /* Map trunk id to mod/port pair */ 938 modid_out = BCM_TRUNK_TO_MODIDf(unit, nh_entry->trunk); 939 port_out = BCM_TRUNK_TO_TGIDf(unit, nh_entry->trunk); 940 } 941 } 942 /* Preserve converted values in the structure. */ 943 /* NOTE: HW has a single field for port/trunk */ 944 /* hence port only used for hw calls. */ 945 nh_entry->trunk = 0; 946 nh_entry->port = port_out; 947 nh_entry->module = modid_out; 948 949 return (BCM_E_NONE); 950 } 951 952 /* 953 * Function: 954 * bcm_xgs3_l3_enable 955 * Purpose: 956 * Enable/disable L3 function. 957 * Parameters: 958 * unit - (IN)SOC PCI unit number. 959 * enable - (IN)TRUE: enable L3 support. 960 * FALSE: disable L3 support. 961 * Returns: 962 * BCM_E_XXX 963 */ 964 int 965 bcm_xgs3_l3_enable(int unit, int enable) 966 { 967 int port; /* Port iterator. */ 968 bcm_pbmp_t port_pbmp; 969 970 /* Make sure module was initialized. */ 971 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 972 return (BCM_E_INIT); 973 } 974 975 BCM_PBMP_CLEAR(port_pbmp); 976 BCM_PBMP_ASSIGN(port_pbmp, PBMP_PORT_ALL(unit)); 977 978 #ifdef BCM_KATANA2_SUPPORT 979 if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) { 980 BCM_IF_ERROR_RETURN(_bcm_kt2_flexio_pbmp_update(unit, &port_pbmp)); 981 } 982 if (soc_feature(unit, soc_feature_linkphy_coe) || 983 soc_feature(unit, soc_feature_subtag_coe)) { 984 _bcm_kt2_subport_pbmp_update(unit, &port_pbmp); 985 } 986 #endif 987 #if defined(BCM_SABER2_SUPPORT) 988 if(SOC_IS_SABER2(unit)){ 989 int oamp_enable; 990 (void)bcm_sb2_sat_oamp_enable_get(unit, &oamp_enable); 991 /* Skip OAMP port for saber2 device */ 992 if(oamp_enable) { 993 SOC_PBMP_PORT_REMOVE(port_pbmp, 994 _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER); 995 } 996 } 997 #endif 998 999 1000 /* Iterate over all the ports. */ 1001 PBMP_ITER(port_pbmp, port) { 1002 /* Set l3 enable to the hw. */ 1003 /* 1004 * In general, we enable this controls for all ports. 1005 * But there may be some ports which does not 1006 * support this setting. these ports may return errors 1007 * Therefore leaving it unchecked. 1008 */ 1009 1010 /* coverity[check_return : FALSE] */ 1011 bcm_esw_port_control_set(unit, port, bcmPortControlIP4, enable); 1012 /* coverity[check_return : FALSE] */ 1013 bcm_esw_port_control_set(unit, port, bcmPortControlIP6, enable); 1014 } 1015 return (BCM_E_NONE); 1016 } 1017 1018 1019 /* 1020 * Function: 1021 * bcm_xgs3_l3_tbl_dma 1022 * Purpose: 1023 * 1024 * Parameters: 1025 * unit -(IN)SOC unit number. 1026 * tbl_mem -(IN)Table memory. 1027 * tbl_entry_sz -(IN)Table entry size. 1028 * descr -(IN)Table descriptor. 1029 * res_ptr -(OUT) Allocated pointer filled with table info 1030 * entry_count -(OUT) Table entry count. 1031 * Returns: 1032 * BCM_E_XXX 1033 */ 1034 int 1035 bcm_xgs3_l3_tbl_dma(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz, 1036 const char *descr, char **res_ptr, int *entry_count) 1037 { 1038 int alloc_size; /* Allocation size. */ 1039 char *buffer; /* Buffer to read the table. */ 1040 int tbl_size; /* HW table size. */ 1041 /* Input parameters sanity check. */ 1042 if ((NULL == res_ptr) || (NULL == descr)) { 1043 return (BCM_E_PARAM); 1044 } 1045 1046 /* If entry size is not deterministic. reject. */ 1047 if (tbl_entry_sz == BCM_XGS3_L3_INVALID_ENT_SZ) { 1048 return (BCM_E_UNAVAIL); 1049 } 1050 1051 if (INVALIDm == tbl_mem) { 1052 return (BCM_E_NOT_FOUND); 1053 } 1054 1055 /* Calculate table size. */ 1056 tbl_size = soc_mem_index_count(unit, tbl_mem); 1057 if (!tbl_size) { 1058 return (BCM_E_NOT_FOUND); 1059 } else if (NULL != entry_count) { 1060 *entry_count = tbl_size; 1061 } 1062 alloc_size = tbl_entry_sz * tbl_size; 1063 1064 /* Allocate memory buffer. */ 1065 buffer = soc_cm_salloc(unit, alloc_size, descr); 1066 if (buffer == NULL) { 1067 return (BCM_E_MEMORY); 1068 } 1069 1070 /* Reset allocated buffer. */ 1071 sal_memset(buffer, 0, alloc_size); 1072 1073 /* Read table to the buffer. */ 1074 if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY, 1075 soc_mem_index_min(unit, tbl_mem), 1076 soc_mem_index_max(unit, tbl_mem), buffer) < 0) { 1077 soc_cm_sfree(unit, buffer); 1078 return (BCM_E_INTERNAL); 1079 } 1080 1081 *res_ptr = buffer; 1082 return (BCM_E_NONE); 1083 } 1084 /* 1085 * Function: 1086 * _bcm_xgs3_l3_intf_init 1087 * Purpose: 1088 * Initialize L3 tables. 1089 * Parameters: 1090 * unit - (IN)SOC unit number. 1091 * Returns: 1092 * BCM_E_XXX 1093 */ 1094 STATIC int 1095 _bcm_xgs3_l3_intf_init(int unit) 1096 { 1097 int mem_sz; /* Allocated memory size. */ 1098 _bcm_l3_tbl_t *tbl_ptr; /* L3 egress intf table pointer. */ 1099 1100 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf); 1101 /* Get first egr intf index. */ 1102 if (soc_feature(unit, soc_feature_l3_egr_intf_zero_invalid)) { 1103 tbl_ptr->idx_min = soc_mem_index_min(unit, 1104 BCM_XGS3_L3_MEM(unit, intf)) + 1; 1105 } else { 1106 tbl_ptr->idx_min = soc_mem_index_min(unit, 1107 BCM_XGS3_L3_MEM(unit, intf)); 1108 } 1109 /* Get last egr intf index. */ 1110 tbl_ptr->idx_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, intf)); 1111 /* Set egr intf max used to first entry.(table empty) */ 1112 tbl_ptr->idx_maxused = tbl_ptr->idx_min; 1113 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1114 /* Set up split table limits */ 1115 tbl_ptr->split_idx = 0; 1116 tbl_ptr->split_maxused = 0; 1117 #endif 1118 1119 BCM_XGS3_L3_IF_TBL_SIZE(unit) = tbl_ptr->idx_max + 1; 1120 1121 /* Keep track of L3 interfaces */ 1122 mem_sz = SHR_BITALLOCSIZE(BCM_XGS3_L3_IF_TBL_SIZE(unit)); 1123 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_IF_INUSE(unit), mem_sz, "l3_intf"); 1124 if (NULL == BCM_XGS3_L3_IF_INUSE(unit)) { 1125 return (BCM_E_MEMORY); 1126 } 1127 1128 /* 1129 * Keep track of L3 interfaces that were ever set on the Next-Hop table. 1130 * This is used to skip the Next Hop table search in 1131 * _bcm_fb_nh_intf_is_tnl_update(). 1132 */ 1133 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_INTF_USED_NH(unit), mem_sz, "l3_intf_nh"); 1134 if (NULL == BCM_XGS3_L3_INTF_USED_NH(unit)) { 1135 return (BCM_E_MEMORY); 1136 } 1137 1138 /* Keep track of L3 interfaces */ 1139 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_IF_ADD2ARL(unit), mem_sz, "l3_intf_arl"); 1140 if (NULL == BCM_XGS3_L3_IF_ADD2ARL(unit)) { 1141 return (BCM_E_MEMORY); 1142 } 1143 1144 return (BCM_E_NONE); 1145 } 1146 /* 1147 * Function: 1148 * _bcm_xgs3_l3_ing_intf_init 1149 * Purpose: 1150 * Initialize ingress l3 interface table . 1151 * Parameters: 1152 * unit - (IN)SOC unit number. 1153 * Returns: 1154 * BCM_E_XXX 1155 */ 1156 STATIC int 1157 _bcm_xgs3_l3_ing_intf_init(int unit) 1158 { 1159 int mem_sz; /* Allocated memory size. */ 1160 int idx; /* Reserved interfaces iteration index. */ 1161 #if defined(BCM_TRIUMPH_SUPPORT) 1162 _bcm_l3_ingress_intf_t iif; /* Ipmc interfaces identity map. */ 1163 int rv; /* Operation return status. */ 1164 #endif /* BCM_TRIUMPH_SUPPORT */ 1165 1166 #if defined(BCM_TRIDENT2_SUPPORT) 1167 char *iif_tbl_ptr = NULL; 1168 iif_entry_t write_entry; 1169 iif_entry_t *hw_entry; 1170 int start_idx, end_idx; 1171 soc_mem_t mem; 1172 #endif /* BCM_TRIDENT2_SUPPORT */ 1173 1174 #if defined(BCM_TRIUMPH_SUPPORT) 1175 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 1176 #endif /* BCM_TRIUMPH_SUPPORT */ 1177 1178 /* 1179 * Keep track of VLAN VRF Ref count in l3_ing_intf table 1180 */ 1181 mem_sz = BCM_VLAN_COUNT * sizeof(_bcm_l3_tbl_ext_t); 1182 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr, mem_sz, "l3_ing_intf"); 1183 if (NULL == BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr) { 1184 return (BCM_E_MEMORY); 1185 } 1186 1187 if (INVALIDm != BCM_XGS3_L3_MEM(unit, ing_intf)) { 1188 BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) = 1189 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, ing_intf)); 1190 if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) == 0){ 1191 /* Wolfhoud2(HR3 family) support partial L3 feature. 1192 * - L3_IIFm is valid in this chip but size=0 due to no support. 1193 */ 1194 return (BCM_E_NONE); 1195 } 1196 } else { 1197 BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) = 0; 1198 return (BCM_E_NONE); 1199 } 1200 1201 /* Keep track of L3 interfaces */ 1202 mem_sz = SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 1203 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_ING_IF_INUSE(unit), mem_sz, "l3_iif"); 1204 if (NULL == BCM_XGS3_L3_ING_IF_INUSE(unit)) { 1205 return (BCM_E_MEMORY); 1206 } 1207 1208 #if defined(BCM_WARM_BOOT_SUPPORT) && defined(BCM_TRIDENT2_SUPPORT) 1209 if (SOC_WARM_BOOT(unit)) { 1210 int stable_size = 0; 1211 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 1212 if (stable_size > 0) { 1213 /* 1214 * The L3 ingress interface inuse bitmaps are recovered from scahe, and 1215 * there is no need to set HW tables during warmboot. 1216 */ 1217 return (BCM_E_NONE); 1218 } 1219 } 1220 #endif 1221 1222 #ifdef BCM_TRIUMPH_SUPPORT 1223 if (soc_feature(unit, soc_feature_l3_iif_under_4k)) { 1224 /* means no enough L3_IIFm entries for 1:1 mapped by VLAN_ID. */ 1225 1226 /* in this feature, L3 ingress interface map mode can only be 1 always */ 1227 BCM_IF_ERROR_RETURN(bcm_xgs3_l3_ingress_intf_map_set(unit, 1)); 1228 1229 /* the entry0 in such L3_IIFm is default entry for VLANm.L3_IIFf 1230 * - flag of BCM_L3_INGRESS_DSCP_TRUST must be unset for this 1231 * L3_IIF default entry. 1232 */ 1233 idx = 0; 1234 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx); 1235 iif.intf_id = idx; 1236 iif.flags &= ~BCM_L3_INGRESS_DSCP_TRUST; 1237 iif.flags &= ~BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 1238 rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL); 1239 BCM_IF_ERROR_RETURN(rv); 1240 } 1241 #endif 1242 1243 /* First 4K interfaces are reserved for per vlan interface use. */ 1244 if (!(BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit))) { 1245 #if defined(BCM_TRIDENT2_SUPPORT) 1246 if (soc_feature(unit, soc_feature_l3_iif_profile)) { 1247 1248 mem = BCM_XGS3_L3_MEM(unit, ing_intf); 1249 start_idx = soc_mem_index_min(unit, L3_IIFm); 1250 end_idx = BCM_VLAN_MAX; 1251 1252 /* DMA L3_IIF table to software copy */ 1253 rv = bcm_xgs3_l3_tbl_range_dma(unit, 1254 mem, BCM_XGS3_L3_ENT_SZ(unit, ing_intf), "l3_iif_tbl", 1255 start_idx, end_idx, &iif_tbl_ptr); 1256 1257 if (BCM_FAILURE(rv)) { 1258 LOG_ERROR(BSL_LS_BCM_L3, 1259 (BSL_META_U(unit, "DMA Read Failed for mem=(%s)\n"), 1260 SOC_MEM_NAME(unit, mem))); 1261 return rv; 1262 } 1263 1264 /* Setup iif structure */ 1265 iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 1266 iif.flags |= BCM_L3_INGRESS_GLOBAL_ROUTE; 1267 1268 for (idx = 0; idx < BCM_VLAN_INVALID; idx++) { 1269 iif.intf_id = idx; 1270 iif.ipmc_intf_id = idx; 1271 1272 hw_entry = soc_mem_table_idx_to_pointer(unit, 1273 mem, iif_entry_t *, iif_tbl_ptr, idx); 1274 1275 rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, 1276 hw_entry, &write_entry); 1277 if (BCM_FAILURE(rv)) { 1278 LOG_ERROR(BSL_LS_BCM_L3, 1279 (BSL_META_U(unit, 1280 "Failed to set l3 ingress interface for index=(%d)\n"), 1281 idx)); 1282 soc_cm_sfree(unit, iif_tbl_ptr); 1283 return rv; 1284 } 1285 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx); 1286 /* Update the entry copy in the DMAed buffer with the 1287 * new contents. of write_entry modified by interface_set 1288 */ 1289 sal_memcpy(hw_entry, &write_entry, soc_mem_entry_bytes(unit, mem)); 1290 } 1291 1292 /* Write back modified contents */ 1293 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 1294 start_idx, end_idx, iif_tbl_ptr); 1295 if (SOC_FAILURE(rv)) { 1296 LOG_ERROR(BSL_LS_BCM_L3, 1297 (BSL_META_U(unit, "DMA Write Failed for mem=(%s)\n"), 1298 SOC_MEM_NAME(unit, mem))); 1299 } 1300 if (iif_tbl_ptr != NULL) { 1301 soc_cm_sfree(unit, iif_tbl_ptr); 1302 } 1303 } else 1304 #endif /* BCM_TRIDENT2_SUPPORT */ 1305 { 1306 for (idx = 0; idx < BCM_VLAN_INVALID; idx++) { 1307 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx); 1308 #if defined(BCM_TRIUMPH_SUPPORT) 1309 if (SOC_IS_TR_VL(unit)) { 1310 iif.intf_id = idx; 1311 iif.ipmc_intf_id = idx; 1312 rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, 1313 NULL, NULL); 1314 BCM_IF_ERROR_RETURN(rv); 1315 } 1316 #endif /* BCM_TRIUMPH_SUPPORT */ 1317 } 1318 } 1319 } 1320 1321 return (BCM_E_NONE); 1322 } 1323 1324 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1325 /* 1326 * Function: 1327 * bcmi_xgs3_l3_nh_tbl_split_range_init 1328 * Purpose: 1329 * Initialize split indexes in L3next hop table. 1330 * Parameters: 1331 * unit - (IN)SOC unit number. 1332 * Returns: 1333 * BCM_E_XXX. 1334 */ 1335 1336 STATIC void 1337 bcmi_xgs3_l3_nh_tbl_split_range_init(int unit) 1338 { 1339 _bcm_l3_tbl_t *tbl_ptr; /* Next hop table pointer. */ 1340 #if defined(BCM_RIOT_SUPPORT) 1341 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 1342 #endif 1343 1344 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 1345 if (NULL == tbl_ptr) { 1346 return; 1347 } 1348 1349 /* Set up split table limits */ 1350 #if defined(BCM_RIOT_SUPPORT) 1351 if (BCMI_L3_NH_OVERLAY_VALID(unit)) { 1352 if (l3_bk_info->l3_nh_overlay_alloc_mode > 0) { 1353 tbl_ptr->split_idx = tbl_ptr->idx_max - 1354 l3_bk_info->l3_nh_overlay_entries + 1; 1355 } else { 1356 tbl_ptr->split_idx = l3_bk_info->l3_nh_overlay_entries; 1357 #if defined(BCM_TRIDENT2_SUPPORT) 1358 if (l3_bk_info->l3_nh_reserve_for_ecmp) { 1359 tbl_ptr->split_idx += BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); 1360 } 1361 #endif 1362 } 1363 tbl_ptr->idx_maxused = tbl_ptr->split_idx; 1364 tbl_ptr->split_maxused = tbl_ptr->idx_min; 1365 } else 1366 #endif /* BCM_RIOT_SUPPORT */ 1367 { 1368 tbl_ptr->split_idx = 0; 1369 tbl_ptr->split_maxused = 0; 1370 } 1371 return; 1372 } 1373 #endif /* defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) */ 1374 1375 /* 1376 * Function: 1377 * _bcm_xgs3_l3_nh_init 1378 * Purpose: 1379 * Initialize L3next hop table. 1380 * Parameters: 1381 * unit - (IN)SOC unit number. 1382 * Returns: 1383 * Number of L3 entries. 1384 */ 1385 STATIC int 1386 _bcm_xgs3_l3_nh_init(int unit) 1387 { 1388 int mem_sz; /* Allocation memory size. */ 1389 _bcm_l3_tbl_t *tbl_ptr; /* Next hop table pointer. */ 1390 1391 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 1392 /* Get first next hop index. */ 1393 /* NOTE: First next hop index is reserved for LPM/HOST lookup failure. */ 1394 tbl_ptr->idx_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, nh)) + 1; 1395 /* Get last next hop index. */ 1396 tbl_ptr->idx_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, nh)); 1397 /* Set next hop max used to first next hop entry.(table empty) */ 1398 tbl_ptr->idx_maxused = tbl_ptr->idx_min; 1399 1400 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1401 bcmi_xgs3_l3_nh_tbl_split_range_init(unit); 1402 #endif 1403 1404 /* Return next hop table size. */ 1405 BCM_XGS3_L3_NH_TBL_SIZE(unit) = 1406 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, nh)); 1407 1408 /* 1409 * Keep track of Next Hop table usage. 1410 */ 1411 mem_sz = BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(_bcm_l3_tbl_ext_t); 1412 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TBL(unit, next_hop).ext_arr, mem_sz, "l3_nh"); 1413 if (NULL == BCM_XGS3_L3_TBL(unit, next_hop).ext_arr) { 1414 return (BCM_E_MEMORY); 1415 } 1416 1417 /* 1418 * Keep track of Next Hop table usage. 1419 */ 1420 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 1421 mem_sz = BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int); 1422 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_NH_MULTI_COUNT(unit), mem_sz, 1423 "l3_nh_multi_count"); 1424 if (NULL == BCM_XGS3_L3_NH_MULTI_COUNT(unit)) { 1425 return (BCM_E_MEMORY); 1426 } 1427 } 1428 1429 1430 return (BCM_E_NONE); 1431 } 1432 1433 #ifdef BCM_WARM_BOOT_SUPPORT 1434 #define BCM_WB_VERSION_1_17 SOC_SCACHE_VERSION(1,17) 1435 #define BCM_WB_VERSION_1_16 SOC_SCACHE_VERSION(1,16) 1436 #define BCM_WB_VERSION_1_15 SOC_SCACHE_VERSION(1,15) 1437 #define BCM_WB_VERSION_1_14 SOC_SCACHE_VERSION(1,14) 1438 #define BCM_WB_VERSION_1_13 SOC_SCACHE_VERSION(1,13) 1439 #define BCM_WB_VERSION_1_12 SOC_SCACHE_VERSION(1,12) 1440 #define BCM_WB_VERSION_1_11 SOC_SCACHE_VERSION(1,11) 1441 #define BCM_WB_VERSION_1_10 SOC_SCACHE_VERSION(1,10) 1442 #define BCM_WB_VERSION_1_9 SOC_SCACHE_VERSION(1,9) 1443 #define BCM_WB_VERSION_1_8 SOC_SCACHE_VERSION(1,8) 1444 #define BCM_WB_VERSION_1_7 SOC_SCACHE_VERSION(1,7) 1445 #define BCM_WB_VERSION_1_6 SOC_SCACHE_VERSION(1,6) 1446 #define BCM_WB_VERSION_1_5 SOC_SCACHE_VERSION(1,5) 1447 #define BCM_WB_VERSION_1_4 SOC_SCACHE_VERSION(1,4) 1448 #define BCM_WB_VERSION_1_3 SOC_SCACHE_VERSION(1,3) 1449 #define BCM_WB_VERSION_1_2 SOC_SCACHE_VERSION(1,2) 1450 #define BCM_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 1451 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 1452 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_17 1453 1454 /* 1455 * _bcm_xgs3_l3_l3table_reinit 1456 * 1457 * Updates l3_v4mc_added and l3_v6mc_added counts 1458 */ 1459 STATIC int 1460 _bcm_xgs3_l3_l3table_reinit(int unit) 1461 { 1462 int i; /* Iteration index. */ 1463 int index_min; /* First entry index. */ 1464 int index_max; /* Last entry index. */ 1465 int rv; /* Operation return value. */ 1466 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 1467 _bcm_l3_cfg_t l3_cfg; /* Extracted IPMC entry */ 1468 #if defined(BCM_HAWKEYE_SUPPORT) 1469 if (SOC_IS_HAWKEYE(unit)) { 1470 return BCM_E_NONE; 1471 } 1472 #endif 1473 /* Make sure hw call pointer was initialized. */ 1474 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get_by_idx)) { 1475 return (BCM_E_UNAVAIL); 1476 } 1477 1478 /* First do IPv4MC table */ 1479 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4))) { 1480 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4)); 1481 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4)); 1482 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4), 1483 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4), 1484 "l3_tbl", &l3_tbl_ptr, NULL); 1485 if (BCM_FAILURE(rv)) { 1486 l3_tbl_ptr = NULL; 1487 } 1488 1489 for (i = index_min; i <= index_max; i++) { 1490 l3_cfg.l3c_flags = 0; 1491 BCM_XGS3_L3_MODULE_LOCK(unit); 1492 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get_by_idx)( 1493 unit, l3_tbl_ptr, 1494 i, &l3_cfg); 1495 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1496 1497 if (rv == BCM_E_NOT_FOUND) { 1498 continue; 1499 } else if (BCM_FAILURE(rv)) { 1500 goto cleanup; 1501 } 1502 BCM_XGS3_L3_IP4_IPMC_CNT(unit)++; 1503 } 1504 if (l3_tbl_ptr) { 1505 soc_cm_sfree(unit, l3_tbl_ptr); 1506 l3_tbl_ptr = NULL; 1507 } 1508 } 1509 1510 /* Now IPv6MC table */ 1511 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6))) { 1512 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6)); 1513 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6)); 1514 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6), 1515 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6), 1516 "l3_tbl", &l3_tbl_ptr, NULL); 1517 if (BCM_FAILURE(rv)) { 1518 l3_tbl_ptr = NULL; 1519 } 1520 1521 for (i = index_min; i <= index_max; i++) { 1522 l3_cfg.l3c_flags = BCM_L3_IP6; 1523 BCM_XGS3_L3_MODULE_LOCK(unit); 1524 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get_by_idx)( 1525 unit, l3_tbl_ptr, 1526 i, &l3_cfg); 1527 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1528 if (rv == BCM_E_NOT_FOUND) { 1529 continue; 1530 } else if (BCM_FAILURE(rv)) { 1531 goto cleanup; 1532 } 1533 BCM_XGS3_L3_IP6_IPMC_CNT(unit)++; 1534 } 1535 } 1536 rv = BCM_E_NONE; 1537 1538 cleanup: 1539 if (l3_tbl_ptr) { 1540 soc_cm_sfree(unit, l3_tbl_ptr); 1541 } 1542 return rv; 1543 } 1544 1545 STATIC int 1546 _bcm_xgs3_l3_nh_reinit(int unit, int egressMode) 1547 { 1548 int idx; /* Iteration index. */ 1549 int index_min; /* First interface entry index. */ 1550 int index_max; /* Last interface entry index. */ 1551 int ret_val; /* Operation return value. */ 1552 int nh_idx; /* Next hop index from L3 */ 1553 int flex_v4_entry; /* IPv4 flex view entry */ 1554 bcm_l3_egress_t nh_info; /* Next hop (egress) info */ 1555 bcm_l3_egress_t nh_null; /* Next hop (egress) info null entry */ 1556 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 1557 char *egr_nh_tbl_ptr = NULL; /* Egr NH Table dma pointer. */ 1558 #ifdef BCM_TOMAHAWK3_SUPPORT 1559 char *egr_nh2_tbl_ptr = NULL; /* Egr NH_2 Table dma pointer. */ 1560 #endif 1561 _bcm_l3_tbl_t *tbl_ptr; /* Next hop table pointer. */ 1562 _bcm_l3_cfg_t l3_cfg; /* Extracted L3 entry */ 1563 #if defined(BCM_HAWKEYE_SUPPORT) 1564 _bcm_rp_l3_data_t *rp_tbl_ptr; 1565 #endif 1566 1567 #ifdef BCM_TRIDENT3_SUPPORT 1568 if (soc_feature(unit, soc_feature_flex_flow)) { 1569 BCM_IF_ERROR_RETURN(_bcm_td3_l3_repl_l3_intf_recover(unit)); 1570 } 1571 #endif 1572 1573 /* Make sure hw call pointer was initialized. */ 1574 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_get)) { 1575 return (BCM_E_UNAVAIL); 1576 } 1577 1578 /* Get next hop table start & end index. */ 1579 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 1580 tbl_ptr->idx_min = index_min = 1581 soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, nh)) + 1; 1582 tbl_ptr->idx_max = index_max = 1583 soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, nh)); 1584 tbl_ptr->idx_maxused = 0; 1585 1586 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1587 bcmi_xgs3_l3_nh_tbl_split_range_init(unit); 1588 #endif 1589 1590 /* BCM_XGS3_L3_NH_TBL_SIZE(unit) = index_max - index_min + 1;*/ 1591 BCM_XGS3_L3_NH_TBL_SIZE(unit) = 1592 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, nh)); 1593 1594 bcm_l3_egress_t_init(&nh_null); 1595 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, nh), 1596 BCM_XGS3_L3_ENT_SZ(unit, nh), 1597 "l3_tbl", &l3_tbl_ptr, NULL); 1598 if (BCM_FAILURE(ret_val)) { 1599 l3_tbl_ptr = NULL; 1600 } 1601 1602 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOPm)) { 1603 ret_val = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm, 1604 sizeof(egr_l3_next_hop_entry_t), 1605 "egr_nh_tbl", &egr_nh_tbl_ptr, NULL); 1606 if (BCM_FAILURE(ret_val)) { 1607 egr_nh_tbl_ptr = NULL; 1608 } 1609 } 1610 #ifdef BCM_TOMAHAWK3_SUPPORT 1611 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 1612 ret_val = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOP_2m, 1613 sizeof(egr_l3_next_hop_2_entry_t), 1614 "egr_nh2_tbl", &egr_nh2_tbl_ptr, NULL); 1615 if (BCM_FAILURE(ret_val)) { 1616 egr_nh2_tbl_ptr = NULL; 1617 goto cleanup; 1618 } 1619 } 1620 #endif 1621 /* Loop over all valid next hop entries. */ 1622 for (idx = index_min; idx <= index_max; idx++) { 1623 uint8 nh_ent_type = -1; /* Next hop Entry type */ 1624 bcm_l3_egress_t_init(&nh_info); 1625 if ((NULL == l3_tbl_ptr) || (NULL == egr_nh_tbl_ptr)) { 1626 BCM_XGS3_L3_MODULE_LOCK(unit); 1627 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_get)(unit, idx, 1628 &nh_info); 1629 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1630 if (BCM_FAILURE(ret_val)) { 1631 goto cleanup; 1632 } 1633 } else { 1634 uint32 *ing_entry_ptr = NULL; 1635 uint32 *egr_entry_ptr = NULL; 1636 uint32 *egr_entry_2_ptr = NULL; 1637 ing_l3_next_hop_entry_t ing_entry_null; 1638 egr_l3_next_hop_entry_t egr_entry_null; 1639 1640 sal_memcpy(&ing_entry_null, 1641 soc_mem_entry_null(unit, 1642 BCM_XGS3_L3_MEM(unit, nh)), 1643 sizeof(ing_l3_next_hop_entry_t)); 1644 sal_memcpy(&egr_entry_null, 1645 soc_mem_entry_null(unit, EGR_L3_NEXT_HOPm), 1646 sizeof(egr_l3_next_hop_entry_t)); 1647 1648 ing_entry_ptr = 1649 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, nh), 1650 uint32 *, l3_tbl_ptr, idx); 1651 1652 egr_entry_ptr = 1653 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm, uint32 *, 1654 egr_nh_tbl_ptr, idx); 1655 1656 #ifdef BCM_TOMAHAWK3_SUPPORT 1657 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 1658 egr_entry_2_ptr = 1659 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOP_2m, uint32 *, 1660 egr_nh2_tbl_ptr, idx); 1661 } 1662 #endif 1663 1664 if (sal_memcmp(ing_entry_ptr, &ing_entry_null, 1665 BCM_XGS3_L3_ENT_SZ(unit, nh)) || 1666 sal_memcmp(egr_entry_ptr, &egr_entry_null, 1667 soc_mem_entry_bytes(unit, EGR_L3_NEXT_HOPm))) { 1668 (void)_bcm_xgs3_nh_entry_parse(unit, ing_entry_ptr, 1669 egr_entry_ptr, egr_entry_2_ptr, idx, &nh_info, &nh_ent_type); 1670 } 1671 } 1672 /* If only L3 Intf(L3 Intf 0) is programmed , checking whther the entry type is valid or not */ 1673 if (!sal_memcmp(&nh_info, &nh_null, sizeof(bcm_l3_egress_t)) && (6 != nh_ent_type)) { 1674 continue; 1675 } 1676 if (idx == index_min) { 1677 /* This corresponds to the CPU */ 1678 BCM_XGS3_L3_ENT_HASH(tbl_ptr, idx) = 0; 1679 } else { 1680 /* Compute hash normally */ 1681 _bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_info); 1682 _bcm_xgs3_nh_hash_calc(unit, &nh_info, 1683 &BCM_XGS3_L3_ENT_HASH(tbl_ptr, idx)); 1684 1685 /* Update hash & reference count info. */ 1686 if (egressMode) { 1687 BCM_XGS3_L3_ENT_INIT(tbl_ptr, idx, _BCM_SINGLE_WIDE, BCM_XGS3_L3_ENT_HASH(tbl_ptr, idx)); 1688 } 1689 } 1690 1691 /* 1692 * Set to indicate that L3 interface is used in Next Hop entry. 1693 * This is used to skip the Next Hop table search in 1694 * _bcm_fb_nh_intf_is_tnl_update(). 1695 */ 1696 BCM_XGS3_L3_INTF_USED_NH_SET(unit, nh_info.intf); 1697 1698 BCM_XGS3_L3_NH_CNT(unit)++; 1699 #ifdef BCM_RIOT_SUPPORT 1700 if (BCMI_RIOT_IS_ENABLED(unit)) { 1701 bcmi_l3_nh_assoc_ol_ul_link_reinit(unit, idx); 1702 } 1703 if ((tbl_ptr->split_idx > 0) && (idx < tbl_ptr->split_idx)) { 1704 tbl_ptr->split_maxused = idx; 1705 } else 1706 #endif 1707 { 1708 tbl_ptr->idx_maxused = idx; 1709 } 1710 } 1711 if (l3_tbl_ptr) { 1712 soc_cm_sfree(unit, l3_tbl_ptr); 1713 l3_tbl_ptr = NULL; 1714 } 1715 1716 /* 1717 * NH table is referenced to from three different tables 1718 * DEFIP, L3_ENTRY_IPV4 and L3_ENTRY_IPV6; In this routine, 1719 * we update NH software state based on references from 1720 * L3_ENTRY_IPV4 and L3_ENTRY_IPV6; References from DEFIP 1721 * table will be accounted for in ecmp_reinit() (See below) 1722 * Recover nh usecount from IPv4 unicast L3 table 1723 */ 1724 1725 #if defined(BCM_HAWKEYE_SUPPORT) 1726 /* 1727 * Update NH table reference count with software DEFIP table. 1728 */ 1729 if (SOC_IS_HAWKEYE(unit)) { 1730 /* Get l3 prefixes table. */ 1731 rp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 1732 1733 /* Iterate over all host rules try to match passed address. */ 1734 for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) { 1735 if (!(rp_tbl_ptr->l3_arr[idx].flags & BCM_XGS3_L3_ENT_VALID)) { 1736 continue; 1737 } 1738 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, 1739 rp_tbl_ptr->l3_arr[idx].nh_idx, 1740 _BCM_SINGLE_WIDE); 1741 } 1742 ret_val = BCM_E_NONE; 1743 goto cleanup; 1744 } 1745 #endif 1746 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4))) { 1747 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v4)); 1748 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v4)); 1749 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v4), 1750 BCM_XGS3_L3_ENT_SZ(unit, v4), 1751 "l3_tbl", &l3_tbl_ptr, NULL); 1752 if (BCM_FAILURE(ret_val)) { 1753 l3_tbl_ptr = NULL; 1754 } 1755 /* Loop over all valid IPV4 unicast entries to get nh use count. */ 1756 for (idx = index_min; idx <= index_max; idx++) { 1757 l3_cfg.l3c_flags = 0; 1758 BCM_XGS3_L3_MODULE_LOCK(unit); 1759 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)( 1760 unit, l3_tbl_ptr, idx, 1761 &l3_cfg, &nh_idx); 1762 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1763 if (ret_val == BCM_E_NOT_FOUND) { 1764 continue; 1765 } else if (BCM_FAILURE(ret_val)) { 1766 goto cleanup; 1767 } 1768 if ((l3_cfg.l3c_flags & BCM_L3_IP6) == BCM_L3_IP6) { 1769 continue; 1770 } 1771 if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) { 1772 continue; 1773 } 1774 BCM_XGS3_L3_IP4_CNT(unit)++; 1775 if((l3_cfg.l3c_flags & BCM_L3_MULTIPATH) != BCM_L3_MULTIPATH) { 1776 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_idx, _BCM_SINGLE_WIDE); 1777 } 1778 } 1779 if (l3_tbl_ptr) { 1780 soc_cm_sfree(unit, l3_tbl_ptr); 1781 l3_tbl_ptr = NULL; 1782 } 1783 } 1784 1785 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v6))) { 1786 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v6)); 1787 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v6)); 1788 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v6), 1789 BCM_XGS3_L3_ENT_SZ(unit, v6), 1790 "l3_tbl", &l3_tbl_ptr, NULL); 1791 if (BCM_FAILURE(ret_val)) { 1792 l3_tbl_ptr = NULL; 1793 } 1794 /* 1795 * Loop over all valid IPV6 unicast entries to get nh use count. 1796 */ 1797 for (idx = index_min; idx <= index_max; idx++) { 1798 flex_v4_entry = 0; 1799 l3_cfg.l3c_flags = BCM_L3_IP6; 1800 BCM_XGS3_L3_MODULE_LOCK(unit); 1801 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)( 1802 unit, l3_tbl_ptr, idx, &l3_cfg, &nh_idx); 1803 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1804 if (ret_val == BCM_E_NOT_FOUND) { 1805 continue; 1806 } else if (BCM_FAILURE(ret_val)) { 1807 goto cleanup; 1808 } 1809 #if defined(BCM_TRIDENT3_SUPPORT) 1810 if (soc_feature(unit, soc_feature_flex_flow)) { 1811 soc_field_t data_type = 0; 1812 uint32 view_id = 0; 1813 int rv, alloc = FALSE; 1814 uint32 *buf_entry = NULL; 1815 soc_mem_t l3_mem = BCM_XGS3_L3_MEM(unit, v6); 1816 1817 if (l3_tbl_ptr == NULL) { 1818 BCM_XGS3_L3_ALLOC(buf_entry, BCM_XGS3_L3_ENT_SZ(unit, v6), 1819 "buf entry"); 1820 if (buf_entry == NULL) { 1821 ret_val = BCM_E_MEMORY; 1822 goto cleanup; 1823 } 1824 ret_val = BCM_XGS3_MEM_READ(unit, l3_mem, idx, buf_entry); 1825 if (ret_val != BCM_E_NONE) { 1826 sal_free(buf_entry); 1827 goto cleanup; 1828 } 1829 alloc = TRUE; 1830 } else { 1831 buf_entry = soc_mem_table_idx_to_pointer(unit, l3_mem, 1832 uint32 *, l3_tbl_ptr, idx); 1833 } 1834 if (soc_mem_field_valid(unit, l3_mem, DATA_TYPEf)) { 1835 data_type = soc_mem_field32_get(unit, l3_mem, 1836 buf_entry, DATA_TYPEf); 1837 rv = soc_flow_db_mem_to_view_id_get(unit, 1838 l3_mem, 1839 SOC_FLOW_DB_KEY_TYPE_INVALID, 1840 data_type, 1841 0, 1842 NULL, 1843 &view_id); 1844 if (rv == BCM_E_NONE) { 1845 if (SOC_MEM_FIELD_VALID(unit, view_id, IPV4__SIPf) || 1846 SOC_MEM_FIELD_VALID(unit, view_id, IPV4__DIPf)) { 1847 flex_v4_entry = 1; 1848 } 1849 } 1850 } 1851 if (alloc == TRUE) { 1852 sal_free(buf_entry); 1853 } 1854 } 1855 #endif 1856 if (!flex_v4_entry && ((l3_cfg.l3c_flags & BCM_L3_IP6) != BCM_L3_IP6)) { 1857 continue; 1858 } 1859 if (!flex_v4_entry && ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC)) { 1860 continue; 1861 } 1862 1863 if (flex_v4_entry) { 1864 BCM_XGS3_L3_IP4_CNT(unit)++; 1865 } else { 1866 BCM_XGS3_L3_IP6_CNT(unit)++; 1867 } 1868 1869 if((l3_cfg.l3c_flags & BCM_L3_MULTIPATH) != BCM_L3_MULTIPATH) { 1870 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_idx, _BCM_SINGLE_WIDE); 1871 } 1872 } 1873 if (l3_tbl_ptr) { 1874 soc_cm_sfree(unit, l3_tbl_ptr); 1875 l3_tbl_ptr = NULL; 1876 } 1877 } 1878 #if defined(BCM_TRIUMPH3_SUPPORT) 1879 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 1880 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4_2))) { 1881 /* Loop over all valid IPV4 unicast entries to get nh use count. */ 1882 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v4_2)); 1883 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v4_2)); 1884 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v4_2), 1885 BCM_XGS3_L3_ENT_SZ(unit, v4_2), 1886 "l3_tbl", &l3_tbl_ptr, NULL); 1887 if (BCM_FAILURE(ret_val)) { 1888 l3_tbl_ptr = NULL; 1889 } 1890 for (idx = index_min; idx <= index_max; idx++) { 1891 l3_cfg.l3c_flags = BCM_L3_DEREFERENCED_NEXTHOP; 1892 BCM_XGS3_L3_MODULE_LOCK(unit); 1893 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(unit, l3_tbl_ptr, 1894 idx, &l3_cfg, 1895 &nh_idx); 1896 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1897 if (ret_val == BCM_E_NOT_FOUND) { 1898 continue; 1899 } else if (BCM_FAILURE(ret_val)) { 1900 goto cleanup; 1901 } 1902 if ((l3_cfg.l3c_flags & BCM_L3_IP6) == BCM_L3_IP6) { 1903 continue; 1904 } 1905 if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) { 1906 continue; 1907 } 1908 BCM_XGS3_L3_IP4_CNT(unit)++; 1909 } 1910 if (l3_tbl_ptr) { 1911 soc_cm_sfree(unit, l3_tbl_ptr); 1912 l3_tbl_ptr = NULL; 1913 } 1914 } 1915 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v6_4))) { 1916 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v6_4)); 1917 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v6_4)); 1918 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v6_4), 1919 BCM_XGS3_L3_ENT_SZ(unit, v6_4), 1920 "l3_tbl", &l3_tbl_ptr, NULL); 1921 if (BCM_FAILURE(ret_val)) { 1922 l3_tbl_ptr = NULL; 1923 } 1924 /* Loop over all valid IPV6 unicast entries to get nh use count. */ 1925 for (idx = index_min; idx <= index_max; idx++) { 1926 l3_cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_DEREFERENCED_NEXTHOP; 1927 BCM_XGS3_L3_MODULE_LOCK(unit); 1928 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(unit, l3_tbl_ptr, 1929 idx, &l3_cfg, 1930 &nh_idx); 1931 BCM_XGS3_L3_MODULE_UNLOCK(unit); 1932 if (ret_val == BCM_E_NOT_FOUND) { 1933 continue; 1934 } else if (BCM_FAILURE(ret_val)) { 1935 goto cleanup; 1936 } 1937 if ((l3_cfg.l3c_flags & BCM_L3_IP6) != BCM_L3_IP6) { 1938 continue; 1939 } 1940 if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) { 1941 continue; 1942 } 1943 BCM_XGS3_L3_IP6_CNT(unit)++; 1944 #if defined(BCM_TRIDENT3_SUPPORT) 1945 if (soc_feature(unit, soc_feature_flex_flow)) { 1946 soc_field_t data_type_64 = 0; 1947 uint32 view_id_64 = 0; 1948 int rv_64, alloc = FALSE; 1949 uint32 *buf_entry_64 = NULL; 1950 soc_mem_t l3_mem_64 = BCM_XGS3_L3_MEM(unit, v6_4); 1951 if (l3_tbl_ptr == NULL) { 1952 BCM_XGS3_L3_ALLOC(buf_entry_64, BCM_XGS3_L3_ENT_SZ(unit, v6_4), 1953 "buf entry 64"); 1954 if (buf_entry_64 == NULL) { 1955 ret_val = BCM_E_MEMORY; 1956 goto cleanup; 1957 } 1958 ret_val = BCM_XGS3_MEM_READ(unit, l3_mem_64, idx, buf_entry_64); 1959 if (ret_val != BCM_E_NONE) { 1960 sal_free(buf_entry_64); 1961 goto cleanup; 1962 } 1963 alloc = TRUE; 1964 } else { 1965 buf_entry_64 = soc_mem_table_idx_to_pointer(unit, l3_mem_64, 1966 uint32 *, l3_tbl_ptr, idx); 1967 } 1968 if (soc_mem_field_valid(unit, l3_mem_64, DATA_TYPEf)) { 1969 data_type_64 = soc_mem_field32_get(unit, l3_mem_64, 1970 buf_entry_64, DATA_TYPEf); 1971 rv_64 = soc_flow_db_mem_to_view_id_get(unit, 1972 l3_mem_64, 1973 SOC_FLOW_DB_KEY_TYPE_INVALID, 1974 data_type_64, 1975 0, 1976 NULL, 1977 &view_id_64); 1978 if (rv_64 == BCM_E_NONE) { 1979 if (SOC_MEM_FIELD_VALID(unit, view_id_64, IPV6__SIPf) || 1980 SOC_MEM_FIELD_VALID(unit, view_id_64, IPV6__DIPf)) { 1981 if((l3_cfg.l3c_flags & BCM_L3_MULTIPATH) != BCM_L3_MULTIPATH) { 1982 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_idx, _BCM_SINGLE_WIDE); 1983 } 1984 } 1985 } 1986 } 1987 if (alloc == TRUE) { 1988 sal_free(buf_entry_64); 1989 } 1990 } 1991 #endif 1992 } 1993 } 1994 } 1995 #endif 1996 ret_val = BCM_E_NONE; 1997 cleanup: 1998 if (l3_tbl_ptr) { 1999 soc_cm_sfree(unit, l3_tbl_ptr); 2000 } 2001 if (egr_nh_tbl_ptr) { 2002 soc_cm_sfree(unit, egr_nh_tbl_ptr); 2003 } 2004 #ifdef BCM_TOMAHAWK3_SUPPORT 2005 if (egr_nh2_tbl_ptr) { 2006 soc_cm_sfree(unit, egr_nh2_tbl_ptr); 2007 } 2008 #endif 2009 return ret_val; 2010 } 2011 2012 #ifdef BCM_TRIDENT2_SUPPORT 2013 /* 2014 * Function: 2015 * _bcm_xgs3_l3_ingress_intf_reinit 2016 * Purpose: 2017 * Recover l3 ingress interfaces info 2018 * Parameters: 2019 * unit - SOC unit number 2020 * Returns: 2021 * BCM_E_XXX 2022 */ 2023 STATIC int 2024 _bcm_xgs3_l3_ingress_intf_reinit(int unit) 2025 { 2026 int idx; /* Iteration index. */ 2027 int rv = BCM_E_NONE; /* Operation return status.*/ 2028 uint8 index; 2029 char *iif_tbl_ptr = NULL; /* IIF Table dma pointer. */ 2030 uint32 *iif_entry_ptr = NULL; /* IIF Profile entry buffer pointer.*/ 2031 2032 if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) > 0) { 2033 rv = bcm_xgs3_l3_tbl_dma(unit, L3_IIFm, 2034 sizeof(iif_entry_t), 2035 "l3_iif", &iif_tbl_ptr, NULL); 2036 if (BCM_FAILURE(rv)) { 2037 goto cleanup; 2038 } 2039 } 2040 2041 for (idx=0; idx < (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); idx++) { 2042 2043 if (!(SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx))) { 2044 continue; 2045 } 2046 2047 iif_entry_ptr = 2048 soc_mem_table_idx_to_pointer(unit, L3_IIFm, uint32 *, 2049 iif_tbl_ptr, idx); 2050 2051 /* coverity[var_deref_model : FALSE] */ 2052 index = soc_mem_field32_get(unit, L3_IIFm, iif_entry_ptr, 2053 L3_IIF_PROFILE_INDEXf); 2054 2055 rv = _bcm_l3_iif_profile_entry_reference(unit, index, 1); 2056 if (BCM_FAILURE(rv)) { 2057 goto cleanup; 2058 } 2059 } 2060 cleanup: 2061 if (iif_tbl_ptr) { 2062 soc_cm_sfree(unit, iif_tbl_ptr); 2063 } 2064 2065 return rv; 2066 } 2067 #endif 2068 2069 STATIC int 2070 _bcm_xgs3_l3_intf_reinit(int unit) 2071 { 2072 int idx; /* Iteration index. */ 2073 _bcm_l3_intf_cfg_t intf_info; /* Interface configuration. */ 2074 bcm_tunnel_initiator_t tnl_info;/* Tunnel initiator struct. */ 2075 int ret_val; /* Operation return value. */ 2076 int entry_width; /* Tunnel entry width. */ 2077 bcm_mac_t mac; 2078 _bcm_l3_tbl_t *tbl_ptr; /* L3 egress intf table pointer. */ 2079 soc_mem_t mem; 2080 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 2081 uint32 *l3_if_entry_ptr = NULL; /* Interface read buffer address. */ 2082 _bcm_l3_intf_fields_t *fld = NULL; /* Interface table common fields. */ 2083 2084 int ingress_map_mode = 0; 2085 #ifdef BCM_RIOT_SUPPORT 2086 egr_mac_da_profile_entry_t macda; 2087 int profiled_mac = 0; 2088 int macda_index = -1; 2089 #endif 2090 bcm_l3_intf_t intf_tmp; 2091 2092 /* Make sure hw call pointer was initialized. */ 2093 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 2094 return (BCM_E_UNAVAIL); 2095 } 2096 2097 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf); 2098 /* Get first egr intf index. */ 2099 if (soc_feature(unit, soc_feature_l3_egr_intf_zero_invalid)) { 2100 tbl_ptr->idx_min = soc_mem_index_min(unit, 2101 BCM_XGS3_L3_MEM(unit, intf)) + 1; 2102 } else { 2103 tbl_ptr->idx_min = soc_mem_index_min(unit, 2104 BCM_XGS3_L3_MEM(unit, intf)); 2105 } 2106 /* Get last egr intf index. */ 2107 tbl_ptr->idx_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, intf)); 2108 /* Set egr intf max used to first entry.(table empty) */ 2109 tbl_ptr->idx_maxused = tbl_ptr->idx_min; 2110 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 2111 /* Set up split table limits */ 2112 tbl_ptr->split_idx = 0; 2113 tbl_ptr->split_maxused = 0; 2114 #endif 2115 2116 /* Get interface table start & end index. */ 2117 BCM_XGS3_L3_IF_TBL_SIZE(unit) = tbl_ptr->idx_max + 1; 2118 sal_memset (mac, 0, sizeof(bcm_mac_t)); 2119 sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t)); 2120 2121 mem = BCM_XGS3_L3_MEM(unit, intf); 2122 ret_val = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, intf), 2123 "l3_tbl", &l3_tbl_ptr, NULL); 2124 if (BCM_FAILURE(ret_val)) { 2125 l3_tbl_ptr = NULL; 2126 } 2127 2128 /* Loop over all valid interfaces. */ 2129 for (idx = tbl_ptr->idx_min; idx <= tbl_ptr->idx_max; idx++) { 2130 2131 /* Read interface from hardware. */ 2132 intf_info.l3i_index = idx; 2133 if (NULL == l3_tbl_ptr) { 2134 BCM_XGS3_L3_MODULE_LOCK(unit); 2135 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get)(unit, &intf_info); 2136 BCM_XGS3_L3_MODULE_UNLOCK(unit); 2137 if (BCM_FAILURE(ret_val)) { 2138 goto cleanup; 2139 } 2140 } else { 2141 l3_if_entry_ptr = 2142 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 2143 l3_tbl_ptr, 2144 intf_info.l3i_index); 2145 2146 /* Extract interface information. */ 2147 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 2148 2149 /* Get vlan id. */ 2150 #ifdef BCM_RIOT_SUPPORT 2151 if (soc_feature(unit, soc_feature_riot)) { 2152 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) { 2153 profiled_mac = soc_mem_field32_get(unit, mem, l3_if_entry_ptr, 2154 MAC_ADDRESS_OVERLAY_TYPEf); 2155 macda_index = soc_mem_field32_get(unit, mem, l3_if_entry_ptr, 2156 MAC_ADDRESS_PROFILE_IDXf); 2157 } 2158 if (profiled_mac) { 2159 /* Read entry from MAC-DA-PROFILEm */ 2160 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm, 2161 MEM_BLOCK_ANY, macda_index, &macda)); 2162 /* Get mac address from EGR_MACDA_PROFILE. */ 2163 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, &macda, 2164 MAC_ADDRESSf, intf_info.l3i_mac_addr); 2165 2166 if (soc_mem_field_valid(unit, mem, DATA_TYPEf) && 2167 (0 == soc_mem_field32_get(unit, mem, l3_if_entry_ptr, 2168 DATA_TYPEf))) { 2169 2170 _bcm_common_profile_mem_ref_cnt_update(unit, 2171 EGR_MAC_DA_PROFILEm, macda_index, 1); 2172 } 2173 } else { 2174 /* Get mac address from EGR_L3_INTF. */ 2175 soc_mem_mac_addr_get(unit, mem, l3_if_entry_ptr, 2176 fld->mac_addr, intf_info.l3i_mac_addr); 2177 } 2178 /*VLAN_VFI_OVERLAY_TYPE is not required in TD3 */ 2179 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) { 2180 if (profiled_mac) { 2181 /* Use profiled_mac indicator to confirm presence of VFI and read the same */ 2182 _BCM_VPN_SET(intf_info.l3i_vid, _BCM_VPN_TYPE_VFI, 2183 soc_mem_field32_get(unit, mem, l3_if_entry_ptr, VFIf)); 2184 } else { 2185 intf_info.l3i_vid = 2186 soc_mem_field32_get(unit, mem, l3_if_entry_ptr, 2187 fld->vlan_id); 2188 } 2189 } else if (soc_mem_field32_get(unit, mem, l3_if_entry_ptr, 2190 VLAN_VFI_OVERLAY_TYPEf)) { 2191 _BCM_VPN_SET(intf_info.l3i_vid, _BCM_VPN_TYPE_VFI, 2192 soc_mem_field32_get(unit, mem, 2193 l3_if_entry_ptr, VFIf)); 2194 } else { 2195 intf_info.l3i_vid = 2196 soc_mem_field32_get(unit, mem, l3_if_entry_ptr, 2197 fld->vlan_id); 2198 } 2199 } else 2200 #endif 2201 { 2202 intf_info.l3i_vid = soc_mem_field32_get( 2203 unit, mem, l3_if_entry_ptr, fld->vlan_id); 2204 /* Get mac address. */ 2205 soc_mem_mac_addr_get(unit, mem, l3_if_entry_ptr, 2206 fld->mac_addr, intf_info.l3i_mac_addr); 2207 } 2208 2209 /* Get tunnel index. */ 2210 if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) { 2211 intf_info.l3i_tunnel_idx = soc_mem_field32_get( 2212 unit, mem, l3_if_entry_ptr, fld->tnl_id); 2213 } 2214 } 2215 2216 if (!sal_memcmp(intf_info.l3i_mac_addr, mac, sizeof(bcm_mac_t)) && 2217 !BCM_VLAN_VALID(intf_info.l3i_vid)){ 2218 continue; 2219 } 2220 2221 if (!BCM_L3_INTF_USED_GET(unit, idx)) { 2222 /* Mark interface as used */ 2223 BCM_L3_INTF_USED_SET(unit, idx); 2224 } 2225 2226 #ifdef BCM_TRIUMPH_SUPPORT 2227 /* Reference count for VLAN VRF */ 2228 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 2229 ret_val = bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode); 2230 if (BCM_FAILURE(ret_val)) { 2231 goto cleanup; 2232 } 2233 } 2234 #endif 2235 if (!ingress_map_mode || 2236 SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) { 2237 /* Increment ref count on related VLAN VRF here */ 2238 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ing_intf), 2239 intf_info.l3i_vid, _BCM_SINGLE_WIDE); 2240 } 2241 2242 /* Reference counts & signatures for tnl_init and adj_mac tables. */ 2243 if (intf_info.l3i_tunnel_idx > 0) { 2244 bcm_tunnel_initiator_t_init(&tnl_info); 2245 bcm_l3_intf_t_init(&intf_tmp); 2246 intf_tmp.l3a_intf_id = intf_info.l3i_index; 2247 ret_val = bcm_xgs3_tunnel_initiator_get(unit, &intf_tmp, &tnl_info); 2248 if (BCM_FAILURE(ret_val)) { 2249 /* For hurricane EGR_L3_INTF:TUNNEL_INDEXf is InValid */ 2250 /* Below check (including SOC_IS_HURRICANE) should be replaced 2251 with intf_info.l3i_tunnel_idx == 0 check */ 2252 /* ================================================== */ 2253 if ((ret_val == BCM_E_NOT_FOUND) && 2254 (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit))) { 2255 continue; 2256 } 2257 goto cleanup; 2258 } 2259 if ((tnl_info.type != bcmTunnelTypeMpls) || 2260 !BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, tnl_init), \ 2261 intf_info.l3i_tunnel_idx)) { 2262 _bcm_xgs3_tnl_init_hash_calc(unit, &tnl_info, 2263 &BCM_XGS3_L3_ENT_HASH(BCM_XGS3_L3_TBL_PTR(unit, tnl_init), 2264 intf_info.l3i_tunnel_idx)); 2265 2266 entry_width = 2267 (_BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, tnl_info.type)) ? \ 2268 _BCM_DOUBLE_WIDE : _BCM_SINGLE_WIDE; 2269 2270 BCM_XGS3_L3_ENT_REF_CNT_INC (BCM_XGS3_L3_TBL_PTR(unit, tnl_init), 2271 intf_info.l3i_tunnel_idx, entry_width); 2272 2273 } 2274 } 2275 } /* Loop over interface table. */ 2276 2277 ret_val = BCM_E_NONE; 2278 2279 cleanup: 2280 if (l3_tbl_ptr) { 2281 soc_cm_sfree(unit, l3_tbl_ptr); 2282 } 2283 return ret_val; 2284 } 2285 2286 /* 2287 * Function: 2288 * _bcm_xgs3_l3_defip_reinit 2289 * Purpose: 2290 * Recover basic DEFIP table info 2291 * Parameters: 2292 * unit - SOC unit number 2293 * Returns: 2294 * BCM_E_XXX 2295 */ 2296 STATIC int 2297 _bcm_xgs3_l3_defip_table_reinit(int unit) 2298 { 2299 int index_min = 0; /* First entry index. */ 2300 int index_max = 0; /* Last entry index. */ 2301 int rv; /* Operation return status. */ 2302 2303 #if defined(BCM_HAWKEYE_SUPPORT) 2304 if (SOC_IS_HAWKEYE(unit)) { 2305 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = BCM_XGS3_L3_RP_MAX_PREFIXES(unit); 2306 return (BCM_E_NONE); 2307 } 2308 #endif 2309 if (soc_feature(unit, soc_feature_esm_support)) { 2310 #ifdef BCM_TRIUMPH_SUPPORT 2311 soc_mem_t mem_v4; /* IPv4 Route table memory. */ 2312 2313 BCM_IF_ERROR_RETURN(_bcm_tr_l3_defip_mem_get(unit, 0, 0, &mem_v4)); 2314 index_min = soc_mem_index_min(unit, mem_v4); 2315 index_max = soc_mem_index_max(unit, mem_v4); 2316 #endif 2317 } else { 2318 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, defip))) { 2319 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, defip)); 2320 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, defip)); 2321 } else { 2322 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 0; 2323 return (BCM_E_NONE); 2324 } 2325 } 2326 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = index_max - index_min + 1; 2327 2328 /* Traverse the defip table */ 2329 rv = bcm_xgs3_defip_traverse(unit, 0, index_min, index_max, NULL, NULL); 2330 if (BCM_FAILURE(rv)) { 2331 return (rv); 2332 } 2333 2334 if (soc_feature(unit, soc_feature_esm_support)) { 2335 #ifdef BCM_TRIUMPH_SUPPORT 2336 soc_mem_t mem_v6; /* IPv6 Route table memory. */ 2337 2338 BCM_IF_ERROR_RETURN 2339 (_bcm_tr_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6)); 2340 index_min = soc_mem_index_min(unit, mem_v6); 2341 index_max = soc_mem_index_max(unit, mem_v6); 2342 #endif 2343 } 2344 2345 /* If warmboot and l3_alpm mode is enabled skip walking defip for IPv6 2346 First defip(IPv4) walk above would have travesered all defip entries*/ 2347 if (soc_feature(unit, soc_feature_alpm) && 2348 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) && 2349 SOC_WARM_BOOT(unit)) { 2350 return (rv); 2351 } else { 2352 rv = bcm_xgs3_defip_traverse(unit, BCM_L3_IP6, index_min, 2353 index_max, NULL, NULL); 2354 if (BCM_FAILURE(rv)) { 2355 return (rv); 2356 } 2357 } 2358 return (rv); 2359 } 2360 2361 #if defined(BCM_TRIUMPH2_SUPPORT) 2362 /* 2363 * Function: 2364 * _bcm_xgs3_l3_flexstat_recover 2365 * Purpose: 2366 * Recover VRF counter table info 2367 * Parameters: 2368 * unit - SOC unit number 2369 * Returns: 2370 * BCM_E_XXX 2371 */ 2372 STATIC int 2373 _bcm_xgs3_l3_flexstat_recover(int unit) 2374 { 2375 int index_min; /* First entry index. */ 2376 int index_max; /* Last entry index. */ 2377 int vrf; /* VRF table index */ 2378 int fs_idx; /* Service counter index */ 2379 int rv = BCM_E_NONE; /* Operation return status. */ 2380 vrf_entry_t vrf_entry; /* VRF memory entry */ 2381 2382 index_min = soc_mem_index_min(unit, VRFm); 2383 index_max = soc_mem_index_max(unit, VRFm); 2384 2385 /* Traverse the VRF table */ 2386 for (vrf = index_min; vrf <= index_max; vrf++) { 2387 rv = READ_VRFm(unit, MEM_BLOCK_ANY, vrf, &vrf_entry); 2388 if (BCM_FAILURE(rv)) { 2389 break; 2390 } 2391 fs_idx = soc_VRFm_field32_get(unit, &vrf_entry, SERVICE_CTR_IDXf); 2392 if (fs_idx) { 2393 _bcm_esw_flex_stat_reinit_add(unit, 2394 _bcmFlexStatTypeVrf, fs_idx, vrf); 2395 } 2396 } 2397 2398 return (rv); 2399 } 2400 #endif /* BCM_TRIUMPH2_SUPPORT */ 2401 2402 #if defined(BCM_TRIDENT_SUPPORT) 2403 int 2404 _bcm_xgs3_trunk_nh_store_recover(int unit) 2405 { 2406 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 2407 int rv=BCM_E_NONE, trunk_idx=-1; 2408 uint32 reg_val=0; 2409 bcm_port_t port_iter; 2410 bcm_module_t local_modid=0; 2411 2412 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get (unit, &local_modid)); 2413 /* EGR_PORT_TO_NHI_MAPPING is not Supported in TD2PLUS, Hence 2414 * Returning Success */ 2415 if (soc_feature(unit, soc_feature_multi_next_hops_on_port)) { 2416 return BCM_E_NONE; 2417 } 2418 2419 PBMP_E_ITER(unit, port_iter) { 2420 if (SOC_IS_STACK_PORT(unit, port_iter)) { 2421 continue; 2422 } 2423 BCM_IF_ERROR_RETURN( 2424 READ_EGR_PORT_TO_NHI_MAPPINGr(unit, port_iter, ®_val)); 2425 rv = bcm_esw_trunk_find(unit, local_modid, port_iter, &trunk_idx); 2426 if (rv == BCM_E_NONE) { 2427 l3_bk_info->l3_trunk_nh_store[trunk_idx] = 2428 soc_reg_field_get(unit, EGR_PORT_TO_NHI_MAPPINGr, reg_val, NEXT_HOP_INDEXf); 2429 } 2430 } 2431 return BCM_E_NONE; 2432 } 2433 #endif /* BCM_TRIDENT_SUPPORT */ 2434 2435 /* 2436 * Function: 2437 * _bcm_esw_l3_warmboot_recover 2438 * Purpose: 2439 * Retrieve from L3 module scache. 2440 * Parameters: 2441 * unit - StrataSwitch unit number. 2442 * Returns: 2443 * BCM_E_XXX 2444 */ 2445 STATIC int 2446 _bcm_esw_l3_warmboot_recover(int unit, int32 *egrmode, int32 *ingrmode, 2447 int32 *hostmode, int32 *intfMapmode, int *ecmp_max_paths, int *ecmp_refcnt) 2448 { 2449 /* 2450 * Match with _bcm_esw_l3_warm_boot_alloc/_bcm_esw_l3_sync 2451 */ 2452 uint8 *l3_scache_ptr; 2453 uint16 recovered_ver; 2454 soc_scache_handle_t scache_handle; 2455 int alloc_sz = sizeof(int32) * 2, stable_size = 0, rv; 2456 int additional_scache_sz = 0; 2457 int alloc_size = 0; 2458 int i; 2459 #ifdef BCM_TRIUMPH3_SUPPORT 2460 int urpfEnable; 2461 #endif /* BCM_TRIUMPH3_SUPPORT */ 2462 #ifdef BCM_TRIUMPH2_SUPPORT 2463 int idx; 2464 #endif 2465 #ifdef BCM_TRIDENT2_SUPPORT 2466 int l3_ip4_options_recover = 0; 2467 uint32 recovered_sz = 0; 2468 #endif 2469 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 2470 int l3_flags_recovered = 0; 2471 int l3_flags_alloced = 0; 2472 uint8 flag = 0; 2473 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 2474 #if defined(BCM_SCORPION_SUPPORT) 2475 uint16 dev_id; 2476 uint8 rev_id; 2477 #endif 2478 #ifdef BCM_TOMAHAWK_SUPPORT 2479 SHR_BITDCL *ecmp_l1_flags = NULL; 2480 SHR_BITDCL *ecmp_l2_flags = NULL; 2481 #endif 2482 SHR_BITDCL *ecmp_flags = NULL; 2483 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 2484 int num_elements; 2485 #endif 2486 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\ 2487 defined(BCM_HURRICANE3_SUPPORT) 2488 int skip_l3_ingress_intf_recover = FALSE; 2489 #endif 2490 2491 *egrmode = 0; /* Default values */ 2492 *ingrmode = 0; 2493 *hostmode = 0; 2494 *intfMapmode = 0; 2495 2496 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L3, 0); 2497 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 2498 if (stable_size > 0) { /* Limited and Extended recovery only */ 2499 2500 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 2501 alloc_sz += sizeof(int32); /* Ingress mode */ 2502 alloc_sz += sizeof(int32); /* IntfMap mode */ 2503 } 2504 2505 #if defined(BCM_SCORPION_SUPPORT) 2506 if (SOC_IS_SCORPION(unit)) { 2507 soc_cm_get_id(unit, &dev_id, &rev_id); 2508 2509 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 2510 alloc_sz, &l3_scache_ptr, 2511 BCM_WB_DEFAULT_VERSION, &recovered_ver); 2512 if (BCM_FAILURE(rv)) { 2513 LOG_ERROR(BSL_LS_BCM_L3, 2514 (BSL_META_U(unit, "Failure on recovering version\n"))); 2515 return rv; 2516 } 2517 if ((dev_id == BCM56820_DEVICE_ID) && 2518 (recovered_ver < BCM_WB_VERSION_1_14)) { 2519 /* Till WB version 13, the ecmp group size was 512. */ 2520 SOC_FEATURE_CLEAR(unit, soc_feature_l3_ecmp_2k_groups); 2521 } 2522 } 2523 #endif /* BCM_SCORPION_SUPPORT */ 2524 2525 #ifdef BCM_TRIUMPH2_SUPPORT 2526 /* For extended scache warmboot mode (level-2) only */ 2527 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 2528 BCM_XGS3_L3_MAX_ECMP_MODE(unit) && 2529 !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) { 2530 alloc_sz += sizeof(uint16) * 2531 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); 2532 } 2533 #endif 2534 2535 #ifdef BCM_TRIUMPH3_SUPPORT 2536 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 2537 int ecmp_dlb_alloc_sz; 2538 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 2539 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 2540 BCM_IF_ERROR_RETURN 2541 (bcm_th2_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz)); 2542 } else 2543 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2544 { 2545 if (!SOC_IS_TRIDENT3X(unit)) { 2546 /* TD3TBD */ 2547 BCM_IF_ERROR_RETURN 2548 (bcm_tr3_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz)); 2549 } 2550 } 2551 alloc_sz += ecmp_dlb_alloc_sz; 2552 } 2553 #endif /* BCM_TRIUMPH3_SUPPORT */ 2554 2555 #ifdef BCM_TRIUMPH2_SUPPORT 2556 if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) || 2557 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 2558 int wb_alloc_sz; 2559 2560 BCM_IF_ERROR_RETURN 2561 (bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get(unit, 2562 &wb_alloc_sz)); 2563 alloc_sz += wb_alloc_sz; 2564 } 2565 #endif /* BCM_TRIUMPH2_SUPPORT */ 2566 2567 #ifdef BCM_TRIDENT2_SUPPORT 2568 /* 2569 * WB version 1.4 was defined for supporting warmboot recovery of 2570 * L3 IP4 Options profile indexes info but the relevant soc feature 2571 * was disabled in sdk-6.2.9. The feature is enabled when the L3 scache 2572 * version is at 1.6. So, 1.4 is just a dummy version. 2573 */ 2574 if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) { 2575 int wb_alloc_sz; 2576 BCM_IF_ERROR_RETURN 2577 (_bcm_td2_l3_ip4_options_profile_scache_len_get(unit, &wb_alloc_sz)); 2578 alloc_sz += wb_alloc_sz; 2579 } 2580 2581 /* 2582 * Check if scache space is allocated for l3_ip4_options_profile. 2583 * 2584 * SDK-6.2.9 did not allocate scache space for ip4 options profile 2585 * although the scache version was at 1.4 (soc_feature was disabled). 2586 * However since the relevant feature was enabled in SDK-6.3.2, 2587 * ip4 options profile information can be recovered with 1.4. 2588 * 2589 * The scache size without ip4 options profile information is 24 Bytes 2590 * To be able to recover the ip4 options profile information, the 2591 * recovered scache size should be greater than 24 Bytes. 2592 */ 2593 SOC_IF_ERROR_RETURN(soc_scache_ptr_get(unit, scache_handle, 2594 &l3_scache_ptr, &recovered_sz)); 2595 recovered_sz -= SOC_WB_SCACHE_CONTROL_SIZE; 2596 l3_ip4_options_recover = (recovered_sz > 24) ? 1 : 0; 2597 2598 2599 #endif /* BCM_TRIDENT2_SUPPORT */ 2600 2601 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\ 2602 defined(BCM_HURRICANE3_SUPPORT) 2603 if (soc_feature(unit, soc_feature_l3_ingress_interface) && 2604 !soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) { 2605 alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 2606 } 2607 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) || 2608 * defined(BCM_HURRICANE3_SUPPORT) 2609 */ 2610 /* Recover ECMP max paths from scache */ 2611 alloc_sz += sizeof(uint32); 2612 2613 /* Determine ECMP_GRP entries size */ 2614 if (soc_feature(unit, soc_feature_l3)) { 2615 alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 2616 } 2617 2618 #ifdef BCM_TRIDENT2_SUPPORT 2619 /* Recover ECMP Ecmp group resorting flags */ 2620 if (soc_feature(unit, soc_feature_l3)) { 2621 alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 2622 } 2623 #endif 2624 2625 #ifdef BCM_TRIUMPH3_SUPPORT 2626 if (soc_feature(unit, soc_feature_l2gre)) { 2627 alloc_sz += BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8); 2628 l3_flags_alloced = 1; 2629 } 2630 #endif /* BCM_TRIUMPH3_SUPPORT */ 2631 #ifdef BCM_TRIDENT_SUPPORT 2632 if (soc_feature(unit, soc_feature_trill)) { 2633 if (!l3_flags_alloced) { 2634 alloc_sz += BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8); 2635 l3_flags_alloced = 1; 2636 } 2637 } 2638 #endif /* BCM_TRIDENT_SUPPORT */ 2639 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 2640 if (soc_feature(unit, soc_feature_vxlan) || 2641 soc_feature(unit, soc_feature_vxlan_lite)) { 2642 if (!l3_flags_alloced) { 2643 alloc_sz += BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8); 2644 l3_flags_alloced = 1; 2645 } 2646 } 2647 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 2648 2649 /* memory needed for multi level prot s/w state */ 2650 if (soc_feature(unit, soc_feature_l3) && 2651 (soc_feature(unit, soc_feature_hierarchical_protection))) { 2652 2653 alloc_sz += (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int)); 2654 } 2655 2656 #ifdef BCM_TRIDENT_SUPPORT 2657 if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) { 2658 if (!l3_flags_alloced) { 2659 alloc_sz += BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8); 2660 } 2661 } 2662 #endif /* BCM_TRIDENT_SUPPORT */ 2663 #if defined(BCM_RIOT_SUPPORT) 2664 if (soc_feature(unit, soc_feature_riot)) { 2665 bcm_td2p_l3_extended_required_scache_size_get(unit, &alloc_sz); 2666 } 2667 #endif /* BCM_RIOT_SUPPORT */ 2668 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 2669 if (soc_feature(unit, soc_feature_dgm)) { 2670 alloc_sz += sizeof(uint16) * 2671 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); 2672 } 2673 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2674 2675 /* Maximum VRF IDs on the device */ 2676 alloc_sz += sizeof(uint16); 2677 2678 #if defined(BCM_TRX_SUPPORT) 2679 if (soc_feature(unit, soc_feature_l3_ingress_interface) && 2680 soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) { 2681 alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 2682 } 2683 #endif 2684 2685 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 2686 alloc_sz, &l3_scache_ptr, 2687 BCM_WB_DEFAULT_VERSION, &recovered_ver); 2688 2689 if (BCM_SUCCESS(rv)) { 2690 /* Common to versions 1.1 and 1.0 */ 2691 sal_memcpy(egrmode, l3_scache_ptr, sizeof(*egrmode)); 2692 l3_scache_ptr += sizeof(*egrmode); 2693 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 2694 sal_memcpy(ingrmode, l3_scache_ptr, sizeof(*ingrmode)); 2695 l3_scache_ptr += sizeof(*ingrmode); 2696 } 2697 2698 if (recovered_ver >= BCM_WB_VERSION_1_1) { 2699 sal_memcpy(hostmode, l3_scache_ptr, sizeof(*hostmode)); 2700 l3_scache_ptr += sizeof(*hostmode); 2701 } 2702 2703 if (recovered_ver >= BCM_WB_VERSION_1_2) { 2704 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 2705 sal_memcpy(intfMapmode, l3_scache_ptr, sizeof(*intfMapmode)); 2706 l3_scache_ptr += sizeof(*intfMapmode); 2707 } 2708 } 2709 2710 if (recovered_ver >= BCM_WB_VERSION_1_3) { 2711 #ifdef BCM_TRIUMPH2_SUPPORT 2712 /* Recover max paths per ecmp group 2713 * for extended scache warmboot mode (level-2) only 2714 */ 2715 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 2716 BCM_XGS3_L3_MAX_ECMP_MODE(unit) && 2717 !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) { 2718 for(idx=0; idx<BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); idx++) { 2719 sal_memcpy(&(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[idx]), 2720 l3_scache_ptr, sizeof(uint16)); 2721 l3_scache_ptr += sizeof(uint16); 2722 } 2723 } 2724 #endif /* BCM_TRIUMPH2_SUPPORT */ 2725 2726 #ifdef BCM_TRIUMPH3_SUPPORT 2727 urpfEnable = 0; 2728 /* although no new scache information is synced, 2729 * the scache version was bumped to 1.5 here */ 2730 if (recovered_ver >= BCM_WB_VERSION_1_5) { 2731 rv = bcm_esw_switch_control_get(unit, 2732 bcmSwitchL3UrpfRouteEnable, 2733 &urpfEnable); 2734 if (BCM_SUCCESS(rv)) { 2735 SOC_CONTROL(unit)->l3_defip_urpf = urpfEnable; 2736 } 2737 } 2738 /* Recover ECMP DLB parameters */ 2739 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 2740 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined (BCM_TRIDENT3_SUPPORT) 2741 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 2742 BCM_IF_ERROR_RETURN 2743 (bcm_th2_ecmp_dlb_scache_recover(unit, &l3_scache_ptr)); 2744 } else 2745 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2746 { 2747 BCM_IF_ERROR_RETURN 2748 (bcm_tr3_ecmp_dlb_scache_recover(unit, &l3_scache_ptr)); 2749 } 2750 } 2751 #endif /* BCM_TRIUMPH3_SUPPORT */ 2752 2753 #ifdef BCM_TRIUMPH2_SUPPORT 2754 /* Recover ECMP defragmentation buffer parameters */ 2755 if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) || 2756 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 2757 if (!soc_feature(unit, soc_feature_l3_no_ecmp)) { 2758 BCM_IF_ERROR_RETURN 2759 (bcm_tr2_l3_ecmp_defragment_buffer_recover(unit, &l3_scache_ptr)); 2760 } 2761 } 2762 #endif /* BCM_TRIUMPH2_SUPPORT */ 2763 2764 } 2765 #ifdef BCM_TRIDENT2_SUPPORT 2766 /* 2767 * l3_ip4_options profile index information is recovered with 2768 * warmboot scache version 1.4 if recovered from sdk-6.3.1 2769 * whereas with 6.2.9 the information is not recovered. 2770 * New version 1.6 will support warmboot sync/recovery for 2771 * ip4 options profile hardware indexes... 2772 */ 2773 if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) { 2774 if ((recovered_ver >= BCM_WB_VERSION_1_6) || 2775 ((recovered_ver >= BCM_WB_VERSION_1_4) && 2776 (l3_ip4_options_recover == 1))) { 2777 BCM_IF_ERROR_RETURN 2778 (_bcm_td2_l3_ip4_options_recover(unit, &l3_scache_ptr)); 2779 } else { 2780 int ip4_options_scache_len; 2781 /* extra scache space size for recovering ip4 options 2782 * profile information in TD2 is 16 bytes */ 2783 BCM_IF_ERROR_RETURN( 2784 _bcm_td2_l3_ip4_options_profile_scache_len_get( 2785 unit, &ip4_options_scache_len)); 2786 additional_scache_sz += ip4_options_scache_len; 2787 } 2788 } 2789 #endif /* BCM_TRIDENT2_SUPPORT */ 2790 if (recovered_ver >= BCM_WB_VERSION_1_7) { 2791 sal_memcpy(ecmp_max_paths, l3_scache_ptr, sizeof(int)); 2792 l3_scache_ptr += sizeof(int); 2793 2794 } else { 2795 /* 2796 * ECMP max paths information used to be saved in the last 2797 * entry in L3_ECMP table before scache version 1.7 was created 2798 * 2799 * While upgrading to this version, read ecmp_max_paths info 2800 * from the hardware (Level 1). 2801 * 2802 * Further warmboots will use scache to sync/recover the info. 2803 */ 2804 ecmp_entry_t ecmp_entry; /* ECMP entry Buffer */ 2805 2806 /* Get maximum number of ECMP paths (stored in last entry) */ 2807 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ( 2808 unit, 2809 BCM_XGS3_L3_MEM(unit, ecmp), 2810 BCM_XGS3_L3_TBL_PTR(unit, ecmp)->idx_max, 2811 &ecmp_entry)); 2812 2813 *ecmp_max_paths = 2814 soc_L3_ECMPm_field32_get(unit, &ecmp_entry, NEXT_HOPf); 2815 2816 /* Allocate scache space for storing ecmp max paths */ 2817 additional_scache_sz += sizeof(int); 2818 } 2819 2820 if (recovered_ver >= BCM_WB_VERSION_1_8) { 2821 if (ecmp_refcnt && soc_feature(unit, soc_feature_l3) && 2822 !soc_feature(unit, soc_feature_l3_no_ecmp)) { 2823 alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 2824 ecmp_flags = sal_alloc(alloc_size, "ECMP flags"); 2825 if (ecmp_flags == NULL) { 2826 return SOC_E_MEMORY; 2827 } 2828 sal_memcpy(ecmp_flags, l3_scache_ptr, alloc_size); 2829 l3_scache_ptr += alloc_size; 2830 for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit); i++) { 2831 if (!SHR_BITGET(ecmp_flags, i)) { 2832 ecmp_refcnt[i] = 0; 2833 } 2834 } 2835 sal_free(ecmp_flags); 2836 } 2837 } else { 2838 /* Allocate scache space for storing ecmp ref counts */ 2839 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 2840 } 2841 2842 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\ 2843 defined(BCM_HURRICANE3_SUPPORT) 2844 if ((recovered_ver >= BCM_WB_VERSION_1_17) && 2845 soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) { 2846 skip_l3_ingress_intf_recover = TRUE; 2847 } 2848 if (skip_l3_ingress_intf_recover == FALSE) { 2849 if (recovered_ver >= BCM_WB_VERSION_1_9) { 2850 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 2851 sal_memcpy(BCM_XGS3_L3_ING_IF_INUSE(unit), l3_scache_ptr, 2852 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))); 2853 l3_scache_ptr += 2854 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 2855 } 2856 } else { 2857 additional_scache_sz += 2858 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 2859 } 2860 } 2861 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) || 2862 * defined(BCM_HURRICANE3_SUPPORT) 2863 */ 2864 2865 #ifdef BCM_TRIDENT2_SUPPORT 2866 if (recovered_ver >= BCM_WB_VERSION_1_9) { 2867 if (soc_feature(unit, soc_feature_l3)) { 2868 alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 2869 ecmp_flags = sal_alloc(alloc_size, "ECMP flags"); 2870 if (ecmp_flags == NULL) { 2871 return SOC_E_MEMORY; 2872 } 2873 sal_memcpy(ecmp_flags, l3_scache_ptr, alloc_size); 2874 l3_scache_ptr += alloc_size; 2875 for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit); i++) { 2876 if (SHR_BITGET(ecmp_flags, i)) { 2877 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, i, 2878 BCM_L3_ECMP_PATH_NO_SORTING); 2879 } else { 2880 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, i, 2881 BCM_L3_ECMP_PATH_NO_SORTING); 2882 } 2883 } 2884 sal_free(ecmp_flags); 2885 } 2886 } else { 2887 /* Allocate scache space for storing ecmp resorting flag */ 2888 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 2889 #ifdef BCM_TOMAHAWK_SUPPORT 2890 if (soc_feature(unit, soc_feature_l3) && 2891 soc_feature(unit, soc_feature_hierarchical_ecmp)) { 2892 /* ECMP Level 1 flags */ 2893 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)); 2894 /* ECMP Level 2 flags */ 2895 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)); 2896 } 2897 2898 #endif /* BCM_TOMAHAWK_SUPPORT */ 2899 } 2900 #endif /* BCM_TRIDENT2_SUPPORT */ 2901 if (recovered_ver >= BCM_WB_VERSION_1_10) { 2902 #ifdef BCM_TRIUMPH3_SUPPORT 2903 if (soc_feature(unit, soc_feature_l2gre)) { 2904 for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) { 2905 sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8)); 2906 BCM_XGS3_L3_ENT_FLAG( 2907 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag; 2908 l3_scache_ptr += sizeof(uint8); 2909 } 2910 l3_flags_recovered = 1; 2911 } 2912 #endif /* BCM_TRIUMPH3_SUPPORT */ 2913 #ifdef BCM_TRIDENT_SUPPORT 2914 if (soc_feature(unit, soc_feature_trill)) { 2915 if (!l3_flags_recovered) { 2916 for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) { 2917 sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8)); 2918 BCM_XGS3_L3_ENT_FLAG( 2919 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag; 2920 l3_scache_ptr += sizeof(uint8); 2921 } 2922 l3_flags_recovered = 1; 2923 } 2924 } 2925 #endif /* BCM_TRIDENT_SUPPORT */ 2926 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 2927 if (soc_feature(unit, soc_feature_vxlan) || 2928 soc_feature(unit, soc_feature_vxlan_lite)) { 2929 if (!l3_flags_recovered) { 2930 for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) { 2931 sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8)); 2932 BCM_XGS3_L3_ENT_FLAG( 2933 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag; 2934 l3_scache_ptr += sizeof(uint8); 2935 } 2936 l3_flags_recovered = 1; 2937 } 2938 } 2939 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 2940 } else { 2941 additional_scache_sz += 2942 BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8); 2943 } 2944 2945 if (recovered_ver >= BCM_WB_VERSION_1_11) { 2946 #ifdef BCM_TOMAHAWK_SUPPORT 2947 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 2948 alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)); 2949 ecmp_l1_flags = sal_alloc(alloc_size, "ECMP level1 flags"); 2950 if (ecmp_l1_flags == NULL) { 2951 return SOC_E_MEMORY; 2952 } 2953 ecmp_l2_flags = sal_alloc(alloc_size, "ECMP level2 flags"); 2954 if (ecmp_l2_flags == NULL) { 2955 sal_free(ecmp_l1_flags); 2956 return SOC_E_MEMORY; 2957 } 2958 sal_memcpy(ecmp_l1_flags, l3_scache_ptr, alloc_size); 2959 l3_scache_ptr += alloc_size; 2960 sal_memcpy(ecmp_l2_flags, l3_scache_ptr, alloc_size); 2961 l3_scache_ptr += alloc_size; 2962 for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) { 2963 if (SHR_BITGET(ecmp_l1_flags, i)) { 2964 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, i, 2965 BCM_L3_ECMP_OVERLAY); 2966 } else { 2967 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, i, 2968 BCM_L3_ECMP_OVERLAY); 2969 } 2970 if (SHR_BITGET(ecmp_l2_flags, i)) { 2971 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, i, 2972 BCM_L3_ECMP_UNDERLAY); 2973 } else { 2974 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, i, 2975 BCM_L3_ECMP_UNDERLAY); 2976 } 2977 } 2978 sal_free(ecmp_l1_flags); 2979 sal_free(ecmp_l2_flags); 2980 } 2981 2982 if (soc_feature(unit, soc_feature_l3) && 2983 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 2984 /* save interface count for each ecmp group */ 2985 BCM_IF_ERROR_RETURN 2986 (bcm_opt_l3_ecmp_rh_member_recover(unit, &l3_scache_ptr, 2987 *ecmp_max_paths)); 2988 } 2989 2990 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 2991 BCM_IF_ERROR_RETURN 2992 (bcm_th_l3_extended_view_reinit(unit, &l3_scache_ptr)); 2993 } 2994 #endif /* BCM_TOMAHAWK_SUPPORT */ 2995 } else { 2996 #ifdef BCM_TOMAHAWK_SUPPORT 2997 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 2998 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)); 2999 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)); 3000 } 3001 3002 if (soc_feature(unit, soc_feature_l3) && 3003 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 3004 /* save interface count for each ecmp group */ 3005 additional_scache_sz += sizeof(int); 3006 /* ECMP max paths info per RH group */ 3007 additional_scache_sz += sizeof(uint16) * BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); 3008 /* Group, member tuples */ 3009 additional_scache_sz += (RH_ECMP_MEMBER_TBL_MAX(unit) * (sizeof(int16) + sizeof(bcm_if_t))); 3010 } 3011 3012 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 3013 bcm_th_l3_extended_required_scache_size_get(unit, &additional_scache_sz); 3014 } 3015 #endif /* BCM_TOMAHAWK_SUPPORT */ 3016 3017 } /* End of BCM_WB_VERSION_1_11 */ 3018 if (recovered_ver >= BCM_WB_VERSION_1_12) { 3019 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 3020 sal_memcpy(BCM_XGS3_L3_NH_MULTI_COUNT(unit), l3_scache_ptr, 3021 BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int)); 3022 /* Till WB version 1_15, l3_scache_ptr was not incremented 3023 in sync as well as recover flow. So, this information 3024 was overwritten by other scache data. Now, it is being 3025 incremented, but to be backward-compatible, increment 3026 of l3_scache_ptr under version 1_16. 3027 */ 3028 if (recovered_ver >= BCM_WB_VERSION_1_16) { 3029 l3_scache_ptr += (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int)); 3030 } 3031 } 3032 } else { 3033 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 3034 additional_scache_sz += 3035 (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int)); 3036 } 3037 } /* End of BCM_WB_VERSION_1_12 */ 3038 #ifdef BCM_TRIDENT_SUPPORT 3039 if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) { 3040 if (!l3_flags_recovered) { 3041 for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) { 3042 sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8)); 3043 BCM_XGS3_L3_ENT_FLAG( 3044 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag; 3045 l3_scache_ptr += sizeof(uint8); 3046 } 3047 } 3048 } 3049 #endif /* BCM_TRIDENT_SUPPORT */ 3050 3051 #ifdef BCM_RIOT_SUPPORT 3052 if (soc_feature(unit, soc_feature_riot)) { 3053 if (recovered_ver >= BCM_WB_VERSION_1_13) { 3054 BCM_IF_ERROR_RETURN 3055 (bcm_td2p_l3_extended_view_reinit(unit, &l3_scache_ptr)); 3056 } else { 3057 bcm_td2p_l3_extended_required_scache_size_get(unit, &additional_scache_sz); 3058 } 3059 } 3060 #endif /* BCM_RIOT_SUPPORT */ 3061 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 3062 /* Recover alternate count per ecmp group */ 3063 if (soc_feature(unit, soc_feature_dgm)) { 3064 for (idx = 0; idx < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); idx++) { 3065 sal_memcpy(&(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[idx]), 3066 l3_scache_ptr, sizeof(uint16)); 3067 l3_scache_ptr += sizeof(uint16); 3068 } 3069 } 3070 #endif /* BCM_TOMAHAWK2_SUPPORT */ 3071 if (recovered_ver >= BCM_WB_VERSION_1_15) { 3072 sal_memcpy(&(SOC_VRF_MAX(unit)), l3_scache_ptr, sizeof(uint16)); 3073 l3_scache_ptr += sizeof(uint16); 3074 } else { 3075 additional_scache_sz += sizeof(uint16); 3076 } 3077 3078 if (!(BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL))) { 3079 if (recovered_ver >= BCM_WB_VERSION_1_16) { 3080 sal_memcpy(BCM_XGS3_L3_IF_ADD2ARL(unit), l3_scache_ptr, 3081 SHR_BITALLOCSIZE(soc_mem_index_count(unit, EGR_L3_INTFm))); 3082 l3_scache_ptr += SHR_BITALLOCSIZE(soc_mem_index_count(unit, EGR_L3_INTFm)); 3083 } else { 3084 additional_scache_sz += 3085 SHR_BITALLOCSIZE((soc_mem_index_count(unit, EGR_L3_INTFm))); 3086 } 3087 } 3088 3089 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 3090 if (soc_feature(unit, soc_feature_ecmp_dlb) && 3091 soc_feature(unit, soc_feature_ecmp_dlb_optimized) && 3092 !soc_feature(unit, soc_feature_th3_style_dlb)) { 3093 if (recovered_ver >= BCM_WB_VERSION_1_16) { 3094 BCM_IF_ERROR_RETURN( 3095 bcm_th2_ecmp_dlb_member_scache_recover(unit, 3096 &l3_scache_ptr)); 3097 } else { 3098 num_elements = soc_mem_index_count(unit, ING_L3_NEXT_HOPm); 3099 additional_scache_sz += SHR_BITALLOCSIZE(num_elements); 3100 } 3101 } 3102 #endif /* BCM_TOMAHAWK2_SUPPORT */ 3103 3104 #if defined(BCM_TRX_SUPPORT) 3105 if (soc_feature(unit, soc_feature_l3_ingress_interface) && 3106 soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) { 3107 if (recovered_ver >= BCM_WB_VERSION_1_17) { 3108 sal_memcpy(BCM_XGS3_L3_ING_IF_INUSE(unit), l3_scache_ptr, 3109 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))); 3110 l3_scache_ptr += 3111 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 3112 } else { 3113 additional_scache_sz += 3114 SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); 3115 } 3116 } 3117 #endif /* BCM_TRX_SUPPORT */ 3118 3119 /* scache realloc for further warm reboots */ 3120 if (additional_scache_sz > 0) { 3121 SOC_IF_ERROR_RETURN(soc_scache_realloc(unit, 3122 scache_handle, additional_scache_sz)); 3123 } 3124 3125 #ifdef BCM_TRIDENT_SUPPORT 3126 if (soc_feature(unit, soc_feature_trill) || 3127 soc_feature(unit, soc_feature_l2gre) || 3128 soc_feature(unit, soc_feature_vxlan)) { 3129 BCM_IF_ERROR_RETURN 3130 (_bcm_xgs3_trunk_nh_store_recover (unit)); 3131 } 3132 #endif /* BCM_TRIDENT_SUPPORT */ 3133 } 3134 3135 #if defined(BCM_SCORPION_SUPPORT) 3136 if (SOC_IS_SCORPION(unit)) { 3137 if ((dev_id == BCM56820_DEVICE_ID) && 3138 (recovered_ver < BCM_WB_VERSION_1_14)) { 3139 /* Reset the soc feature. */ 3140 SOC_FEATURE_SET(unit, soc_feature_l3_ecmp_2k_groups); 3141 } 3142 } 3143 #endif /* BCM_SCORPION_SUPPORT */ 3144 } 3145 3146 return BCM_E_NONE; 3147 } 3148 3149 /* 3150 * Function: 3151 * _bcm_tunnel_initiator_reinit 3152 * Purpose: 3153 * Tunnel initiator state and ref-count recovery. 3154 * Parameters: 3155 * unit - (IN) BCM device number. 3156 * Returns: 3157 * BCM_E_XXX 3158 */ 3159 int 3160 _bcm_tunnel_initiator_reinit(int unit) { 3161 3162 int i, idx; /* Table iteration index. */ 3163 int idx_min, idx_max; /* Maximum Table index. */ 3164 uint32 intf; 3165 tunnel_entry_t l3_tnl_entry; 3166 egr_ip_tunnel_entry_t egr_tnl_entry; 3167 soc_field_t fld = ENTRY_TYPEf; 3168 int local_idx_maxused = 0; 3169 3170 if (!SOC_MEM_IS_VALID(unit,L3_TUNNELm)) { 3171 /* if (SOC_IS_HURRICANE(unit)) */ 3172 return SOC_E_NONE; 3173 } 3174 3175 idx = soc_mem_index_min(unit, L3_TUNNELm); 3176 idx_max = soc_mem_index_max(unit, L3_TUNNELm); 3177 3178 for (idx = 0; idx <= idx_max; idx++) { 3179 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_TUNNELm, 3180 MEM_BLOCK_ANY, idx, &l3_tnl_entry)); 3181 if (!soc_L3_TUNNELm_field32_get(unit, &l3_tnl_entry, VALIDf)) { 3182 continue; 3183 } 3184 3185 intf = soc_L3_TUNNELm_field32_get(unit, &l3_tnl_entry, IINTFf); 3186 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 3187 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf); 3188 } 3189 } 3190 3191 /* Adjust ref counts */ 3192 idx_min = 1; 3193 idx_max = soc_mem_index_max(unit, EGR_IP_TUNNELm); 3194 3195 #if defined(BCM_FIREBOLT_SUPPORT) 3196 if (SOC_IS_FB_FX_HX(unit) || SOC_IS_BRADLEY(unit)) { 3197 fld = TUNNEL_TYPEf; 3198 } else if (SOC_IS_TRIDENT3X(unit)) { 3199 fld = DATA_TYPEf; 3200 } 3201 #endif 3202 3203 for (i = idx_min; i <= idx_max; i++) { 3204 SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_IP_TUNNELm, 3205 MEM_BLOCK_ANY, i, &egr_tnl_entry)); 3206 if (soc_EGR_IP_TUNNELm_field32_get(unit, &egr_tnl_entry, fld) != 0) { 3207 local_idx_maxused = i; 3208 } 3209 } 3210 3211 if (local_idx_maxused != 0) { 3212 BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused = local_idx_maxused; 3213 } else { 3214 BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused = idx_min; 3215 } 3216 return BCM_E_NONE; 3217 } 3218 3219 /* 3220 * Function: 3221 * _bcm_xgs3_l3_reinit 3222 * Purpose: 3223 * Recovers L3 sw state from hw tables 3224 * Parameters: 3225 * unit - SOC unit number 3226 * Returns: 3227 * BCM_E_XXX 3228 */ 3229 int 3230 _bcm_xgs3_l3_reinit(int unit) 3231 { 3232 int32 l3EgressMode = 0, l3IngressMode = 0, l3HostAddMode=0, l3IntfMapMode=0; 3233 int i, l3EcmpMaxPaths = 0; 3234 int *ecmp_refcnt = NULL; 3235 int alloc_size; 3236 int rv = BCM_E_NONE; 3237 3238 /* 3239 * Init L3 counters. 3240 */ 3241 BCM_XGS3_L3_CNTRS_RESET(unit); 3242 3243 /* 3244 * Init have table sizes & hw callbacks. 3245 */ 3246 BCM_IF_ERROR_RETURN(bcm_xgs3_l3_tables_init(unit)); 3247 3248 if (soc_property_get(unit, spn_L3_INTF_VLAN_SPLIT_EGRESS, 0)) { 3249 BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_L3_INTF_VLAN_SPLIT_EGRESS; 3250 } else { 3251 BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_L3_INTF_VLAN_SPLIT_EGRESS; 3252 } 3253 3254 /* 3255 * Get L3 mode(s) and recover from scache 3256 */ 3257 alloc_size = sizeof(int) * BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit); 3258 ecmp_refcnt = sal_alloc(alloc_size, "ECMP refcnt"); 3259 3260 for (i = 0; i < (BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); i++) { 3261 ecmp_refcnt[i] = 1; 3262 } 3263 rv = (_bcm_esw_l3_warmboot_recover(unit, 3264 &l3EgressMode, &l3IngressMode, &l3HostAddMode, 3265 &l3IntfMapMode, &l3EcmpMaxPaths, ecmp_refcnt)); 3266 if (BCM_FAILURE(rv)) { 3267 sal_free(ecmp_refcnt); 3268 return rv; 3269 } 3270 3271 #ifdef BCM_TRIUMPH_SUPPORT 3272 /* 3273 * Recover Ingress Mode 3274 */ 3275 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 3276 rv = (bcm_xgs3_l3_ingress_mode_set(unit, l3IngressMode)); 3277 if (BCM_FAILURE(rv)) { 3278 sal_free(ecmp_refcnt); 3279 return rv; 3280 } 3281 } 3282 #endif /* BCM_TRIUMPH_SUPPORT */ 3283 3284 /* 3285 * Recover Egress Mode 3286 */ 3287 rv = (bcm_xgs3_l3_egress_mode_set(unit, l3EgressMode)); 3288 if (BCM_FAILURE(rv)) { 3289 sal_free(ecmp_refcnt); 3290 return rv; 3291 } 3292 3293 /* 3294 * Recover Host Add Mode 3295 */ 3296 rv = (bcm_xgs3_l3_host_as_route_return_set(unit, l3HostAddMode)); 3297 if (BCM_FAILURE(rv)) { 3298 sal_free(ecmp_refcnt); 3299 return rv; 3300 } 3301 3302 #ifdef BCM_TRIUMPH_SUPPORT 3303 /* 3304 * Recover Intf Map mode 3305 */ 3306 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 3307 if (soc_feature(unit, soc_feature_l3_iif_under_4k)) { 3308 /* l3IntfMapMode can only be 1 for L3_IIFm size under 4K */ 3309 l3IntfMapMode = 1; 3310 } 3311 rv = (bcm_xgs3_l3_ingress_intf_map_set(unit, l3IntfMapMode)); 3312 if (BCM_FAILURE(rv)) { 3313 sal_free(ecmp_refcnt); 3314 return rv; 3315 } 3316 } 3317 #endif /* BCM_TRIUMPH_SUPPORT */ 3318 3319 /* 3320 * Recover L3 Intf sw state 3321 */ 3322 rv = (_bcm_xgs3_l3_intf_reinit(unit)); 3323 if (BCM_FAILURE(rv)) { 3324 sal_free(ecmp_refcnt); 3325 return rv; 3326 } 3327 3328 #ifdef BCM_TRIDENT2_SUPPORT 3329 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 3330 rv = (_bcm_xgs3_l3_ingress_intf_reinit(unit)); 3331 if (BCM_FAILURE(rv)) { 3332 sal_free(ecmp_refcnt); 3333 return rv; 3334 } 3335 } 3336 #endif 3337 /* 3338 * Recover next hop table. 3339 */ 3340 rv = (_bcm_xgs3_l3_nh_reinit(unit, l3EgressMode)); 3341 if (BCM_FAILURE(rv)) { 3342 sal_free(ecmp_refcnt); 3343 return rv; 3344 } 3345 3346 /* 3347 * Recover ecmp groups. 3348 */ 3349 rv = (_bcm_xgs3_l3_ecmp_reinit(unit, l3EcmpMaxPaths, ecmp_refcnt)); 3350 sal_free(ecmp_refcnt); 3351 if (BCM_FAILURE(rv)) { 3352 return rv; 3353 } 3354 3355 /* 3356 * Recover l3 entries(host) table. 3357 */ 3358 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_l3table_reinit(unit)); 3359 3360 /* 3361 * Recover defip table. 3362 */ 3363 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_defip_table_reinit(unit)); 3364 3365 /* 3366 * Recover VRF table. 3367 */ 3368 #if defined(BCM_TRIUMPH2_SUPPORT) 3369 if (soc_feature(unit, soc_feature_gport_service_counters)) { 3370 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_flexstat_recover(unit)); 3371 } 3372 #endif /* BCM_TRIUMPH2_SUPPORT */ 3373 3374 /* 3375 * Recover tunnel terminator table. 3376 */ 3377 if (!soc_feature(unit, soc_feature_no_tunnel)) { 3378 BCM_IF_ERROR_RETURN(_bcm_tunnel_initiator_reinit(unit)); 3379 BCM_IF_ERROR_RETURN(soc_tunnel_term_reinit(unit)); 3380 } else { 3381 if (soc_feature(unit, soc_feature_vxlan_lite)) { 3382 BCM_IF_ERROR_RETURN(_bcm_tunnel_initiator_reinit(unit)); 3383 } 3384 } 3385 3386 /* 3387 * Recover ESM host table state 3388 */ 3389 #if defined(BCM_TRIUMPH3_SUPPORT) 3390 if (SOC_IS_TRIUMPH3(unit) && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 3391 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_esm_host_state_recover(unit)); 3392 } 3393 #endif /* BCM_TRIUMPH3_SUPPORT */ 3394 3395 #if defined(BCM_TRX_SUPPORT) 3396 BCM_IF_ERROR_RETURN (_bcm_field_l3_recover_callback(unit)); 3397 #endif /* BCM_TRX_SUPPORT */ 3398 #if defined (BCM_KATANA_SUPPORT) || defined (BCM_TRIDENT_SUPPORT) \ 3399 || defined (BCM_TRIUMPH3_SUPPORT) || defined (BCM_GREYHOUND_SUPPORT) 3400 BCM_IF_ERROR_RETURN (bcmi_xgs3_fp_l3_egress_ref_count_update(unit)); 3401 #endif 3402 return (BCM_E_NONE); 3403 } 3404 #endif /* BCM_WARM_BOOT_SUPPORT */ 3405 3406 3407 /* 3408 * Function: 3409 * _bcm_xgs3_l3_table_init 3410 * Purpose: 3411 * Initialize L3 tables. 3412 * Parameters: 3413 * unit - (IN) SOC unit number. 3414 * Returns: 3415 * Number of L3 entries. 3416 */ 3417 STATIC int 3418 _bcm_xgs3_l3_table_init(int unit) 3419 { 3420 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 3421 defined(BCM_HAWKEYE_SUPPORT) 3422 if (soc_feature(unit, soc_feature_fp_based_routing)) { 3423 BCM_XGS3_L3_TBL_SIZE(unit) = BCM_XGS3_L3_RP_MAX_PREFIXES(unit); 3424 return (BCM_E_NONE); 3425 } 3426 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 3427 3428 /* Get table L3 host table size. */ 3429 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4))) { 3430 BCM_XGS3_L3_TBL_SIZE(unit) = 3431 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, v4)); 3432 } else { 3433 BCM_XGS3_L3_TBL_SIZE(unit) = 0; 3434 } 3435 3436 return (BCM_E_NONE); 3437 } 3438 3439 #ifdef BCM_FIREBOLT_SUPPORT 3440 /* 3441 * Function: 3442 * bcm_xgs3_l3_fbx_defip_init 3443 * Purpose: 3444 * Initialize L3 DEFIP table for fbx devices. 3445 * Parameters: 3446 * unit - (IN) SOC unit number. 3447 * Returns: 3448 * BCM_E_XXX 3449 */ 3450 int 3451 bcm_xgs3_l3_fbx_defip_init(int unit) 3452 { 3453 #if defined (BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) || \ 3454 defined (BCM_RAVEN_SUPPORT) 3455 uint32 reg_val; /* Buffer to store urpf register value.*/ 3456 3457 /* NOTE: URPF enable check must be done before */ 3458 /* specific route table initialization. */ 3459 3460 /* URPF support check. */ 3461 if (SOC_REG_IS_VALID(unit, L3_DEFIP_RPF_CONTROLr)) { 3462 BCM_IF_ERROR_RETURN(READ_L3_DEFIP_RPF_CONTROLr(unit, ®_val)); 3463 3464 if (soc_reg_field_get(unit, L3_DEFIP_RPF_CONTROLr, reg_val, 3465 DEFIP_RPF_ENABLEf)) { 3466 SOC_URPF_STATUS_SET(unit, TRUE); 3467 } else { 3468 SOC_URPF_STATUS_SET(unit, FALSE); 3469 } 3470 } 3471 #else /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */ 3472 SOC_URPF_STATUS_SET(unit, FALSE); 3473 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */ 3474 3475 #if defined(BCM_SCORPION_SUPPORT) 3476 if (SOC_IS_SCORPION(unit)) { 3477 BCM_IF_ERROR_RETURN(_bcm_sc_defip_init(unit)); 3478 } else 3479 #endif /* BCM_SCORPION_SUPPORT */ 3480 #ifdef BCM_KATANA2_SUPPORT 3481 if (SOC_IS_KATANA2(unit)) { 3482 BCM_IF_ERROR_RETURN(_bcm_kt2_l3_defip_init(unit)); 3483 } else 3484 #endif 3485 #ifdef BCM_TRIUMPH3_SUPPORT 3486 if (SOC_IS_TRIUMPH3(unit)) { 3487 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_init(unit)); 3488 } else 3489 #endif 3490 #if defined(BCM_TRIDENT2_SUPPORT) 3491 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 3492 BCM_IF_ERROR_RETURN(_bcm_l3_defip_init(unit)); 3493 #if defined(BCM_TOMAHAWK3_SUPPORT) 3494 /* Only config LPM_IP_CONTROLm here if ALPM is disabled. ALPM uses diff setting */ 3495 if (SOC_MEM_IS_VALID(unit, LPM_IP_CONTROLm) && !soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 3496 lpm_ip_control_entry_t entry; 3497 int tcam_pair_count = 0; 3498 sal_memset(&entry, 0, sizeof(entry)); 3499 3500 SOC_IF_ERROR_RETURN(soc_fb_lpm_tcam_pair_count_get(unit, &tcam_pair_count)); 3501 3502 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_0f, !tcam_pair_count); 3503 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_1f, !(tcam_pair_count / 2)); 3504 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_2f, !(tcam_pair_count / 3)); 3505 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_3f, !(tcam_pair_count / 4)); 3506 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_KEY_INPUT_SEL_BLOCK_0f, 0); 3507 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_KEY_INPUT_SEL_BLOCK_1f, 0); 3508 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_KEY_INPUT_SEL_BLOCK_0f, 0); 3509 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_KEY_INPUT_SEL_BLOCK_1f, 0); 3510 3511 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_DATABASE_SEL_BLOCK_0f, 4); 3512 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_DATABASE_SEL_BLOCK_1f, 4); 3513 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_DATABASE_SEL_BLOCK_0f, 4); 3514 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_DATABASE_SEL_BLOCK_1f, 4); 3515 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_0f, 0); 3516 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_1f, 0); 3517 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_2f, 0); 3518 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_3f, 0); 3519 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DB1_MODEf, 0); 3520 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DB0_MODEf, 1); 3521 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DATA0_SELf, 0); 3522 soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DATA1_SELf, 4); 3523 soc_mem_write(unit, LPM_IP_CONTROLm, COPYNO_ALL, 0, &entry); 3524 3525 } 3526 #endif 3527 } else 3528 #endif /* BCM_TRIDENT2_SUPPORT*/ 3529 #if defined(BCM_TRIUMPH_SUPPORT) 3530 if (SOC_IS_TR_VL(unit) && 3531 (!(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit)|| 3532 SOC_IS_GREYHOUND2(unit)))) { 3533 BCM_IF_ERROR_RETURN(_bcm_tr_defip_init(unit)); 3534 } else 3535 #endif /* BCM_TRIUMPH_SUPPORT*/ 3536 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 3537 defined(BCM_HAWKEYE_SUPPORT) 3538 if (soc_feature(unit, soc_feature_fp_based_routing)) { 3539 return (BCM_E_NONE); 3540 } else 3541 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 3542 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 3543 if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) || 3544 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) { 3545 BCM_IF_ERROR_RETURN(soc_hu2_lpm_init(unit)); 3546 } else 3547 #endif /*BCM_HURRICANE2_SUPPORT */ 3548 { 3549 /* Init prefixes offsets, hash/avl - lookup engine. */ 3550 BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit)); 3551 } 3552 return (BCM_E_NONE); 3553 } 3554 3555 /* 3556 * Function: 3557 * bcm_xgs3_l3_fbx_defip_deinit 3558 * Purpose: 3559 * De-initialize L3 DEFIP table for fbx devices. 3560 * Parameters: 3561 * unit - (IN) SOC unit number. 3562 * Returns: 3563 * BCM_E_XXX 3564 */ 3565 int 3566 bcm_xgs3_l3_fbx_defip_deinit(int unit) 3567 { 3568 3569 #if defined(BCM_SCORPION_SUPPORT) 3570 if (SOC_IS_SCORPION(unit)) { 3571 BCM_IF_ERROR_RETURN(_bcm_sc_defip_deinit(unit)); 3572 } else 3573 #endif /* BCM_SCORPION_SUPPORT */ 3574 #if defined(BCM_KATANA2_SUPPORT) 3575 if (SOC_IS_KATANA2(unit)) { 3576 BCM_IF_ERROR_RETURN(_bcm_kt2_l3_defip_deinit(unit)); 3577 } else 3578 #endif /* BCM_KATANA2_SUPPORT */ 3579 #if defined(BCM_TRIUMPH3_SUPPORT) 3580 if (SOC_IS_TRIUMPH3(unit)) { 3581 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_deinit(unit)); 3582 } else 3583 #endif /* BCM_TRIUMPH3_SUPPORT */ 3584 #if defined(BCM_TRIDENT2_SUPPORT) 3585 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 3586 BCM_IF_ERROR_RETURN(_bcm_l3_defip_deinit(unit)); 3587 } else 3588 #endif /* BCM_TRIDENT2_SUPPORT */ 3589 #if defined(BCM_TRIUMPH_SUPPORT) 3590 if (SOC_IS_TR_VL(unit)) { 3591 #if defined(BCM_HURRICANE3_SUPPORT) 3592 if (soc_feature(unit, soc_feature_miml_no_l3)) { 3593 return (BCM_E_NONE); 3594 } 3595 #endif /* BCM_HURRICANE3_SUPPORT */ 3596 BCM_IF_ERROR_RETURN(_bcm_tr_defip_deinit(unit)); 3597 } else 3598 #endif /* BCM_TRIUMPH_SUPPORT*/ 3599 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 3600 defined(BCM_HAWKEYE_SUPPORT) 3601 if (soc_feature(unit, soc_feature_fp_based_routing)) { 3602 return (BCM_E_NONE); 3603 } else 3604 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 3605 #if defined(BCM_HURRICANE2_SUPPORT) 3606 if (SOC_IS_HURRICANE2(unit)) { 3607 BCM_IF_ERROR_RETURN(soc_hu2_lpm_deinit(unit)); 3608 } else 3609 #endif /*BCM_HURRICANE2_SUPPORT */ 3610 { 3611 /* Init prefixes offsets, hash/avl - lookup engine. */ 3612 BCM_IF_ERROR_RETURN(soc_fb_lpm_deinit(unit)); 3613 } 3614 return (BCM_E_NONE); 3615 } 3616 #endif /* BCM_FIREBOLT_SUPPORT */ 3617 3618 /* 3619 * Function: 3620 * _bcm_xgs3_defip_table_init 3621 * Purpose: 3622 * Initialize L3 DEFIP tables. 3623 * Parameters: 3624 * unit - (IN) SOC unit number. 3625 * Returns: 3626 * Number of DEFIP entries. 3627 */ 3628 STATIC int 3629 _bcm_xgs3_defip_table_init(int unit) 3630 { 3631 int defip_config = 0; 3632 int ipv6_128_depth = 0; 3633 int l3_defip_pair_128_size = 0; 3634 soc_mem_t defip_pair_mem = L3_DEFIP_PAIR_128m; 3635 3636 #ifdef BCM_TRIDENT2PLUS_SUPPORT 3637 uint16 dev_id; 3638 uint8 rev_id; 3639 soc_cm_get_id_otp(unit, &dev_id, &rev_id); 3640 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 3641 3642 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 3643 defined(BCM_HAWKEYE_SUPPORT) 3644 if (soc_feature(unit, soc_feature_fp_based_routing)) { 3645 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 3646 BCM_XGS3_L3_RP_MAX_PREFIXES(unit); 3647 return (BCM_E_NONE); 3648 } 3649 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 3650 /* Get table size. */ 3651 3652 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_PAIR_LEVEL1m)) { 3653 defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m; 3654 } 3655 3656 if (soc_feature(unit, soc_feature_l3_shared_defip_table)) { 3657 #ifdef BCM_WARM_BOOT_SUPPORT 3658 if (!SOC_WARM_BOOT(unit)) { 3659 #endif 3660 if (SOC_MEM_IS_VALID(unit, defip_pair_mem)) { 3661 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || 3662 SOC_IS_HELIX4(unit) || SOC_IS_TRIDENT3X(unit) || 3663 soc_feature(unit, soc_feature_l3_reduced_defip_table)) { 3664 defip_config = soc_property_get(unit, 3665 spn_IPV6_LPM_128B_ENABLE, 1); 3666 if (!defip_config && 3667 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) && 3668 soc_feature(unit, soc_feature_alpm)) { 3669 ipv6_128_depth = 0; 3670 } else { 3671 int num_ipv6_def; 3672 3673 /* Pair half the tcams by default when ipv6_128b is enabled */ 3674 num_ipv6_def = 3675 ((SOC_CONTROL(unit)->l3_defip_max_tcams/2) * SOC_CONTROL(unit)->l3_defip_tcam_size) / 2; 3676 #ifdef BCM_TRIDENT2PLUS_SUPPORT 3677 if (dev_id == BCM56832_DEVICE_ID) { 3678 num_ipv6_def = 512; 3679 } else 3680 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 3681 if (defip_config && 3682 soc_feature(unit, soc_feature_l3_reduced_defip_table)) { 3683 num_ipv6_def = 2048; 3684 } 3685 ipv6_128_depth = soc_property_get(unit, 3686 spn_NUM_IPV6_LPM_128B_ENTRIES, 3687 (defip_config ? num_ipv6_def : 0)); 3688 } 3689 ipv6_128_depth = ipv6_128_depth + (ipv6_128_depth % 2); 3690 #ifdef ALPM_ENABLE 3691 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 3692 if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit)) 3693 && (soc_alpm_cmn_mode_get(unit) == SOC_ALPM_MODE_PARALLEL || 3694 soc_alpm_cmn_mode_get(unit) == SOC_ALPM_MODE_TCAM_ALPM)) { 3695 ipv6_128_depth = (ipv6_128_depth + 3) / 4 * 4; 3696 } else 3697 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_APACHE_SUPPORT */ 3698 { 3699 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT) 3700 if (soc_trident2_alpm_mode_get(unit) == 1) { 3701 ipv6_128_depth = (ipv6_128_depth + 3) / 4 * 4; 3702 } 3703 #endif /* BCM_TRIDENT2_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */ 3704 } 3705 #endif /* ALPM_ENABLE */ 3706 3707 if (SOC_CONTROL(unit)->tcam_protect_write) { 3708 ipv6_128_depth = (ipv6_128_depth + 3) / 4 * 4; 3709 } 3710 l3_defip_pair_128_size = soc_mem_index_count(unit, 3711 defip_pair_mem); 3712 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3713 ipv6_128_depth = 0; 3714 } 3715 if (l3_defip_pair_128_size != ipv6_128_depth) { 3716 /* Resize the tables */ 3717 BCM_IF_ERROR_RETURN(_bcm_xgs3_route_tables_resize(unit, 3718 ipv6_128_depth)); 3719 } 3720 } 3721 } 3722 #ifdef BCM_WARM_BOOT_SUPPORT 3723 } 3724 #endif 3725 } 3726 3727 #ifdef BCM_HURRICANE3_SUPPORT 3728 if (soc_feature(unit, soc_feature_miml_no_l3)) { 3729 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 0; 3730 return (BCM_E_NONE); 3731 } 3732 #endif /* BCM_HURRICANE3_SUPPORT */ 3733 3734 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 3735 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)); 3736 #ifdef BCM_FIREBOLT_SUPPORT 3737 if (SOC_IS_FBX(unit)) { 3738 BCM_IF_ERROR_RETURN(bcm_xgs3_l3_fbx_defip_init(unit)); 3739 } 3740 #endif /* BCM_FIREBOLT_SUPPORT */ 3741 3742 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 3743 if (soc_feature(unit, soc_feature_ipmc_defip)) { 3744 BCM_IF_ERROR_RETURN(bcm_td2p_l3_defip_init(unit)); 3745 } 3746 #endif 3747 3748 return (BCM_E_NONE); 3749 } 3750 3751 /* 3752 * Function: 3753 * _bcm_fb_mem_ip6_defip_lwr_set 3754 * Purpose: 3755 * Set an IP6 address field in L3_DEFIPm at index n 3756 * Parameters: 3757 * unit - (IN) SOC unit number; 3758 * lpm_key - (OUT) Buffer to fill. 3759 * lpm_cfg - (IN) Route information. 3760 * Note: 3761 * See soc_mem_ip6_addr_set() 3762 */ 3763 STATIC void 3764 _bcm_fb_mem_ip6_defip_lwr_set(int unit, void *lpm_key, _bcm_defip_cfg_t *lpm_cfg) 3765 { 3766 uint8 *ip6; /* Ip6 address. */ 3767 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 3768 uint32 ip6_word; /* Temp storage. */ 3769 int idx; 3770 3771 /* Just to keep variable name short. */ 3772 ip6 = lpm_cfg->defip_ip6_addr; 3773 3774 /* Create mask from prefix length. */ 3775 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 3776 3777 /* Apply subnet mask */ 3778 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 3779 if (idx < BCM_IP6_ADDRLEN) { 3780 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 3781 } 3782 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 3783 ip6[idx] = 0; /* Reset rest of bytes. */ 3784 } 3785 3786 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 3787 uint32 _key_data[2] = {0, 0}; 3788 3789 ip6_word = ((ip6[8] << 24) | (ip6[9] << 16) | (ip6[10] << 8) | (ip6[11])); 3790 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3791 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY1f, _key_data); 3792 3793 ip6_word = ((ip6[12] << 24) | (ip6[13] << 16) | (ip6[14] << 8) | (ip6[15])); 3794 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3795 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY0f, _key_data); 3796 3797 ip6_word = ((mask[8] << 24) | (mask[9] << 16) | (mask[10] << 8) | 3798 (mask[11])); 3799 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3800 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK1f, _key_data); 3801 3802 ip6_word = ((mask[12] << 24) | (mask[13] << 16) | (mask[14] << 8) | 3803 (mask[15])); 3804 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3805 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK0f, _key_data); 3806 3807 return; 3808 } 3809 3810 ip6_word = ((ip6[8] << 24) | (ip6[9] << 16) | (ip6[10] << 8) | (ip6[11])); 3811 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word); 3812 3813 ip6_word = ((ip6[12] << 24) | (ip6[13] << 16) | (ip6[14] << 8) | (ip6[15])); 3814 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word); 3815 3816 ip6_word = ((mask[8] << 24) | (mask[9] << 16) | (mask[10] << 8) | 3817 (mask[11])); 3818 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f, 3819 (void *)&ip6_word); 3820 3821 ip6_word = ((mask[12] << 24) | (mask[13] << 16) | (mask[14] << 8) | 3822 (mask[15])); 3823 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f, 3824 (void *)&ip6_word); 3825 } 3826 3827 /* 3828 * Function: 3829 * _bcm_fb_mem_ip6_defip_upr_set 3830 * Purpose: 3831 * Set an IP6 address field in L3_DEFIPm at index n + 1024 3832 * Parameters: 3833 * unit - (IN) SOC unit number; 3834 * lpm_key - (OUT) Buffer to fill. 3835 * lpm_cfg - (IN) Route information. 3836 * Note: 3837 * See soc_mem_ip6_addr_set() 3838 */ 3839 STATIC void 3840 _bcm_fb_mem_ip6_defip_upr_set(int unit, void *lpm_key, 3841 _bcm_defip_cfg_t *lpm_cfg) 3842 { 3843 uint8 *ip6; /* Ip6 address. */ 3844 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 3845 uint32 ip6_word; /* Temp storage. */ 3846 3847 /* Just to keep variable name short. */ 3848 ip6 = lpm_cfg->defip_ip6_addr; 3849 3850 /* Create mask from prefix length. */ 3851 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 3852 3853 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 3854 uint32 _key_data[2] = {0}; 3855 3856 ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 3857 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3858 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 3859 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 3860 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY1f, _key_data); 3861 3862 ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 3863 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3864 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 3865 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 3866 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY0f, _key_data); 3867 3868 ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | 3869 (mask[3])); 3870 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3871 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 3872 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 3873 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK1f, _key_data); 3874 3875 ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | 3876 (mask[7])); 3877 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 3878 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 3879 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 3880 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK0f, _key_data); 3881 3882 return; 3883 } 3884 3885 ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 3886 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word); 3887 3888 ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 3889 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word); 3890 3891 ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | 3892 (mask[3])); 3893 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f, 3894 (void *)&ip6_word); 3895 3896 ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | 3897 (mask[7])); 3898 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f, 3899 (void *)&ip6_word); 3900 } 3901 3902 /* 3903 * Function: 3904 * _bcm_fb_mem_ip6_128b_defip_get 3905 * Purpose: 3906 * Set an IP6 address field in L3_DEFIPm 3907 * Note: 3908 * See soc_mem_ip6_addr_set() 3909 */ 3910 STATIC void 3911 _bcm_fb_mem_ip6_128b_defip_get(int unit, const void *lpm_key, 3912 const void *lpm_key_upr, _bcm_defip_cfg_t *lpm_cfg) 3913 { 3914 uint8 *ip6; /* Ip6 address. */ 3915 uint8 mask[BCM_IP6_ADDRLEN] = {0}; /* Subnet mask. */ 3916 uint32 ip6_word; /* Temp storage. */ 3917 3918 /* Just to keep variable name short. */ 3919 ip6 = lpm_cfg->defip_ip6_addr; 3920 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 3921 3922 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 3923 uint32 _key_data[2] = {0, 0}; 3924 3925 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, KEY1f, _key_data); 3926 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3927 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 3928 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 3929 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 3930 ip6[3] = (uint8) (ip6_word & 0xff); 3931 3932 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, KEY0f, _key_data); 3933 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3934 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 3935 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 3936 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 3937 ip6[7] = (uint8) (ip6_word & 0xff); 3938 3939 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY1f, _key_data); 3940 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3941 ip6[8] = (uint8) ((ip6_word >> 24) & 0xff); 3942 ip6[9] = (uint8) ((ip6_word >> 16) & 0xff); 3943 ip6[10] = (uint8) ((ip6_word >> 8) & 0xff); 3944 ip6[11] = (uint8) (ip6_word & 0xff); 3945 3946 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY0f, _key_data); 3947 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3948 ip6[12] = (uint8) ((ip6_word >> 24) & 0xff); 3949 ip6[13] = (uint8) ((ip6_word >> 16) & 0xff); 3950 ip6[14] = (uint8) ((ip6_word >> 8) & 0xff); 3951 ip6[15] = (uint8) (ip6_word & 0xff); 3952 3953 3954 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, MASK1f, _key_data); 3955 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3956 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 3957 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 3958 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 3959 mask[3] = (uint8) (ip6_word & 0xff); 3960 3961 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, MASK0f, _key_data); 3962 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3963 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 3964 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 3965 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 3966 mask[7] = (uint8) (ip6_word & 0xff); 3967 3968 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK1f, _key_data); 3969 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3970 mask[8] = (uint8) ((ip6_word >> 24) & 0xff); 3971 mask[9] = (uint8) ((ip6_word >> 16) & 0xff); 3972 mask[10] = (uint8) ((ip6_word >> 8) & 0xff); 3973 mask[11] = (uint8) (ip6_word & 0xff); 3974 3975 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK0f, _key_data); 3976 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 3977 mask[12] = (uint8) ((ip6_word >> 24) & 0xff); 3978 mask[13] = (uint8) ((ip6_word >> 16) & 0xff); 3979 mask[14] = (uint8) ((ip6_word >> 8) & 0xff); 3980 mask[15] = (uint8) (ip6_word & 0xff); 3981 3982 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 3983 return; 3984 } 3985 3986 soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR1f, &ip6_word); 3987 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 3988 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 3989 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 3990 ip6[3] = (uint8) (ip6_word & 0xff); 3991 3992 soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR0f, &ip6_word); 3993 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 3994 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 3995 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 3996 ip6[7] = (uint8) (ip6_word & 0xff); 3997 3998 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word); 3999 ip6[8] = (uint8) ((ip6_word >> 24) & 0xff); 4000 ip6[9] = (uint8) ((ip6_word >> 16) & 0xff); 4001 ip6[10] = (uint8) ((ip6_word >> 8) & 0xff); 4002 ip6[11] = (uint8) (ip6_word & 0xff); 4003 4004 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word); 4005 ip6[12] = (uint8) ((ip6_word >> 24) & 0xff); 4006 ip6[13] = (uint8) ((ip6_word >> 16) & 0xff); 4007 ip6[14] = (uint8) ((ip6_word >> 8) & 0xff); 4008 ip6[15] = (uint8) (ip6_word & 0xff); 4009 4010 soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR_MASK1f, &ip6_word); 4011 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 4012 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 4013 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 4014 mask[3] = (uint8) (ip6_word & 0xff); 4015 4016 soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR_MASK0f, &ip6_word); 4017 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 4018 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 4019 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 4020 mask[7] = (uint8) (ip6_word & 0xff); 4021 4022 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word); 4023 mask[8] = (uint8) ((ip6_word >> 24) & 0xff); 4024 mask[9] = (uint8) ((ip6_word >> 16) & 0xff); 4025 mask[10] = (uint8) ((ip6_word >> 8) & 0xff); 4026 mask[11] = (uint8) (ip6_word & 0xff); 4027 4028 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word); 4029 mask[12] = (uint8) ((ip6_word >> 24) & 0xff); 4030 mask[13] = (uint8) ((ip6_word >> 16) & 0xff); 4031 mask[14] = (uint8) ((ip6_word >> 8) & 0xff); 4032 mask[15] = (uint8) (ip6_word & 0xff); 4033 4034 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 4035 } 4036 4037 4038 /* 4039 * Function: 4040 * _bcm_fb_lpm_upr_ent_init 4041 * Purpose: 4042 * Service routine used to initialize lkup key for lpm entry. 4043 * Parameters: 4044 * unit - (IN)SOC unit number. 4045 * lpm_cfg - (IN)Prefix info. 4046 * lpm_entry - (OUT)Hw buffer to fill. 4047 * Returns: 4048 * BCM_E_XXX 4049 */ 4050 STATIC int 4051 _bcm_fb_lpm_upr_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 4052 uint32 *lpm_entry) 4053 { 4054 int vrf_id; 4055 int vrf_mask; 4056 4057 /* Extract entry vrf id & vrf mask. */ 4058 /*for Hurricane it should return default value 4059 for vrf id*/ 4060 BCM_IF_ERROR_RETURN 4061 (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask)); 4062 4063 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 4064 _bcm_th3_lpm_key_init(unit, lpm_cfg, lpm_entry); 4065 4066 /* Set prefix ip address & mask. */ 4067 _bcm_fb_mem_ip6_defip_upr_set(unit, lpm_entry, lpm_cfg); 4068 4069 /* Set valid bit. */ 4070 soc_mem_field32_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, VALID0f, 1); 4071 /* Set second part valid bit. */ 4072 soc_mem_field32_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, VALID1f, 1); 4073 4074 return BCM_E_NONE; 4075 } 4076 4077 /* Set prefix ip address & mask. */ 4078 _bcm_fb_mem_ip6_defip_upr_set(unit, lpm_entry, lpm_cfg); 4079 4080 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_0f, vrf_id); 4081 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK0f, vrf_mask); 4082 /* Set valid bit. */ 4083 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID0f, 1); 4084 /* Set second part valid bit. */ 4085 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 1); 4086 4087 /* Set mode to ipv6 */ 4088 soc_L3_DEFIPm_field32_set(unit, lpm_entry, defip_mode0_bit[unit], 3); 4089 soc_L3_DEFIPm_field32_set(unit, lpm_entry, defip_mode1_bit[unit], 3); 4090 4091 /* Set Virtual Router id if supported. */ 4092 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_1f)){ 4093 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_1f, vrf_id); 4094 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK1f, vrf_mask); 4095 } 4096 #if defined(BCM_TRX_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 4097 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) { 4098 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask0_bit[unit], 4099 (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) - 1); 4100 } 4101 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) { 4102 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask1_bit[unit], 4103 (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) - 1); 4104 } 4105 #endif /* BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */ 4106 4107 #if defined(BCM_TRX_SUPPORT) 4108 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) { 4109 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 4110 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), 4111 lpm_entry, GLOBAL_ROUTE0f, 0x1); 4112 } 4113 } 4114 #endif /* BCM_TRX_SUPPORT */ 4115 4116 return (BCM_E_NONE); 4117 } 4118 4119 int 4120 _bcm_fb_get_largest_prefix(int u, int ipv6, void *e, 4121 int *index, int *pfx_len, int* count) 4122 { 4123 return soc_fb_get_largest_prefix(u, ipv6, e, index, pfx_len, count); 4124 } 4125 4126 int _bcm_fb_lpm128_get_smallest_movable_prefix(int u, int ipv6, 4127 void *e, void *eupr, int *index, 4128 int *pfx_len, int*count) 4129 { 4130 return soc_fb_lpm128_get_smallest_movable_prefix(u, ipv6, e, eupr, index, 4131 pfx_len, count); 4132 } 4133 4134 /* 4135 * Function: 4136 * _bcm_fb_lpm128_ent_get_key 4137 * Purpose: 4138 * Parse entry key from DEFIP table. 4139 * Parameters: 4140 * unit - (IN)SOC unit number. 4141 * lpm_cfg - (OUT)Buffer to fill defip information. 4142 * lpm_entry - (IN) Buffer read from hw. 4143 * lpm_entry_upr - (IN) Buffer read from hw. 4144 * Returns: 4145 * void 4146 */ 4147 STATIC void 4148 _bcm_fb_lpm128_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg, 4149 uint32 *lpm_entry, uint32 *lpm_entry_upr) 4150 { 4151 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 4152 4153 /* Set prefix ip address & mask. */ 4154 if (ipv6) { 4155 _bcm_fb_mem_ip6_128b_defip_get(unit, lpm_entry, lpm_entry_upr, lpm_cfg); 4156 } 4157 4158 /* Get Virtual Router id */ 4159 soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf); 4160 4161 return; 4162 } 4163 4164 /* 4165 * Function: 4166 * _bcm_fb_lpm128_defip_cfg_get 4167 * Purpose: 4168 * Parse entry key from DEFIP table. 4169 * Parameters: 4170 * unit - (IN)SOC unit number. 4171 * lpm_entry - (IN) Buffer read from hw. 4172 * lpm_entry_upr - (IN) Buffer read from hw. 4173 * lpm_cfg - (OUT)Buffer to fill defip information. 4174 * nh_ecmp_idx - (OUT) ecmp nh_index id 4175 * Returns: 4176 * void 4177 */ 4178 int 4179 _bcm_fb_lpm128_defip_cfg_get(int unit, void *defip_lpm_entry, 4180 void *defip_lpm_entry_upr, 4181 _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 4182 { 4183 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; 4184 uint32 lpm_entry_upr[SOC_MAX_MEM_WORDS]; 4185 int b128 = 0; 4186 4187 if (lpm_cfg == NULL || defip_lpm_entry == NULL) { 4188 return BCM_E_PARAM; 4189 } 4190 4191 sal_memcpy(lpm_entry, defip_lpm_entry, 4192 BCM_XGS3_L3_ENT_SZ(unit, defip)); 4193 sal_memcpy(lpm_entry_upr, defip_lpm_entry_upr, 4194 BCM_XGS3_L3_ENT_SZ(unit, defip)); 4195 4196 /* Parse the entry. */ 4197 BCM_IF_ERROR_RETURN( 4198 _bcm_fb_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, 4199 (uint32 *)lpm_entry, &b128)); 4200 if (!b128) { 4201 return SOC_E_PARAM; 4202 } 4203 4204 _bcm_fb_lpm128_ent_get_key(unit, lpm_cfg, lpm_entry, lpm_entry_upr); 4205 lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX; 4206 return SOC_E_NONE; 4207 } 4208 4209 /* 4210 * Function: 4211 * _bcm_fb_mem_ip6_defip_set 4212 * Purpose: 4213 * Set an IP6 address field in L3_DEFIPm 4214 * Parameters: 4215 * unit - (IN) SOC unit number; 4216 * lpm_key - (OUT) Buffer to fill. 4217 * lpm_cfg - (IN) Route information. 4218 * Note: 4219 * See soc_mem_ip6_addr_set() 4220 */ 4221 STATIC void 4222 _bcm_fb_mem_ip6_defip_set(int unit, void *lpm_key, _bcm_defip_cfg_t *lpm_cfg) 4223 { 4224 uint8 *ip6; /* Ip6 address. */ 4225 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 4226 uint32 ip6_word; /* Temp storage. */ 4227 int idx; /* Iteration index . */ 4228 4229 /* Just to keep variable name short. */ 4230 ip6 = lpm_cfg->defip_ip6_addr; 4231 4232 /* Create mask from prefix length. */ 4233 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 4234 4235 /* Apply subnet mask */ 4236 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 4237 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 4238 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 4239 ip6[idx] = 0; /* Reset rest of bytes. */ 4240 } 4241 4242 4243 ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 4244 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word); 4245 4246 ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 4247 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word); 4248 4249 ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3])); 4250 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f, 4251 (void *)&ip6_word); 4252 4253 ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7])); 4254 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f, 4255 (void *)&ip6_word); 4256 } 4257 4258 int 4259 _bcm_th3_lpm_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 4260 uint32 *lpm_entry) 4261 { 4262 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 4263 uint32 _key_data[2] = {0,0}; 4264 uint8 *ip6; /* Ip6 address. */ 4265 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 4266 uint32 ip6_word; /* Temp storage. */ 4267 int idx; 4268 4269 int mode = 1; 4270 int vrf_id; 4271 int vrf_mask; 4272 bcm_ip_t ip4_mask; 4273 ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len); 4274 4275 BCM_IF_ERROR_RETURN 4276 (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask)); 4277 4278 if (!ipv6) { 4279 mode = 0; 4280 } else if (lpm_cfg->defip_sub_len > 64 || 4281 lpm_cfg->defip_flags_high & BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR) { 4282 mode = 3; 4283 } else { 4284 mode = 1; 4285 } 4286 4287 /* Just to keep variable name short. */ 4288 ip6 = lpm_cfg->defip_ip6_addr; 4289 4290 /* Create mask from prefix length. */ 4291 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 4292 4293 /* Apply subnet mask */ 4294 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 4295 if (idx < BCM_IP6_ADDRLEN) { 4296 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 4297 } 4298 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 4299 ip6[idx] = 0; /* Reset rest of bytes. */ 4300 } 4301 4302 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, lpm_cfg->defip_ip_addr); 4303 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, mode); 4304 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id); 4305 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, (ipv6 ? 1 : 0)); 4306 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data); 4307 4308 _key_data[0] = _key_data[1] = 0; 4309 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask); 4310 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip4_mask); 4311 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 4312 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4313 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data); 4314 if (ipv6) { 4315 /* Apply subnet mask */ 4316 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 4317 if (idx < BCM_IP6_ADDRLEN) { 4318 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 4319 } 4320 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 4321 ip6[idx] = 0; /* Reset rest of bytes. */ 4322 } 4323 4324 _key_data[0] = _key_data[1] = 0; 4325 4326 if (mode == 3) { 4327 ip6_word = ((ip6[8] << 24) | (ip6[9] << 16) | (ip6[10] << 8) | (ip6[11])); 4328 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4329 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id); 4330 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 4331 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4332 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY1f, _key_data); 4333 4334 ip6_word = ((ip6[12] << 24) | (ip6[13] << 16) | (ip6[14] << 8) | (ip6[15])); 4335 _key_data[0] = _key_data[1] = 0; 4336 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4337 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 4338 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4339 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id); 4340 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data); 4341 4342 ip6_word = ((mask[8] << 24) | (mask[9] << 16) | (mask[10] << 8) | 4343 (mask[11])); 4344 _key_data[0] = _key_data[1] = 0; 4345 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4346 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask); 4347 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 4348 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4349 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK1f, _key_data); 4350 4351 ip6_word = ((mask[12] << 24) | (mask[13] << 16) | (mask[14] << 8) | 4352 (mask[15])); 4353 _key_data[0] = _key_data[1] = 0; 4354 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4355 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3)); 4356 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4357 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask); 4358 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data); 4359 4360 } else { 4361 4362 ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 4363 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4364 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id); 4365 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1)); 4366 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4367 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY1f, _key_data); 4368 4369 ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 4370 _key_data[0] = _key_data[1] = 0; 4371 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4372 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id); 4373 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1)); 4374 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4375 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data); 4376 4377 ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | 4378 (mask[3])); 4379 _key_data[0] = _key_data[1] = 0; 4380 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4381 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask); 4382 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1)); 4383 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4384 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK1f, _key_data); 4385 4386 ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | 4387 (mask[7])); 4388 _key_data[0] = _key_data[1] = 0; 4389 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word); 4390 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask); 4391 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1)); 4392 soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1); 4393 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data); 4394 } 4395 } 4396 return (BCM_E_NONE); 4397 } 4398 4399 /* 4400 * Function: 4401 * _bcm_fb_lpm_ent_init 4402 * Purpose: 4403 * Service routine used to initialize lkup key for lpm entry. 4404 * Parameters: 4405 * unit - (IN)SOC unit number. 4406 * lpm_cfg - (IN)Prefix info. 4407 * lpm_entry - (OUT)Hw buffer to fill. 4408 * Returns: 4409 * BCM_E_XXX 4410 */ 4411 int 4412 _bcm_fb_lpm_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 4413 uint32 *lpm_entry) 4414 { 4415 bcm_ip_t ip4_mask; 4416 int vrf_id; 4417 int vrf_mask; 4418 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 4419 int ipmc = lpm_cfg->defip_flags & BCM_L3_IPMC; 4420 int pfx_len = lpm_cfg->defip_sub_len; 4421 int mode = 1; 4422 4423 #ifdef BCM_TRIDENT3_SUPPORT 4424 if (soc_feature(unit, soc_feature_flex_flow) && 4425 lpm_cfg->defip_flow_handle != 0) { 4426 return _bcm_td3_lpm_flex_ent_init(unit, lpm_cfg, lpm_entry); 4427 } 4428 #endif 4429 4430 /* Extract entry vrf id & vrf mask. */ 4431 /*for Hurricane it should return default value 4432 for vrf id*/ 4433 BCM_IF_ERROR_RETURN 4434 (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask)); 4435 4436 /* Set mode */ 4437 if (!ipv6) { 4438 mode = 0; 4439 } else if (pfx_len > 64 || 4440 lpm_cfg->defip_flags_high & BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR) { 4441 mode = 3; 4442 } else { 4443 mode = 1; 4444 } 4445 4446 /* Set prefix ip address & mask. */ 4447 if (ipv6) { 4448 if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 4449 if (mode == 3) { 4450 _bcm_fb_mem_ip6_defip_lwr_set(unit, lpm_entry, lpm_cfg); 4451 } else { 4452 _bcm_fb_mem_ip6_defip_set(unit, lpm_entry, lpm_cfg); 4453 } 4454 } 4455 } else { 4456 ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len); 4457 /* Apply subnet mask. */ 4458 lpm_cfg->defip_ip_addr &= ip4_mask; 4459 4460 if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 4461 /* Set address to the buffer. */ 4462 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, IP_ADDR0f, 4463 lpm_cfg->defip_ip_addr); 4464 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, IP_ADDR_MASK0f, ip4_mask); 4465 } 4466 } 4467 4468 4469 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 4470 uint32 fmte[10]; 4471 _bcm_th3_lpm_key_init(unit, lpm_cfg, lpm_entry); 4472 sal_memset(fmte, 0, sizeof(fmte)); 4473 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 4474 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, 4475 SUB_DB_PRIORITYf, 2); 4476 } else if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 4477 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, 4478 SUB_DB_PRIORITYf, 0); 4479 } else { 4480 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, 4481 SUB_DB_PRIORITYf, 1); 4482 } 4483 soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, 4484 FIXED_DATA0f, fmte); 4485 } else { 4486 if (ipv6) { 4487 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 4488 defined(BCM_TRX_SUPPORT) 4489 /* Set Virtual Router id if supported. */ 4490 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_1f)){ 4491 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_1f, vrf_id); 4492 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_MASK1f, vrf_mask); 4493 } 4494 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 4495 } 4496 } 4497 4498 /* Set valid bit. */ 4499 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID0f, 1); 4500 if (ipv6) { 4501 /* Set second part valid bit. */ 4502 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID1f, 1); 4503 } 4504 4505 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 4506 defined(BCM_TRX_SUPPORT) 4507 /* Set Virtual Router id if supported. */ 4508 if (!SOC_IS_HURRICANEX(unit) && SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_0f)) { 4509 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_0f, vrf_id); 4510 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_MASK0f, vrf_mask); 4511 } 4512 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 4513 4514 #if defined(BCM_TRIDENT2_SUPPORT) 4515 if (lpm_cfg->defip_entry_type == bcmDefipEntryTypeFcoe && SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_0f)) { 4516 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_0f, vrf_id); 4517 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_MASK0f, vrf_mask); 4518 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, D_ID0f, 4519 lpm_cfg->defip_fcoe_d_id); 4520 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, D_ID_MASK0f, 4521 lpm_cfg->defip_fcoe_d_id_mask); 4522 #ifdef BCM_TRIDENT3_SUPPORT 4523 if (SOC_IS_TRIDENT3X(unit)) { 4524 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 3); 4525 } else 4526 #endif /* BCM_TRIDENT3_SUPPORT */ 4527 { 4528 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ENTRY_TYPE0f, 1); 4529 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ENTRY_TYPE_MASK0f, 1); 4530 } 4531 } 4532 #endif 4533 4534 if (ipmc && SOC_IS_TRIDENT3X(unit)) { 4535 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, DATA_TYPE0f, 2); 4536 } 4537 4538 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode0_bit[unit])) { 4539 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode0_bit[unit], mode); 4540 } 4541 4542 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode1_bit[unit])) { 4543 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode1_bit[unit], mode); 4544 } 4545 4546 #if defined(BCM_TRX_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 4547 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) { 4548 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask0_bit[unit], 4549 (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) - 1); 4550 } 4551 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) { 4552 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask1_bit[unit], 4553 (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) - 1); 4554 } 4555 #endif /* BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */ 4556 #if defined(BCM_RAVEN_SUPPORT) 4557 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_MASK0f)) { 4558 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), 4559 lpm_entry, RESERVED_MASK0f, 0); 4560 } 4561 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_KEY0f)) { 4562 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, RESERVED_KEY0f, 0); 4563 } 4564 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_MASK1f)) { 4565 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), 4566 lpm_entry, RESERVED_MASK1f, 0); 4567 } 4568 if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_KEY1f)) { 4569 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, RESERVED_KEY1f, 0); 4570 } 4571 #endif /* BCM_RAVEN_SUPPORT */ 4572 4573 #if defined(BCM_TRX_SUPPORT) 4574 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) { 4575 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 4576 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), 4577 lpm_entry, GLOBAL_ROUTE0f, 0x1); 4578 } 4579 } 4580 #endif /* BCM_TRX_SUPPORT */ 4581 4582 return (BCM_E_NONE); 4583 } 4584 4585 4586 /* 4587 * Routine to fill the L3_DEFIP_DATA_ONLY and L3_DEFIP_HIT_ONLY buffers 4588 * as per the given DEFIP config structure. 4589 */ 4590 int 4591 _bcm_fb_lpm_prepare_defip_data(int unit, 4592 _bcm_defip_cfg_t *lpm_cfg, 4593 int nh_ecmp_idx, 4594 uint32 *lpm_data, 4595 uint32 *lpm_hit, 4596 int upper) 4597 { 4598 int rpe[2] = {RPE0f, RPE1f}; 4599 int pri[2] = {PRI0f, PRI1f}; 4600 int ecmp[2] = {ECMP0f, ECMP1f}; 4601 #if defined(BCM_TRX_SUPPORT) 4602 int class_id[2] = {CLASS_ID0f, CLASS_ID1f}; 4603 int global_route[2] = {GLOBAL_ROUTE0f, GLOBAL_ROUTE1f}; 4604 #endif 4605 int dst_discard[2] = {DST_DISCARD0f, DST_DISCARD1f}; 4606 int default_route[2] = {DEFAULTROUTE0f, DEFAULTROUTE1f}; 4607 int next_hop_index[2] = {NEXT_HOP_INDEX0f, NEXT_HOP_INDEX1f}; 4608 int ecmp_count[2] = {ECMP_COUNT0f, ECMP_COUNT1f}; 4609 #if defined(BCM_TRIDENT3_SUPPORT) 4610 int dest_field[2] = {DESTINATION0f, DESTINATION1f}; 4611 #endif 4612 #if 0 4613 int ecmp_ptr[2] = {ECMP_PTR0f, ECMP_PTR1f}; 4614 int src_discard[2] = {SRC_DISCARD0f, SRC_DISCARD1f}; 4615 int reserved_ecmp_ptr[2] = {RESERVED_ECMP_PTR0f, RESERVED_ECMP_PTR1f}; 4616 #endif 4617 soc_mem_t mem = L3_DEFIP_DATA_ONLYm; 4618 soc_mem_t hit_mem = L3_DEFIP_HIT_ONLYm; 4619 4620 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1_HIT_ONLYm)) { 4621 mem = L3_DEFIP_DATA_LEVEL1m; 4622 hit_mem = L3_DEFIP_LEVEL1_HIT_ONLYm; 4623 } 4624 if (NULL == lpm_cfg || NULL == lpm_data) { 4625 return BCM_E_INTERNAL; 4626 } 4627 4628 if (upper >> 1) { 4629 return BCM_E_INTERNAL; 4630 } 4631 4632 /* Set hit bit. */ 4633 if (lpm_hit != NULL) { 4634 int hit[2] = {HIT0f, HIT1f}; 4635 4636 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 4637 soc_mem_field32_set(unit, hit_mem, lpm_hit, hit[upper], 1); 4638 } 4639 } 4640 4641 if (SOC_IS_TOMAHAWK3(unit)) { 4642 uint32 fmte[10]; 4643 sal_memset(fmte, 0, sizeof(fmte)); 4644 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 4645 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, RPE0f, 1); 4646 } 4647 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, PRI0f, lpm_cfg->defip_prio); 4648 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, CLASS_ID0f, 4649 lpm_cfg->defip_lookup_class); 4650 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DESTINATIONf, nh_ecmp_idx); 4651 4652 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 4653 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 1); 4654 } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4655 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 0); 4656 } 4657 4658 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 4659 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_OFFSET_MODEf, 4660 lpm_cfg->defip_flex_ctr_mode); 4661 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_POOL_NUMBERf, 4662 lpm_cfg->defip_flex_ctr_pool); 4663 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_BASE_COUNTER_IDXf, 4664 lpm_cfg->defip_flex_ctr_base_id); 4665 } 4666 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 4667 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DST_DISCARDf, 1); 4668 } 4669 if (upper) { 4670 soc_mem_field_set(unit, mem, lpm_data, ASSOC_DATA1f, fmte); 4671 } else { 4672 soc_mem_field_set(unit, mem, lpm_data, ASSOC_DATA0f, fmte); 4673 } 4674 sal_memset(fmte, 0, sizeof(fmte)); 4675 soc_format_field32_set(unit, ALPM1_DATAfmt, fmte, DIRECT_ROUTEf, 1); 4676 soc_mem_field_set(unit, mem, lpm_data, ALPM1_DATA0f, fmte); 4677 sal_memset(fmte, 0, sizeof(fmte)); 4678 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 4679 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 2); 4680 } else if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 4681 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 0); 4682 } else { 4683 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 1); 4684 } 4685 soc_mem_field_set(unit, mem, lpm_data, FIXED_DATA0f, fmte); 4686 return BCM_E_NONE; 4687 } 4688 /* Set priority override bit. */ 4689 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 4690 soc_mem_field32_set(unit, mem, lpm_data, rpe[upper], 1); 4691 } 4692 4693 /* Configure entry for SIP lookup if URPF is enabled. 4694 * For devices like KT2 both DIP and SIP lookup is done 4695 * using only 1 L3_DEFIP entry, unlike other devices where 4696 * L3_DEFIP table is divided in 2 parts to support URPF. 4697 * RPExf and DEFAULTROUTExf are not overlayed in KT2 like previous devices. 4698 */ 4699 if (soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) { 4700 soc_mem_field32_set(unit, mem, lpm_data, default_route[upper], 4701 (SOC_URPF_STATUS_GET(unit) ? 1 : 0)); 4702 } 4703 4704 /* Write priority field. */ 4705 soc_mem_field32_set(unit, mem, lpm_data, pri[upper], lpm_cfg->defip_prio); 4706 4707 /* Fill next hop information. */ 4708 #if defined(BCM_TRIDENT3_SUPPORT) 4709 if (SOC_IS_TRIDENT3X(unit)) { 4710 /* TRIDENT3 has DESTINATION0 and DESTINATION1 fields */ 4711 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 4712 soc_mem_field32_dest_set(unit, mem, lpm_data, dest_field[upper], 4713 SOC_MEM_FIF_DEST_ECMP, nh_ecmp_idx); 4714 } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4715 soc_mem_field32_dest_set(unit, mem, lpm_data, dest_field[upper], 4716 SOC_MEM_FIF_DEST_NEXTHOP, nh_ecmp_idx); 4717 } 4718 } else 4719 #endif 4720 { 4721 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 4722 soc_mem_field32_set(unit, mem, lpm_data, ecmp[upper], 1); 4723 /* NOTE: Order is important set next hop index before ECMP_COUNT. 4724 * If device doesn't have ECMP_COUNT: ECMP_PTR field is shorter than 4725 * next hop -> we must ensure that write resets high bits of next hop 4726 * field. 4727 */ 4728 if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4729 soc_mem_field32_set(unit, mem, lpm_data, next_hop_index[upper], 4730 nh_ecmp_idx); 4731 } 4732 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ecmp_count[upper])) { 4733 soc_mem_field32_set(unit, mem, lpm_data, ecmp_count[upper], 4734 lpm_cfg->defip_ecmp_count); 4735 } 4736 } else { 4737 soc_mem_field32_set(unit, mem, lpm_data, ecmp[upper], 0); 4738 if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4739 soc_mem_field32_set(unit, mem, lpm_data, next_hop_index[upper], 4740 nh_ecmp_idx); 4741 } 4742 } 4743 } 4744 4745 /* Set destination discard flag. */ 4746 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 4747 if (SOC_MEM_FIELD_VALID(unit, mem, dst_discard[upper])) { 4748 soc_mem_field32_set(unit, mem, lpm_data, dst_discard[upper], 1); 4749 } else { 4750 return (BCM_E_UNAVAIL); 4751 } 4752 } 4753 4754 #if defined(BCM_TRX_SUPPORT) 4755 /* Set classification group id. */ 4756 if (SOC_MEM_FIELD_VALID(unit, mem, class_id[upper])) { 4757 soc_mem_field32_set(unit, mem, lpm_data, class_id[upper], 4758 lpm_cfg->defip_lookup_class); 4759 } 4760 4761 /* Set Global route flag. */ 4762 if (SOC_MEM_FIELD_VALID(unit, mem, global_route[upper])) { 4763 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 4764 soc_mem_field32_set(unit, mem, lpm_data, 4765 global_route[upper], 0x1); 4766 } 4767 } 4768 #endif /* BCM_TRX_SUPPORT */ 4769 4770 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 4771 if (soc_feature(unit, soc_feature_ipmc_defip) && 4772 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 4773 4774 int l3mc_index[2] = {L3MC_INDEX0f, L3MC_INDEX1f}; 4775 int dest_fmt[2] = {DESTINATION0f, DESTINATION1f}; 4776 int expected_l3_iif[2] = {EXPECTED_L3_IIF0f, EXPECTED_L3_IIF1f}; 4777 int multicast_route[2] = {MULTICAST_ROUTE0f, MULTICAST_ROUTE1f}; 4778 int data_type[2] = {DATA_TYPE0f, DATA_TYPE1f}; 4779 int ipmc_ext_l3_iifp_mismatch_drop[2] = 4780 {IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP1f}; 4781 int ipmc_ext_l3_iifp_mismatch_tocpu[2] = 4782 {IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU1f}; 4783 4784 if (soc_mem_field_valid(unit, mem, multicast_route[upper])) { 4785 soc_mem_field32_set(unit, mem, lpm_data, multicast_route[upper], 1); 4786 } else if (soc_mem_field_valid(unit, mem, data_type[upper])) { 4787 soc_mem_field32_set(unit, mem, lpm_data, data_type[upper], 2); 4788 } 4789 4790 if (soc_feature(unit, soc_feature_generic_dest)) { 4791 if (lpm_cfg->defip_mc_group > 0) { 4792 soc_mem_field32_dest_set(unit, mem, lpm_data, dest_fmt[upper], 4793 SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group); 4794 } 4795 } else { 4796 soc_mem_field32_set(unit, mem, lpm_data, l3mc_index[upper], lpm_cfg->defip_mc_group); 4797 } 4798 4799 /* 4800 * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf 4801 */ 4802 if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) { 4803 soc_mem_field32_set(unit, mem, lpm_data, expected_l3_iif[upper], 4804 _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp)); 4805 4806 } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 4807 (lpm_cfg->defip_expected_intf != 0)) { 4808 4809 soc_mem_field32_set(unit, mem, lpm_data, expected_l3_iif[upper], 4810 lpm_cfg->defip_expected_intf); 4811 4812 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) { 4813 soc_mem_field32_set(unit, mem, lpm_data, 4814 ipmc_ext_l3_iifp_mismatch_drop[upper], 1); 4815 } 4816 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 4817 soc_mem_field32_set(unit, mem, lpm_data, 4818 ipmc_ext_l3_iifp_mismatch_tocpu[upper], 1); 4819 } 4820 } 4821 } 4822 #endif 4823 4824 return BCM_E_NONE; 4825 } 4826 4827 4828 int 4829 _bcm_fb_lpm_prepare_defip_entry(int unit, _bcm_defip_cfg_t *lpm_cfg, 4830 int nh_ecmp_idx, uint32 *lpm_entry, 4831 uint32 *lpm_entry_upr) 4832 { 4833 soc_mem_t mem = L3_DEFIPm; 4834 if (NULL == lpm_cfg || NULL == lpm_entry) { 4835 return BCM_E_PARAM; 4836 } 4837 4838 if (!SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 4839 mem = L3_DEFIP_LEVEL1m; 4840 } 4841 #ifdef BCM_TRIDENT3_SUPPORT 4842 if (soc_feature(unit, soc_feature_flex_flow) && 4843 lpm_cfg->defip_flow_handle != 0) { 4844 BCM_IF_ERROR_RETURN( 4845 _bcm_td3_lpm_prepare_flex_defip_entry(unit, lpm_cfg, 4846 nh_ecmp_idx, lpm_entry)); 4847 return BCM_E_NONE; 4848 } 4849 #endif 4850 4851 4852 /* Set hit bit. */ 4853 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 4854 soc_mem_field32_set(unit, mem, lpm_entry, 4855 HIT0f, 0x1); 4856 } 4857 4858 if (!SOC_IS_TOMAHAWK3(unit)) { 4859 /* Set priority override bit. */ 4860 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 4861 soc_mem_field32_set(unit, mem, lpm_entry, 4862 RPE0f, 0x1); 4863 } 4864 /* Write priority field. */ 4865 soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio); 4866 4867 /* Configure entry for SIP lookup if URPF is enabled. 4868 * For devices like KT2 both DIP and SIP lookup is done 4869 * using only 1 L3_DEFIP entry, unlike other devices where 4870 * L3_DEFIP table is divided in 2 parts to support URPF. 4871 * RPExf and DEFAULTROUTExf are not overlayed in KT2 like previous devices. 4872 */ 4873 if (soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) { 4874 soc_mem_field32_set(unit, mem, lpm_entry, DEFAULTROUTE0f, 4875 (SOC_URPF_STATUS_GET(unit) ? 1 : 0)); 4876 } 4877 } 4878 4879 /* Fill next hop information. */ 4880 if (SOC_IS_TRIDENT3X(unit)) { 4881 /* TRIDENT3 has DESTINATION0 and DESTINATION1 fields */ 4882 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 4883 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 4884 SOC_MEM_FIF_DEST_ECMP, nh_ecmp_idx); 4885 } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4886 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 4887 SOC_MEM_FIF_DEST_NEXTHOP, nh_ecmp_idx); 4888 4889 } 4890 /* Set destination discard flag. */ 4891 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 4892 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) { 4893 soc_mem_field32_set(unit, mem, lpm_entry, DST_DISCARD0f, 1); 4894 } else { 4895 return (BCM_E_UNAVAIL); 4896 } 4897 } 4898 } else if (!SOC_IS_TOMAHAWK3(unit)){ 4899 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 4900 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1); 4901 /* NOTE: Order is important set next hop index before ECMP_COUNT. 4902 * If device doesn't have ECMP_COUNT: ECMP_PTR field is shorter than 4903 * next hop -> we must ensure that write resets high bits of next hop 4904 * field. 4905 */ 4906 if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4907 soc_mem_field32_set(unit, mem, lpm_entry, NEXT_HOP_INDEX0f, 4908 nh_ecmp_idx); 4909 } 4910 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ECMP_COUNT0f)) { 4911 soc_mem_field32_set(unit, mem, lpm_entry, ECMP_COUNT0f, 4912 lpm_cfg->defip_ecmp_count); 4913 } 4914 } else { 4915 if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 4916 soc_mem_field32_set(unit, mem, lpm_entry, NEXT_HOP_INDEX0f, 4917 nh_ecmp_idx); 4918 } 4919 } 4920 4921 /* Set destination discard flag. */ 4922 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 4923 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) { 4924 soc_mem_field32_set(unit, mem, lpm_entry, DST_DISCARD0f, 1); 4925 } else { 4926 return (BCM_E_UNAVAIL); 4927 } 4928 } 4929 } 4930 4931 #if defined(BCM_TRX_SUPPORT) 4932 if (!SOC_IS_TOMAHAWK3(unit)) { 4933 /* Set classification group id. */ 4934 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) { 4935 soc_mem_field32_set(unit, mem, lpm_entry, CLASS_ID0f, 4936 lpm_cfg->defip_lookup_class); 4937 } 4938 4939 /* Set Global route flag. */ 4940 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, GLOBAL_ROUTE0f)) { 4941 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 4942 soc_mem_field32_set(unit, mem, lpm_entry, 4943 GLOBAL_ROUTE0f, 0x1); 4944 } 4945 } 4946 } 4947 #endif /* BCM_TRX_SUPPORT */ 4948 4949 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 4950 if (soc_feature(unit, soc_feature_ipmc_defip) && 4951 (lpm_cfg->defip_flags & BCM_L3_IPMC) && !(SOC_IS_TOMAHAWK3(unit))) { 4952 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 4953 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MULTICAST_ROUTE0f, 1); 4954 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 4955 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 2); 4956 } 4957 4958 if (soc_feature(unit, soc_feature_generic_dest)) { 4959 if (lpm_cfg->defip_mc_group > 0) { 4960 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 4961 SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group); 4962 } 4963 } else { 4964 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f, lpm_cfg->defip_mc_group); 4965 } 4966 4967 /* 4968 * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf 4969 */ 4970 if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) { 4971 soc_mem_field32_set(unit, mem, lpm_entry, EXPECTED_L3_IIF0f, 4972 _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp)); 4973 4974 } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 4975 (lpm_cfg->defip_expected_intf != 0)) { 4976 4977 soc_mem_field32_set(unit, mem, lpm_entry, EXPECTED_L3_IIF0f, lpm_cfg->defip_expected_intf); 4978 4979 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) { 4980 soc_mem_field32_set(unit, mem, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, 1); 4981 } 4982 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 4983 soc_mem_field32_set(unit, mem, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, 1); 4984 } 4985 } 4986 } 4987 #endif 4988 4989 #if defined(BCM_TRIDENT2_SUPPORT) 4990 #if defined(BCM_TOMAHAWK3_SUPPORT) 4991 if (SOC_IS_TOMAHAWK3(unit)) { 4992 uint32 fmte[4]; 4993 sal_memset(fmte, 0, sizeof(fmte)); 4994 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 4995 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, RPEf, 1); 4996 } 4997 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, PRIf, lpm_cfg->defip_prio); 4998 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, CLASS_IDf, 4999 lpm_cfg->defip_lookup_class); 5000 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DESTINATIONf, nh_ecmp_idx); 5001 5002 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 5003 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 1); 5004 } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) { 5005 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 0); 5006 } 5007 5008 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 5009 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_OFFSET_MODEf, 5010 lpm_cfg->defip_flex_ctr_mode); 5011 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_POOL_NUMBERf, 5012 lpm_cfg->defip_flex_ctr_pool); 5013 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_BASE_COUNTER_IDXf, 5014 lpm_cfg->defip_flex_ctr_base_id); 5015 } 5016 5017 /* Set destination discard flag. */ 5018 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 5019 soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DST_DISCARDf, 1); 5020 } 5021 5022 soc_mem_field_set(unit, mem, lpm_entry, ASSOC_DATA0f, fmte); 5023 sal_memset(fmte, 0, sizeof(fmte)); 5024 soc_format_field32_set(unit, ALPM1_DATAfmt, fmte, DIRECT_ROUTEf, 1); 5025 soc_mem_field_set(unit, mem, lpm_entry, ALPM1_DATA0f, fmte); 5026 5027 sal_memset(fmte, 0, sizeof(fmte)); 5028 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 5029 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 2); 5030 } else if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 5031 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 0); 5032 } else { 5033 soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 1); 5034 } 5035 soc_mem_field_set(unit, mem, lpm_entry, FIXED_DATA0f, fmte); 5036 5037 } else if (soc_feature(unit,soc_feature_advanced_flex_counter)) 5038 #endif 5039 { 5040 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, FLEX_CTR_OFFSET_MODE0f)) { 5041 soc_mem_field32_set(unit, mem, lpm_entry, FLEX_CTR_OFFSET_MODE0f, 5042 lpm_cfg->defip_flex_ctr_mode); 5043 soc_mem_field32_set(unit, mem, lpm_entry, FLEX_CTR_POOL_NUMBER0f, 5044 lpm_cfg->defip_flex_ctr_pool); 5045 soc_mem_field32_set(unit, mem, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f, 5046 lpm_cfg->defip_flex_ctr_base_id); 5047 } 5048 } 5049 #endif 5050 5051 /* 5052 * Note ipv4 entries are expected to reside in part 0 of the entry. 5053 * ipv6 entries both parts should be filled. 5054 * Hence if entry is ipv6 copy part 0 to part 1 5055 */ 5056 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 5057 soc_fb_lpm_ip4entry0_to_1(unit, lpm_entry, lpm_entry, TRUE); 5058 if (lpm_entry_upr != NULL) { 5059 sal_memcpy(lpm_entry_upr, lpm_entry, 5060 BCM_XGS3_L3_ENT_SZ(unit, defip)); 5061 } 5062 } 5063 5064 /* 5065 * Initialize hw buffer from lpm configuration. 5066 * NOTE: DON'T MOVE _bcm_fb_defip_ent_init CALL UP, 5067 * We want to copy flags & nh info, avoid ipv6 mask & address corruption. 5068 */ 5069 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, lpm_entry)); 5070 5071 if (NULL == lpm_entry_upr) { 5072 /* lpm_entry_upr should not be null only in case of 128b entries */ 5073 return BCM_E_NONE; 5074 } 5075 5076 return _bcm_fb_lpm_upr_ent_init(unit, lpm_cfg, lpm_entry_upr); 5077 5078 } 5079 5080 int 5081 _bcm_fb_lpm128_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 5082 { 5083 uint32 hw_entry_lwr[SOC_MAX_MEM_WORDS]; 5084 uint32 hw_entry_upr[SOC_MAX_MEM_WORDS]; 5085 int hw_index = 0; /* Entry offset in the TCAM. */ 5086 int rv = BCM_E_NONE; /* Operation return status. */ 5087 int ipv6 = 1; 5088 5089 5090 /* Input parameters check. */ 5091 if (lpm_cfg == NULL) { 5092 return (BCM_E_PARAM); 5093 } 5094 /* 5095 * No support for routes matching AFTER vrf specific. 5096 * By not allowing VRF_GLOBAL for 128-V6 routes, 5097 * we make sure that 64-V6 private entries dont get 5098 * priotized over 128-V6 public/global entries. 5099 */ 5100 if ((BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) && 5101 (lpm_cfg->defip_sub_len > 64)) { 5102 return (BCM_E_UNAVAIL); 5103 } 5104 5105 sal_memset(hw_entry_lwr, 0x0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5106 5107 if (!(lpm_cfg->defip_flags & BCM_L3_IP6)) { 5108 ipv6 = 0; 5109 } 5110 5111 if (ipv6) { 5112 sal_memset(hw_entry_upr, 0x0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5113 lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR; 5114 _bcm_fb_lpm_prepare_defip_entry(unit, lpm_cfg, nh_ecmp_idx, 5115 hw_entry_lwr, 5116 hw_entry_upr); 5117 } else { 5118 _bcm_fb_lpm_prepare_defip_entry(unit, lpm_cfg, nh_ecmp_idx, 5119 hw_entry_lwr, 5120 NULL); 5121 } 5122 5123 if (ipv6) { 5124 rv = soc_fb_lpm128_insert(unit, hw_entry_lwr, hw_entry_upr, &hw_index); 5125 } else { 5126 rv = soc_fb_lpm128_insert(unit, hw_entry_lwr, NULL, &hw_index); 5127 } 5128 /* Lack of index indicates a new route. */ 5129 if (BCM_SUCCESS(rv) && BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index) { 5130 BCM_XGS3_L3_DEFIP_CNT_INC(unit, ipv6); 5131 lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR; 5132 } 5133 5134 return rv; 5135 } 5136 5137 /* 5138 * Function: 5139 * _bcm_fb_lpm_clear_hit 5140 * Purpose: 5141 * Clear prefix entry hit bit. 5142 * Parameters: 5143 * unit - (IN)SOC unit number. 5144 * lpm_cfg - (IN)Route info. 5145 * lpm_entry - (IN)Buffer to write to hw. 5146 * Returns: 5147 * BCM_E_XXX 5148 */ 5149 STATIC int 5150 _bcm_fb_lpm_clear_hit(int unit, _bcm_defip_cfg_t *lpm_cfg, 5151 uint32 *lpm_entry) 5152 { 5153 int rv; /* Operation return status. */ 5154 int tbl_idx; /* Defip table index. */ 5155 defip_hit_only_entry_t lpm_hit_entry; 5156 /* LPM Hit Only Entry */ 5157 int defip_hit_size = 0; /* LPM Hit Only Entry Size */ 5158 soc_field_t hit_field = HIT0f; /* HIT bit field id. */ 5159 5160 /* Input parameters check */ 5161 if ((NULL == lpm_cfg) || (NULL == lpm_entry)) { 5162 return (BCM_E_PARAM); 5163 } 5164 5165 /* If entry was not hit clear "clear hit" and return */ 5166 if (!(lpm_cfg->defip_flags & BCM_L3_HIT)) { 5167 return (BCM_E_NONE); 5168 } 5169 5170 if (soc_feature(unit, soc_feature_lpm_atomic_write)) { 5171 /* Use only HIT ONLY VIEW to write entry */ 5172 5173 defip_hit_size = sizeof(defip_hit_only_entry_t); 5174 sal_memset(&lpm_hit_entry, 0, defip_hit_size); 5175 5176 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 5177 tbl_idx = lpm_cfg->defip_index; 5178 } else { 5179 tbl_idx = lpm_cfg->defip_index >> 1; 5180 } 5181 5182 BCM_IF_ERROR_RETURN(READ_L3_DEFIP_HIT_ONLYm(unit, 5183 MEM_BLOCK_ALL, tbl_idx, &lpm_hit_entry)); 5184 /* Reset entry hit bit in buffer. */ 5185 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 5186 soc_L3_DEFIP_HIT_ONLYm_field32_set(unit, &lpm_hit_entry, HIT1f, 0); 5187 } else { 5188 if (lpm_cfg->defip_index & 0x1) { 5189 hit_field = HIT1f; 5190 } 5191 } 5192 soc_L3_DEFIP_HIT_ONLYm_field32_set(unit, &lpm_hit_entry, hit_field, 0); 5193 5194 rv = BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_HIT_ONLYm, tbl_idx, &lpm_hit_entry); 5195 } else { 5196 /* Reset entry hit bit in buffer. */ 5197 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 5198 tbl_idx = lpm_cfg->defip_index; 5199 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT1f, 0); 5200 } else { 5201 tbl_idx = lpm_cfg->defip_index >> 1; 5202 if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 5203 rv = READ_L3_DEFIPm(unit, MEM_BLOCK_ALL, tbl_idx, lpm_entry); 5204 } else { 5205 rv = READ_L3_DEFIP_LEVEL1m(unit, MEM_BLOCK_ALL, tbl_idx, lpm_entry); 5206 } 5207 if (lpm_cfg->defip_index & 0x1) { 5208 hit_field = HIT1f; 5209 } 5210 } 5211 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, hit_field, 0); 5212 5213 /* Write lpm buffer to hardware. */ 5214 rv = BCM_XGS3_MEM_WRITE(unit, BCM_XGS3_L3_MEM(unit, defip), tbl_idx, lpm_entry); 5215 } 5216 return rv; 5217 } 5218 5219 int _bcm_fb_lpm128_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 5220 { 5221 uint32 lpm_key[SOC_MAX_MEM_WORDS]; /* Route lookup key. */ 5222 uint32 lpm_key_upr[SOC_MAX_MEM_WORDS]; /* Route lookup key. */ 5223 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 5224 uint32 lpm_entry_upr[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 5225 int clear_hit; /* Clear hit indicator. */ 5226 int rv; /* Operation return status. */ 5227 int pfx; 5228 int ipv6 = 1; 5229 5230 /* Input parameters check */ 5231 if (NULL == lpm_cfg) { 5232 return (BCM_E_PARAM); 5233 } 5234 5235 5236 if (!(lpm_cfg->defip_flags & BCM_L3_IP6)) { 5237 ipv6 = 0; 5238 } 5239 5240 /* Zero buffers. */ 5241 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5242 sal_memset(lpm_key, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5243 5244 if (ipv6) { 5245 sal_memset(lpm_key_upr, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5246 sal_memset(lpm_entry_upr, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5247 lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR; 5248 } 5249 /* Check if clear hit bit required. */ 5250 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 5251 5252 /* Initialize lkup key. */ 5253 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, (uint32 *)lpm_key)); 5254 if (ipv6) { 5255 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_upr_ent_init(unit, lpm_cfg, 5256 (uint32 *)lpm_key_upr)); 5257 /* Perform hw lookup. */ 5258 rv = soc_fb_lpm128_match(unit, (uint32 *)lpm_key, (uint32 *)lpm_key_upr, (uint32 *)lpm_entry, 5259 (uint32 *)lpm_entry_upr, &lpm_cfg->defip_index, &pfx, NULL); 5260 } else { 5261 /* Perform hw lookup. */ 5262 rv = soc_fb_lpm128_match(unit, (uint32 *)lpm_key, NULL, (uint32 *)lpm_entry, 5263 NULL, &lpm_cfg->defip_index, &pfx, NULL); 5264 } 5265 5266 BCM_IF_ERROR_RETURN(rv); 5267 5268 /* Found the entry in paired tcam */ 5269 lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR; 5270 5271 /* 5272 * If entry is ipv4 we always operate on entry in "zero" half of the 5273 * buffer. copy "one" half to "zero" half of lpm_entry, if entry is found 5274 * at "one" half. 5275 */ 5276 if ((!(lpm_cfg->defip_flags & BCM_L3_IP6)) && (lpm_cfg->defip_index & 0x1)) { 5277 soc_fb_lpm_ip4entry1_to_0(unit, &lpm_entry, &lpm_entry, TRUE); 5278 } 5279 5280 #ifdef BCM_TRIDENT_SUPPORT 5281 if (!(SOC_IS_TOMAHAWK3(unit)) && (SOC_IS_TD_TT(unit) || SOC_IS_TD2_TT2(unit))) { 5282 uint32 i, hit; 5283 defip_hit_only_entry_t hit_entry[2]; 5284 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym}; 5285 int hit_mem_cnt = 2; 5286 5287 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) { 5288 hit_mem[0] = L3_DEFIP_HIT_ONLYm; 5289 hit_mem_cnt = 1; 5290 } 5291 5292 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 5293 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 5294 BCM_IF_ERROR_RETURN 5295 (BCM_XGS3_MEM_READ(unit, hit_mem[i], 5296 lpm_cfg->defip_index, &hit_entry[i])); 5297 hit |= soc_mem_field32_get(unit, hit_mem[i], 5298 &hit_entry[i], HIT0f); 5299 } 5300 soc_mem_field32_set(unit, L3_DEFIPm, &lpm_entry, HIT0f, hit); 5301 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 5302 hit |= soc_mem_field32_get(unit, hit_mem[i], 5303 &hit_entry[i], HIT1f); 5304 } 5305 soc_mem_field32_set(unit, L3_DEFIPm, &lpm_entry, HIT1f, hit); 5306 } else { 5307 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 5308 BCM_IF_ERROR_RETURN 5309 (BCM_XGS3_MEM_READ(unit, hit_mem[i], 5310 lpm_cfg->defip_index >> 1, &hit_entry[i])); 5311 hit |= soc_mem_field32_get(unit, hit_mem[i], &hit_entry[i], 5312 lpm_cfg->defip_index & 0x1 ? 5313 HIT1f : HIT0f); 5314 } 5315 soc_mem_field32_set(unit, L3_DEFIPm, &lpm_entry, HIT0f, hit); 5316 } 5317 } 5318 #endif /* BCM_TRIDENT_SUPPORT */ 5319 5320 /* Parse hw buffer to defip entry. */ 5321 BCM_IF_ERROR_RETURN( 5322 _bcm_fb_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, (uint32 *)lpm_entry, NULL)); 5323 5324 /* Clear the HIT bit */ 5325 if (clear_hit) { 5326 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_clear_hit(unit, lpm_cfg, (uint32 *)lpm_entry)); 5327 } 5328 5329 return BCM_E_NONE; 5330 } 5331 5332 int 5333 _bcm_fb_lpm128_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 5334 { 5335 5336 int rv; /* Operation return status. */ 5337 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 5338 uint32 lpm_entry_upr[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 5339 int ipv6 = 1; 5340 5341 /* Input parameters check */ 5342 if (NULL == lpm_cfg) { 5343 return (BCM_E_PARAM); 5344 } 5345 5346 lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR; 5347 5348 if (!(lpm_cfg->defip_flags & BCM_L3_IP6)) { 5349 ipv6 = 0; 5350 } 5351 5352 /* Zero buffers. */ 5353 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5354 /* Initialize hw buffer deletion key. */ 5355 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, lpm_entry)); 5356 if (ipv6) { 5357 sal_memset(&lpm_entry_upr, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5358 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_upr_ent_init(unit, lpm_cfg, 5359 lpm_entry_upr)); 5360 } 5361 5362 /* Write buffer to hw. */ 5363 if (ipv6) { 5364 rv = soc_fb_lpm128_delete(unit, lpm_entry, lpm_entry_upr); 5365 } else { 5366 rv = soc_fb_lpm128_delete(unit, lpm_entry, NULL); 5367 } 5368 /* If route delete, then decrement total number of routes. */ 5369 if (rv >= 0) { 5370 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, ipv6); 5371 } 5372 return rv; 5373 } 5374 5375 /* 5376 * Function: 5377 * _bcm_fb_mem_ip6_defip_get 5378 * Purpose: 5379 * Set an IP6 address field in L3_DEFIPm 5380 * Note: 5381 * See soc_mem_ip6_addr_set() 5382 */ 5383 STATIC void 5384 _bcm_fb_mem_ip6_defip_get(int unit, const void *lpm_key, 5385 _bcm_defip_cfg_t *lpm_cfg) 5386 { 5387 uint8 *ip6; /* Ip6 address. */ 5388 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 5389 uint32 ip6_word; /* Temp storage. */ 5390 5391 sal_memset(mask, 0, sizeof (bcm_ip6_t)); 5392 5393 /* Just to keep variable name short. */ 5394 ip6 = lpm_cfg->defip_ip6_addr; 5395 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 5396 5397 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 5398 uint32 _key_data[2] = {0, 0}; 5399 5400 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY1f, _key_data); 5401 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 5402 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 5403 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 5404 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 5405 ip6[3] = (uint8) (ip6_word & 0xff); 5406 5407 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY0f, _key_data); 5408 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 5409 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 5410 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 5411 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 5412 ip6[7] = (uint8) (ip6_word & 0xff); 5413 5414 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK1f, _key_data); 5415 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 5416 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 5417 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 5418 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 5419 mask[3] = (uint8) (ip6_word & 0xff); 5420 5421 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK0f, _key_data); 5422 ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 5423 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 5424 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 5425 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 5426 mask[7] = (uint8) (ip6_word & 0xff); 5427 5428 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 5429 return; 5430 } 5431 5432 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word); 5433 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 5434 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 5435 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 5436 ip6[3] = (uint8) (ip6_word & 0xff); 5437 5438 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word); 5439 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 5440 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 5441 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 5442 ip6[7] = (uint8) (ip6_word & 0xff); 5443 5444 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word); 5445 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 5446 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 5447 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 5448 mask[3] = (uint8) (ip6_word & 0xff); 5449 5450 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word); 5451 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 5452 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 5453 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 5454 mask[7] = (uint8) (ip6_word & 0xff); 5455 5456 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 5457 } 5458 5459 5460 STATIC int 5461 _bcm_th3_lpm_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg, 5462 uint32 *lpm_entry) 5463 { 5464 uint32 _key_data[2]; 5465 bcm_ip_t v4_mask; 5466 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 5467 5468 sal_memset(_key_data, 0, sizeof(_key_data)); 5469 5470 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data); 5471 5472 if (ipv6) { 5473 _bcm_fb_mem_ip6_defip_get(unit, lpm_entry, lpm_cfg); 5474 /* Get Virtual Router id */ 5475 soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf); 5476 } else { 5477 lpm_cfg->defip_ip_addr = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 5478 lpm_cfg->defip_entry_type = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf); 5479 /* Get Virtual Router id */ 5480 soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf); 5481 /* Get subnet mask. */ 5482 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data); 5483 v4_mask = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 5484 5485 /* Fill mask length. */ 5486 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 5487 } 5488 return (BCM_E_NONE); 5489 } 5490 5491 /* 5492 * Function: 5493 * _bcm_fb_lpm_ent_get_key 5494 * Purpose: 5495 * Parse entry key from DEFIP table. 5496 * Parameters: 5497 * unit - (IN)SOC unit number. 5498 * lpm_cfg - (OUT)Buffer to fill defip information. 5499 * lpm_entry - (IN) Buffer read from hw. 5500 * Returns: 5501 * void 5502 */ 5503 STATIC int 5504 _bcm_fb_lpm_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg, 5505 uint32 *lpm_entry) 5506 { 5507 5508 bcm_ip_t v4_mask; 5509 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 5510 5511 #ifdef BCM_TRIDENT3_SUPPORT 5512 if (soc_feature(unit, soc_feature_flex_flow)) { 5513 uint32 key_type; 5514 5515 key_type = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, KEY_TYPE0f); 5516 5517 if (BCMI_LPM_FLEX_VIEW(key_type)) { 5518 return _bcm_td3_lpm_flex_ent_get_key(unit, lpm_cfg, lpm_entry, key_type); 5519 } 5520 } 5521 #endif 5522 5523 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 5524 return _bcm_th3_lpm_ent_get_key(unit, lpm_cfg, lpm_entry); 5525 } 5526 /* Set prefix ip address & mask. */ 5527 if (ipv6) { 5528 _bcm_fb_mem_ip6_defip_get(unit, lpm_entry, lpm_cfg); 5529 } else { 5530 /* Get ipv4 address. */ 5531 lpm_cfg->defip_ip_addr = 5532 soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR0f); 5533 5534 /* Get subnet mask. */ 5535 v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_MASK0f); 5536 5537 /* Fill mask length. */ 5538 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 5539 } 5540 5541 /* Get Virtual Router id */ 5542 soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf); 5543 5544 return (BCM_E_NONE); 5545 } 5546 5547 /* 5548 * Function: 5549 * _bcm_fb_lpm128_update_match 5550 * Purpose: 5551 * Update/Delete all entries in defip table matching a certain rule. 5552 * Parameters: 5553 * unit - (IN)SOC unit number. 5554 * trv_data - (IN)Delete pattern + compare,act,notify routines. 5555 * Returns: 5556 * BCM_E_XXX 5557 */ 5558 int 5559 _bcm_fb_lpm128_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 5560 { 5561 uint32 ipv6 = 0; /* Iterate over ipv6 only flag. */ 5562 int idx; /* Iteration index. */ 5563 int tmp_idx; /* ipv4 entries iterator. */ 5564 char *lpm_tbl_ptr = NULL; /* Dma table pointer. */ 5565 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 5566 int cmp_result; /* Test routine result. */ 5567 uint32 *lpm_entry = NULL; /* Hw entry buffer. */ 5568 uint32 *lpm_entry_upr = NULL; /* Hw entry buffer. */ 5569 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 5570 int defip_table_size; /* Defip table size. */ 5571 int rv = BCM_E_NONE; /* Operation return status. */ 5572 int idx_start = 0; 5573 int idx_end = 0; 5574 #ifdef BCM_TRIDENT_SUPPORT 5575 char *lpm_hit_only_tbl_ptr[2] = { NULL }; /* Dma table pointer. */ 5576 int tbl_entry_sz; 5577 #endif /* BCM_TRIDENT_SUPPORT */ 5578 int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 5579 int tcam_pair_count = 0; 5580 int b128 = 0; 5581 int tcam_number; 5582 int read_reverse = 0; 5583 uint32 lpm_entry_tmp[SOC_MAX_MEM_WORDS]; 5584 #ifdef BCM_WARM_BOOT_SUPPORT 5585 int need_reinit = 0; 5586 #endif 5587 5588 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 5589 return BCM_E_UNAVAIL; 5590 } 5591 5592 ipv6 = (trv_data->flags & BCM_L3_IP6); 5593 read_reverse = (trv_data->flags & BCM_XGS3_L3_OP_GET_REVERSE); 5594 SOC_IF_ERROR_RETURN(soc_fb_lpm_tcam_pair_count_get(unit, &tcam_pair_count)); 5595 5596 /* If soc_feature_l3_defip_advanced_lookup is TRUE then 5597 * both DIP and SIP lookup is done using only 1 L3_DEFIP entry. 5598 * L3_DEFIP table is not divided into 2 to support URPF (For ex: Katana2). 5599 */ 5600 if (SOC_URPF_STATUS_GET(unit) && 5601 !soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) { 5602 switch(tcam_pair_count) { 5603 case 1: 5604 case 2: 5605 defip_table_size = 2 * tcam_depth; 5606 break; 5607 case 3: 5608 case 4: 5609 defip_table_size = 4 * tcam_depth; 5610 break; 5611 case 5: 5612 case 6: 5613 defip_table_size = 6 * tcam_depth; 5614 break; 5615 case 7: 5616 case 8: 5617 defip_table_size = 8 * tcam_depth; 5618 break; 5619 default: 5620 defip_table_size = 0; 5621 break; 5622 } 5623 } else { 5624 defip_table_size = (tcam_pair_count * tcam_depth * 2); 5625 } 5626 5627 if (!defip_table_size) { 5628 return BCM_E_NONE; 5629 } 5630 /* Table DMA the LPM table to software copy */ 5631 rv = bcm_xgs3_l3_tbl_range_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 5632 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 5633 0, defip_table_size - 1, 5634 &lpm_tbl_ptr); 5635 if (rv < 0) { 5636 goto free_table; 5637 } 5638 5639 idx_start = 0; 5640 idx_end = defip_table_size; 5641 5642 /* Table DMA the HIT table to software copy */ 5643 #ifdef BCM_TRIDENT_SUPPORT 5644 if (SOC_IS_TD_TT(unit) && !(SOC_IS_TOMAHAWK3(unit))) { 5645 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) { 5646 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit, 5647 L3_DEFIP_HIT_ONLYm)); 5648 rv = bcm_xgs3_l3_tbl_range_dma(unit, 5649 L3_DEFIP_HIT_ONLYm, 5650 tbl_entry_sz, 5651 "lpm_hit_only_tbl", 5652 idx_start, idx_end - 1, 5653 &lpm_hit_only_tbl_ptr[0]); 5654 if (rv < 0) { 5655 goto free_table; 5656 } 5657 } else { 5658 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit, 5659 L3_DEFIP_HIT_ONLY_Xm)); 5660 rv = bcm_xgs3_l3_tbl_range_dma(unit, 5661 L3_DEFIP_HIT_ONLY_Xm, 5662 tbl_entry_sz, 5663 "lpm_hit_only_x_tbl", 5664 idx_start, idx_end - 1, 5665 &lpm_hit_only_tbl_ptr[0]); 5666 if (rv < 0) { 5667 goto free_table; 5668 } 5669 5670 rv = bcm_xgs3_l3_tbl_range_dma(unit, 5671 L3_DEFIP_HIT_ONLY_Ym, 5672 tbl_entry_sz, 5673 "lpm_hit_only_y_tbl", 5674 idx_start, idx_end - 1, 5675 &lpm_hit_only_tbl_ptr[1]); 5676 if (rv < 0) { 5677 goto free_table; 5678 } 5679 } 5680 } 5681 #endif /* BCM_TRIDENT_SUPPORT */ 5682 5683 for (idx = read_reverse ? (idx_end - 1) : idx_start; 5684 (read_reverse ? (idx >= idx_start) : (idx < idx_end)); 5685 (read_reverse ? idx-- : idx++)) { 5686 tcam_number = idx / tcam_depth; 5687 if (ipv6 && (tcam_number & 1)) { 5688 if (read_reverse) { 5689 idx -= tcam_depth; 5690 } else { 5691 idx += tcam_depth; 5692 } 5693 if (idx >= defip_table_size) { 5694 break; 5695 } 5696 } 5697 /* Calculate entry ofset. */ 5698 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 5699 lpm_entry = 5700 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 5701 defip_level1_entry_t *, lpm_tbl_ptr, idx); 5702 } else { 5703 lpm_entry = 5704 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 5705 defip_entry_t *, lpm_tbl_ptr, idx); 5706 } 5707 if (ipv6) { 5708 /* Calculate entry ofset. */ 5709 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 5710 lpm_entry_upr = 5711 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 5712 defip_level1_entry_t *, lpm_tbl_ptr, 5713 idx + tcam_depth); 5714 } else { 5715 lpm_entry_upr = 5716 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 5717 defip_entry_t *, lpm_tbl_ptr, idx + tcam_depth); 5718 } 5719 } 5720 5721 sal_memcpy(&lpm_entry_tmp, lpm_entry, BCM_XGS3_L3_ENT_SZ(unit, defip)); 5722 #ifdef BCM_WARM_BOOT_SUPPORT 5723 need_reinit = 0; 5724 #endif 5725 /* Each lpm entry contains 2 ipv4 entries -> Check both. */ 5726 for (tmp_idx = 0; tmp_idx < ((ipv6) ? 1 : 2); tmp_idx++) { 5727 5728 if (tmp_idx) { 5729 /* Check second part of the entry. */ 5730 soc_fb_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE); 5731 } 5732 5733 /* The ipv4 route can not be in the first half of L3_DEFIPm since the TH2 L3_DEFIP issue , 5734 so skip it*/ 5735 if (soc_feature(unit,soc_feature_half_of_l3_defip_ipv4_capacity) && 5736 !ipv6 && !tmp_idx) { 5737 continue; 5738 } 5739 5740 /* Make sure entry is valid. */ 5741 if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID0f)) { 5742 continue; 5743 } 5744 5745 if (ipv6) { 5746 /* Make sure entry is valid. */ 5747 if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry_upr, VALID0f)) { 5748 continue; 5749 } 5750 5751 #if defined(BCM_TOMAHAWK3_SUPPORT) 5752 if (SOC_IS_TOMAHAWK3(unit)) { 5753 uint32 _key_data[2] = {0, 0}; 5754 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data); 5755 if (!(soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf))) { 5756 continue; 5757 } 5758 } else 5759 #endif 5760 if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode0_bit[unit])) { 5761 continue; 5762 } 5763 } 5764 #ifdef BCM_TRIDENT_SUPPORT 5765 if (SOC_IS_TD_TT(unit) && !(SOC_IS_TOMAHAWK3(unit))) { 5766 uint32 i, hit; 5767 defip_hit_only_entry_t *hit_entry[2]; 5768 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym}; 5769 int hit_mem_cnt = 2; 5770 5771 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) 5772 || SOC_IS_TRIDENT3X(unit)) { 5773 hit_mem[0] = L3_DEFIP_HIT_ONLYm; 5774 hit_mem_cnt = 1; 5775 } 5776 5777 if (ipv6) { 5778 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 5779 hit_entry[i] = soc_mem_table_idx_to_pointer(unit, 5780 hit_mem[i], 5781 defip_hit_only_entry_t *, 5782 lpm_hit_only_tbl_ptr[i], 5783 idx); 5784 hit |= soc_mem_field32_get(unit, hit_mem[i], 5785 hit_entry[i], HIT0f); 5786 } 5787 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit); 5788 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 5789 hit |= soc_mem_field32_get(unit, hit_mem[i], 5790 hit_entry[i], HIT1f); 5791 } 5792 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT1f, hit); 5793 } else { 5794 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 5795 hit_entry[i] = soc_mem_table_idx_to_pointer(unit, 5796 hit_mem[i], 5797 defip_hit_only_entry_t *, 5798 lpm_hit_only_tbl_ptr[i], 5799 idx); 5800 hit |= soc_mem_field32_get(unit, hit_mem[i], 5801 hit_entry[i], 5802 tmp_idx ? HIT1f : HIT0f); 5803 } 5804 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit); 5805 } 5806 } 5807 #endif /* BCM_TRIDENT_SUPPORT */ 5808 5809 /* Zero destination buffer first. */ 5810 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 5811 5812 /* Parse the entry. */ 5813 rv = _bcm_fb_lpm_ent_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry, &b128); 5814 if (BCM_FAILURE(rv)) { 5815 LOG_ERROR(BSL_LS_BCM_L3, 5816 (BSL_META_U(unit, 5817 "_bcm_fb_lpm_ent_parse failed\n"))); 5818 goto free_table; 5819 } 5820 if (ipv6 && b128 != 1) { 5821 LOG_ERROR(BSL_LS_BCM_L3, 5822 (BSL_META_U(unit, 5823 "b128 traverse: entry is not b128\n"))); 5824 rv = SOC_E_INTERNAL; 5825 goto free_table; 5826 } 5827 if (ipv6) { 5828 lpm_cfg.defip_index = ((idx / (tcam_depth * 2)) * tcam_depth) + 5829 (idx % tcam_depth); 5830 } else { 5831 lpm_cfg.defip_index = idx; 5832 } 5833 /* If protocol doesn't match skip the entry. */ 5834 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 5835 continue; 5836 } 5837 5838 /* Fill entry ip address & subnet mask. */ 5839 if (ipv6) { 5840 _bcm_fb_lpm128_ent_get_key(unit, &lpm_cfg, lpm_entry, 5841 lpm_entry_upr); 5842 } else { 5843 _bcm_fb_lpm_ent_get_key(unit, &lpm_cfg, lpm_entry); 5844 } 5845 lpm_cfg.defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR; 5846 /* Execute operation routine if any. */ 5847 if (trv_data->op_cb) { 5848 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 5849 (void *)&lpm_cfg, 5850 (void *)&nh_ecmp_idx, &cmp_result); 5851 if (rv < 0) { 5852 goto free_table; 5853 } 5854 } 5855 #ifdef BCM_WARM_BOOT_SUPPORT 5856 need_reinit = 1; 5857 #endif 5858 } 5859 #ifdef BCM_WARM_BOOT_SUPPORT 5860 if (SOC_WARM_BOOT(unit) && need_reinit) { 5861 /* coverity[forward_null : FALSE] */ 5862 rv = soc_fb_lpm128_reinit(unit, idx, (uint32 *)&lpm_entry_tmp, 5863 lpm_entry_upr); 5864 if (rv < 0) { 5865 goto free_table; 5866 } 5867 } 5868 #endif /* BCM_WARM_BOOT_SUPPORT */ 5869 } 5870 5871 #ifdef BCM_WARM_BOOT_SUPPORT 5872 if (SOC_WARM_BOOT(unit)) { 5873 SOC_IF_ERROR_RETURN(soc_fb_lpm128_reinit_done(unit, ipv6)); 5874 } 5875 #endif /* BCM_WARM_BOOT_SUPPORT */ 5876 5877 free_table: 5878 if (lpm_tbl_ptr != NULL) { 5879 soc_cm_sfree(unit, lpm_tbl_ptr); 5880 } 5881 #ifdef BCM_TRIDENT_SUPPORT 5882 if (lpm_hit_only_tbl_ptr[0] != NULL) { 5883 soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[0]); 5884 } 5885 if (lpm_hit_only_tbl_ptr[1] != NULL) { 5886 soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[1]); 5887 } 5888 #endif 5889 5890 return rv; 5891 } 5892 5893 /* 5894 * Function: 5895 * bcm_xgs3_l3_tbl_range_dma 5896 * Purpose: 5897 * 5898 * Parameters: 5899 * unit -(IN)SOC unit number. 5900 * tbl_mem -(IN)Table memory. 5901 * tbl_entry_sz -(IN)Table entry size. 5902 * descr -(IN)Table descriptor. 5903 * start -(IN) Start index 5904 * end -(IN) End index 5905 * res_ptr -(OUT) Allocated pointer filled with table info 5906 * Returns: 5907 * BCM_E_XXX 5908 */ 5909 int 5910 bcm_xgs3_l3_tbl_range_dma(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz, 5911 const char *descr, int start, int end, char **res_ptr) 5912 { 5913 int alloc_size; /* Allocation size. */ 5914 char *buffer; /* Buffer to read the table. */ 5915 int tbl_size; /* HW table size. */ 5916 5917 /* Input parameters sanity check. */ 5918 if ((NULL == res_ptr) || (NULL == descr)) { 5919 return (BCM_E_PARAM); 5920 } 5921 5922 /* If entry size is not deterministic. reject. */ 5923 if (tbl_entry_sz == BCM_XGS3_L3_INVALID_ENT_SZ) { 5924 return (BCM_E_UNAVAIL); 5925 } 5926 5927 if (INVALIDm == tbl_mem) { 5928 return (BCM_E_NOT_FOUND); 5929 } 5930 5931 if (start < soc_mem_index_min(unit, tbl_mem) || 5932 end > soc_mem_index_max(unit, tbl_mem)) { 5933 return BCM_E_PARAM; 5934 } 5935 5936 /* Calculate table size. */ 5937 tbl_size = (end - start) + 1; 5938 alloc_size = tbl_entry_sz * tbl_size; 5939 5940 /* Allocate memory buffer. */ 5941 buffer = soc_cm_salloc(unit, alloc_size, descr); 5942 if (buffer == NULL) { 5943 return (BCM_E_MEMORY); 5944 } 5945 5946 /* Reset allocated buffer. */ 5947 memset(buffer, 0, alloc_size); 5948 5949 /* Read table to the buffer. */ 5950 if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY, 5951 start, 5952 end, buffer) < 0) { 5953 soc_cm_sfree(unit, buffer); 5954 return (BCM_E_INTERNAL); 5955 } 5956 5957 *res_ptr = buffer; 5958 return (BCM_E_NONE); 5959 } 5960 5961 5962 /* 5963 * Function: 5964 * _bcm_xgs3_l3_tnl_initiator_init 5965 * Purpose: 5966 * Initiate the tunnel terminator table. 5967 * Parameters: 5968 * unit - (IN) SOC unit number. 5969 * Returns: 5970 * BCM_E_XXX 5971 */ 5972 STATIC int 5973 _bcm_xgs3_l3_tnl_initiator_init(int unit) 5974 { 5975 int mem_sz; /* Memory allocation size. */ 5976 _bcm_l3_tbl_t *tbl_ptr; /* Tunnel initiator table. */ 5977 5978 /* Get table pointer. */ 5979 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 5980 5981 /* Get L3 tunnel table first & last index. */ 5982 tbl_ptr->idx_min = soc_mem_index_min(unit, 5983 BCM_XGS3_L3_MEM(unit, tnl_init_v4)); 5984 tbl_ptr->idx_max = soc_mem_index_max(unit, 5985 BCM_XGS3_L3_MEM(unit, tnl_init_v4)); 5986 5987 /* Set max used tunnel to first one (table is empty). */ 5988 tbl_ptr->idx_maxused = tbl_ptr->idx_min; 5989 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 5990 tbl_ptr->split_idx = 0; 5991 tbl_ptr->split_maxused = 0; 5992 #endif 5993 5994 5995 BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit) = tbl_ptr->idx_max - tbl_ptr->idx_min + 1; 5996 5997 /* 5998 * Keep track of tunnel initiator table usage. 5999 * Table size doesn't include first reserved entry. 6000 */ 6001 mem_sz = (BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit) + 1) * 6002 sizeof(_bcm_l3_tbl_ext_t); 6003 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr, 6004 mem_sz, "l3_tnl_init"); 6005 if (NULL == BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr) { 6006 return (BCM_E_MEMORY); 6007 } 6008 6009 return (BCM_E_NONE); 6010 } 6011 6012 /* 6013 * Function: 6014 * _bcm_xgs3_l3_tnl_dscp_init 6015 * Purpose: 6016 * Initiate the tunnel dscp table. 6017 * Parameters: 6018 * unit - (IN) SOC unit number. 6019 * Returns: 6020 * BCM_E_XXX 6021 */ 6022 STATIC int 6023 _bcm_xgs3_l3_tnl_dscp_init(int unit) 6024 { 6025 int mem_sz; /* Allocated memory size. */ 6026 int tnl_dscp_tbl_sz; /* Dscp map entry count. */ 6027 6028 #ifdef BCM_HURRICANE3_SUPPORT 6029 if (soc_feature(unit, soc_feature_miml_no_l3)) { 6030 tnl_dscp_tbl_sz = 0; 6031 BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit) = tnl_dscp_tbl_sz; 6032 return (BCM_E_NONE); 6033 } 6034 #endif 6035 tnl_dscp_tbl_sz = soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, tnl_dscp)); 6036 6037 /* Keep track of L3 tunnel dscp map IDs based on 6038 * the number of DSCP map table instances. Each 6039 * instance has (#prio * #color) entries. For Firebolt 6040 * there are 8 priorities and 4 colors. 6041 */ 6042 BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit) = 6043 SOC_IS_TRX(unit) ? (1) : tnl_dscp_tbl_sz / (8 * 4); 6044 mem_sz = SHR_BITALLOCSIZE(BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit)); 6045 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit), mem_sz, 6046 "l3_dscp_map"); 6047 if (NULL == BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit)) { 6048 return (BCM_E_MEMORY); 6049 } 6050 6051 return (BCM_E_NONE); 6052 } 6053 6054 6055 /* 6056 * Function: 6057 * _bcm_xgs3_l3_adj_mac_init 6058 * Purpose: 6059 * Initialize L3 tables. 6060 * Parameters: 6061 * unit - (IN) SOC unit number. 6062 * Returns: 6063 * BCM_E_XXX 6064 */ 6065 STATIC int 6066 _bcm_xgs3_l3_adj_mac_init(int unit) 6067 { 6068 return (BCM_E_NONE); 6069 } 6070 6071 #ifdef BCM_TRIDENT_SUPPORT 6072 /* 6073 * Function: 6074 * _bcm_xgs3_trunk_nh_store_init 6075 * Purpose: 6076 * Initialize Trunk to NextHop Index Store 6077 * Parameters: 6078 * unit - (IN) SOC unit number. 6079 * Returns: 6080 * BCM_E_XXX 6081 */ 6082 int 6083 _bcm_xgs3_trunk_nh_store_init(int unit) 6084 { 6085 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 6086 int num_trunk; 6087 soc_mem_t trunk_mem = TRUNK_GROUPm; 6088 6089 if (soc_feature(unit, soc_feature_fastlag)) { 6090 trunk_mem = FAST_TRUNK_GROUPm; 6091 } 6092 6093 num_trunk = soc_mem_index_count(unit, trunk_mem); 6094 6095 /* Allocate ip4 options profile usage bitmap */ 6096 if (NULL == l3_bk_info->l3_trunk_nh_store) { 6097 l3_bk_info->l3_trunk_nh_store = 6098 sal_alloc(sizeof(int) * num_trunk, "trunk nextHop store"); 6099 if (l3_bk_info->l3_trunk_nh_store == NULL) { 6100 return BCM_E_MEMORY; 6101 } 6102 } 6103 sal_memset( l3_bk_info->l3_trunk_nh_store, 0, sizeof(int) * num_trunk); 6104 return BCM_E_NONE; 6105 } 6106 6107 /* 6108 * Function: 6109 * _bcm_xgs3_trunk_nh_store_init 6110 * Purpose: 6111 * Initialize Trunk to NextHop Index Store 6112 * Parameters: 6113 * unit - (IN) SOC unit number. 6114 * Returns: 6115 * BCM_E_XXX 6116 */ 6117 void 6118 _bcm_xgs3_trunk_nh_store_deinit(int unit) 6119 { 6120 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 6121 6122 if (l3_bk_info->l3_trunk_nh_store) { 6123 sal_free(l3_bk_info->l3_trunk_nh_store); 6124 l3_bk_info->l3_trunk_nh_store = NULL; 6125 } 6126 6127 } 6128 6129 /* 6130 * Function: 6131 * _bcm_xgs3_trunk_nh_store_set 6132 * Purpose: 6133 * Set Trunk to NextHop Index Store entry 6134 * Parameters: 6135 * unit - (IN) SOC unit number. 6136 * Returns: 6137 * BCM_E_XXX 6138 */ 6139 int 6140 _bcm_xgs3_trunk_nh_store_set(int unit, bcm_trunk_t trunk_id, int nh_index) 6141 { 6142 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 6143 int num_trunk; 6144 soc_mem_t trunk_mem = TRUNK_GROUPm; 6145 6146 if (soc_feature(unit, soc_feature_fastlag)) { 6147 trunk_mem = FAST_TRUNK_GROUPm; 6148 } 6149 6150 num_trunk = soc_mem_index_count(unit, trunk_mem); 6151 6152 if (l3_bk_info->l3_trunk_nh_store) { 6153 if (trunk_id < num_trunk) { 6154 l3_bk_info->l3_trunk_nh_store[trunk_id] = nh_index; 6155 } else { 6156 return BCM_E_PARAM; 6157 } 6158 } 6159 return BCM_E_NONE; 6160 } 6161 6162 /* 6163 * Function: 6164 * _bcm_xgs3_trunk_nh_store_get 6165 * Purpose: 6166 * Get Trunk to NextHop Index Store entry 6167 * Parameters: 6168 * unit - (IN) SOC unit number. 6169 * Returns: 6170 * BCM_E_XXX 6171 */ 6172 int 6173 _bcm_xgs3_trunk_nh_store_get(int unit, bcm_trunk_t trunk_id, int *nh_index) 6174 { 6175 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 6176 int num_trunk; 6177 soc_mem_t trunk_mem = TRUNK_GROUPm; 6178 6179 if (soc_feature(unit, soc_feature_fastlag)) { 6180 trunk_mem = FAST_TRUNK_GROUPm; 6181 } 6182 6183 num_trunk = soc_mem_index_count(unit, trunk_mem); 6184 6185 if (l3_bk_info->l3_trunk_nh_store) { 6186 if (trunk_id < num_trunk) { 6187 *nh_index = l3_bk_info->l3_trunk_nh_store[trunk_id]; 6188 } else { 6189 return BCM_E_PARAM; 6190 } 6191 } 6192 return BCM_E_NONE; 6193 } 6194 6195 /* 6196 * Function: 6197 * _bcm_xgs3_trunk_nh_store_reset 6198 * Purpose: 6199 * Reset Trunk to NextHop Index Store entry 6200 * Parameters: 6201 * unit - (IN) SOC unit number. 6202 * Returns: 6203 * BCM_E_XXX 6204 */ 6205 int 6206 _bcm_xgs3_trunk_nh_store_reset(int unit, bcm_trunk_t trunk_id, int nh_index) 6207 { 6208 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 6209 int num_trunk; 6210 soc_mem_t trunk_mem = TRUNK_GROUPm; 6211 6212 if (soc_feature(unit, soc_feature_fastlag)) { 6213 trunk_mem = FAST_TRUNK_GROUPm; 6214 } 6215 6216 num_trunk = soc_mem_index_count(unit, trunk_mem); 6217 6218 if (l3_bk_info->l3_trunk_nh_store) { 6219 if (trunk_id < num_trunk) { 6220 if ((nh_index == -1) || 6221 (l3_bk_info->l3_trunk_nh_store[trunk_id] == nh_index)) { 6222 l3_bk_info->l3_trunk_nh_store[trunk_id] = 0; 6223 } 6224 } else { 6225 return BCM_E_PARAM; 6226 } 6227 } 6228 return BCM_E_NONE; 6229 } 6230 6231 int 6232 _bcm_xgs3_trunk_nh_store_unmap(int unit, bcm_trunk_t tid, int nh_index) 6233 { 6234 int rv = BCM_E_NONE; 6235 int idx = 0; 6236 bcm_port_t local_ports[SOC_MAX_NUM_PORTS]; 6237 int num_ports=0; 6238 int gport = 0; 6239 int modid = 0; 6240 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 6241 bcm_trunk_member_t *tmp_member_gports_array = NULL; 6242 #endif 6243 6244 BCM_IF_ERROR_RETURN( 6245 _bcm_xgs3_trunk_nh_store_reset(unit, tid, -1)); 6246 6247 rv = bcm_esw_trunk_get(unit, tid, NULL, 0, NULL, &num_ports); 6248 if (BCM_FAILURE(rv)) { 6249 return BCM_E_PORT; 6250 } 6251 if (num_ports == 0) { 6252 return BCM_E_NONE; 6253 } 6254 6255 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 6256 if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 6257 tmp_member_gports_array = sal_alloc( 6258 sizeof(bcm_trunk_member_t) * num_ports, "tmp_member_gports_arry"); 6259 if (tmp_member_gports_array == NULL) { 6260 return BCM_E_MEMORY; 6261 } 6262 sal_memset(tmp_member_gports_array, 0, 6263 sizeof(bcm_trunk_member_t) * num_ports); 6264 rv = bcm_esw_trunk_get(unit, tid, NULL, 6265 num_ports, tmp_member_gports_array, &num_ports); 6266 if (BCM_FAILURE(rv)) { 6267 goto clean_up; 6268 } 6269 } else 6270 #endif 6271 { 6272 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, tid, 6273 SOC_MAX_NUM_PORTS, local_ports, &num_ports)); 6274 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid)); 6275 } 6276 6277 for (idx = 0; idx < num_ports; idx++) { 6278 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 6279 if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 6280 gport = tmp_member_gports_array[idx].gport; 6281 } else 6282 #endif 6283 { 6284 BCM_GPORT_MODPORT_SET(gport, modid, local_ports[idx]); 6285 } 6286 6287 rv = _bcm_trx_gport_to_nhi_set(unit, gport, 0); 6288 if (BCM_FAILURE(rv)) { 6289 goto clean_up; 6290 } 6291 } 6292 6293 clean_up: 6294 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 6295 if (NULL != tmp_member_gports_array) { 6296 sal_free(tmp_member_gports_array); 6297 } 6298 #endif 6299 return rv; 6300 } 6301 #endif /* BCM_TRIDENT_SUPPORT */ 6302 6303 /* 6304 * Function: 6305 * _bcm_xgs3_l3_free_resource 6306 * Purpose: 6307 * Free all allocated tables and memory 6308 * Parameters: 6309 * unit - SOC unit number 6310 * Returns: 6311 * Nothing 6312 */ 6313 STATIC void 6314 _bcm_xgs3_l3_free_resource(int unit) 6315 { 6316 int rv; /* Operation return status. */ 6317 6318 /* If software tables were not allocated we are done. */ 6319 if (NULL == l3_module_data[unit]) { 6320 return; 6321 } 6322 6323 /* Free next hop ref counts & hashes. */ 6324 if (BCM_XGS3_L3_TBL(unit, next_hop).ext_arr) { 6325 sal_free(BCM_XGS3_L3_TBL(unit, next_hop).ext_arr); 6326 BCM_XGS3_L3_TBL(unit, next_hop).ext_arr = NULL; 6327 } 6328 6329 /* Free VLAN VRF ref counts stored in ing_intf table */ 6330 if (BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr) { 6331 sal_free(BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr); 6332 BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr = NULL; 6333 } 6334 6335 /* Free tunnel initiator ref counts & hashes. */ 6336 if (BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr) { 6337 sal_free(BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr); 6338 BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr = NULL; 6339 } 6340 6341 /* Free route table. */ 6342 if (SOC_IS_FBX(unit)) { 6343 rv = bcm_xgs3_l3_fbx_defip_deinit(unit); 6344 if (BCM_FAILURE(rv)) { 6345 LOG_ERROR(BSL_LS_BCM_L3, 6346 (BSL_META_U(unit, 6347 "Route table free error %d\n"), 6348 rv)); 6349 } 6350 } 6351 6352 if (BCM_XGS3_L3_TBL(unit, ecmp).ext_arr) { 6353 sal_free(BCM_XGS3_L3_TBL(unit, ecmp).ext_arr); 6354 BCM_XGS3_L3_TBL(unit, ecmp).ext_arr = NULL; 6355 } 6356 6357 if(!soc_feature(unit, soc_feature_no_tunnel)) { 6358 /* Tunnels terminator table deinit. */ 6359 rv = soc_tunnel_term_deinit(unit); 6360 if (BCM_FAILURE(rv)) { 6361 LOG_ERROR(BSL_LS_BCM_L3, 6362 (BSL_META_U(unit, 6363 "Tunnel terminator table free %d\n"), 6364 rv)); 6365 } 6366 } 6367 6368 #ifdef BCM_TRIUMPH2_SUPPORT 6369 if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) || 6370 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 6371 bcm_tr2_l3_ecmp_defragment_buffer_deinit(unit); 6372 } 6373 if(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) { 6374 sal_free(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)); 6375 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit) = NULL; 6376 } 6377 #endif /* BCM_TRIUMPH2_SUPPORT */ 6378 6379 /* Free ecmp groups ref counts & hashes. */ 6380 if (BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr) { 6381 sal_free(BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr); 6382 BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr = NULL; 6383 } 6384 6385 #ifdef BCM_TRIDENT_SUPPORT 6386 if (soc_feature(unit, soc_feature_trill) || 6387 soc_feature(unit, soc_feature_l2gre) || 6388 soc_feature(unit, soc_feature_vxlan)) { 6389 (void) _bcm_xgs3_trunk_nh_store_deinit(unit); 6390 } 6391 #endif /* BCM_TRIDENT_SUPPORT */ 6392 6393 #ifdef BCM_TRIUMPH3_SUPPORT 6394 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 6395 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 6396 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 6397 _bcm_th2_ecmp_dlb_deinit(unit); 6398 } else 6399 #endif /* BCM_TOMAHAWK2_SUPPORT */ 6400 { 6401 _bcm_tr3_ecmp_dlb_deinit(unit); 6402 } 6403 } 6404 #endif /* BCM_TRIUMPH3_SUPPORT */ 6405 6406 #ifdef BCM_TRIDENT2_SUPPORT 6407 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) && 6408 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 6409 bcm_td2_ecmp_rh_deinit(unit); 6410 } 6411 #endif /* BCM_TRIDENT2_SUPPORT */ 6412 6413 #ifdef BCM_TOMAHAWK_SUPPORT 6414 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 6415 bcm_opt_ecmp_rh_deinit(unit); 6416 } 6417 #endif /* BCM_TOMAHAWK_SUPPORT */ 6418 6419 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 6420 if (soc_feature(unit, soc_feature_ipmc_defip)) { 6421 bcm_td2p_l3_defip_deinit(unit); 6422 } 6423 #endif 6424 6425 /* Free interface indexes usage bits. */ 6426 if (BCM_XGS3_L3_IF_INUSE(unit)) { 6427 sal_free(BCM_XGS3_L3_IF_INUSE(unit)); 6428 BCM_XGS3_L3_IF_INUSE(unit) = NULL; 6429 } 6430 6431 /* Free egress interfaces indexes usage bits ever set in Next Hop table. */ 6432 if (BCM_XGS3_L3_INTF_USED_NH(unit)) { 6433 sal_free(BCM_XGS3_L3_INTF_USED_NH(unit)); 6434 BCM_XGS3_L3_INTF_USED_NH(unit) = NULL; 6435 } 6436 6437 /* Free interface indexes usage bits. */ 6438 if (BCM_XGS3_L3_ING_IF_INUSE(unit)) { 6439 sal_free(BCM_XGS3_L3_ING_IF_INUSE(unit)); 6440 BCM_XGS3_L3_ING_IF_INUSE(unit) = NULL; 6441 } 6442 6443 6444 /* Free interface address in ARL bits. */ 6445 if (BCM_XGS3_L3_IF_ADD2ARL(unit)) { 6446 sal_free(BCM_XGS3_L3_IF_ADD2ARL(unit)); 6447 BCM_XGS3_L3_IF_ADD2ARL(unit) = NULL; 6448 } 6449 6450 /* Free dscp map indexes usage bits. */ 6451 if (BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit)) { 6452 sal_free(BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit)); 6453 BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit) = NULL; 6454 } 6455 6456 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 6457 defined(BCM_HAWKEYE_SUPPORT) 6458 if (soc_feature(unit, soc_feature_fp_based_routing)) { 6459 _bcm_rp_l3_deinit(unit); 6460 } 6461 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 6462 6463 #if defined(BCM_TRIUMPH2_SUPPORT) 6464 if (soc_feature(unit, soc_feature_gport_service_counters)) { 6465 _bcm_esw_flex_stat_release_handles(unit, _bcmFlexStatTypeVrf); 6466 } 6467 #endif 6468 6469 #if defined(BCM_TRIUMPH3_SUPPORT) 6470 if (SOC_IS_TRIUMPH3(unit)) { 6471 if(BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 6472 rv = _bcm_tr3_esm_host_tbl_deinit(unit); 6473 if (BCM_FAILURE(rv)) { 6474 LOG_ERROR(BSL_LS_BCM_L3, 6475 (BSL_META_U(unit, 6476 "Error in freeing ESM host tbl state %d\n"), 6477 rv)); 6478 } 6479 } 6480 } 6481 #endif 6482 6483 #ifdef BCM_TRIDENT2_SUPPORT 6484 if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) { 6485 rv = _bcm_td2_l3_ip4_options_free_resources(unit); 6486 if (BCM_FAILURE(rv)) { 6487 LOG_ERROR(BSL_LS_BCM_L3, 6488 (BSL_META_U(unit, 6489 "Error in freeing IP4 options profile %d\n"), 6490 rv)); 6491 } 6492 } 6493 if (soc_feature(unit, soc_feature_nat)) { 6494 _bcm_esw_l3_nat_free_resource(unit); 6495 } 6496 #endif /* BCM_TRIDENT2_SUPPORT */ 6497 6498 #if defined(BCM_TRX_SUPPORT) 6499 if (soc_feature(unit, soc_feature_virtual_switching)) { 6500 rv = _bcm_virtual_deinit(unit); 6501 if (BCM_FAILURE(rv)) { 6502 LOG_ERROR(BSL_LS_BCM_L3, 6503 (BSL_META_U(unit, 6504 "Error in freeing virtual %d\n"), 6505 rv)); 6506 } 6507 } 6508 #endif 6509 6510 #if defined(BCM_RIOT_SUPPORT) 6511 if (soc_feature(unit, soc_feature_riot)) { 6512 _bcm_td2p_macda_oui_profile_deinit(unit); 6513 } 6514 #endif /* BCM_RIOT_SUPPORT */ 6515 6516 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 6517 sal_free(BCM_XGS3_L3_NH_MULTI_COUNT(unit)); 6518 BCM_XGS3_L3_NH_MULTI_COUNT(unit) = NULL; 6519 } 6520 #ifdef BCM_TOMAHAWK2_SUPPORT 6521 if (BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)) { 6522 sal_free(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)); 6523 BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit) = NULL; 6524 } 6525 #endif /* BCM_TOMAHAWK2_SUPPORT */ 6526 6527 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 6528 if (BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit)) { 6529 sal_free(BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit)); 6530 BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit) = NULL; 6531 } 6532 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */ 6533 6534 /* Free module data. */ 6535 if (l3_module_data[unit]) { 6536 sal_free(l3_module_data[unit]->l3_ecmp_info.ecmp_flags); 6537 } 6538 sal_free(l3_module_data[unit]); 6539 l3_module_data[unit] = NULL; 6540 6541 return; 6542 } 6543 6544 /* 6545 * Function: 6546 * _bcm_xgs3_l3_get_tunnel_id 6547 * Purpose: 6548 * Routine extracts tunnel id based on interface id. 6549 * Parameters: 6550 * unit - (IN)StrataSwitch #. 6551 * ifindex - (IN)Interface index. 6552 * tunnel - (OUT) tunnel_id. 6553 * Returns: 6554 * BCM_E_XXX 6555 */ 6556 int 6557 _bcm_xgs3_l3_get_tunnel_id(int unit, int ifindex, int *tunnel_id) 6558 { 6559 _bcm_l3_intf_cfg_t l3_intf; /* Buffer to read interface info. */ 6560 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 6561 6562 /* Input parameters check. */ 6563 if (NULL == tunnel_id) { 6564 return (BCM_E_PARAM); 6565 } 6566 6567 /* Initialization. */ 6568 sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 6569 *tunnel_id = 0; 6570 6571 /* Set interface index. */ 6572 BCM_XGS3_L3_INTF_IDX_SET(l3_intf, ifindex); 6573 6574 /* Read interface information. */ 6575 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 6576 BCM_XGS3_L3_MODULE_LOCK(unit); 6577 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf); 6578 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6579 } 6580 /* Check hw operation status. */ 6581 BCM_IF_ERROR_RETURN(rv); 6582 6583 /* Save interface tunnel index. */ 6584 *tunnel_id = l3_intf.l3i_tunnel_idx; 6585 6586 return (BCM_E_NONE); 6587 } 6588 6589 /* 6590 * Function: 6591 * _bcm_xgs3_nh_entry_init 6592 * Purpose: 6593 * Routine fills next hop specific info 6594 * based on l3 configuration OR defip entry. 6595 * Parameters: 6596 * unit - (IN) StrataSwitch #. 6597 * nh_entry - (OUT)Next hop pointer to fill. 6598 * l3cfg - (IN) L3 host entry. 6599 * lpm_cfg - (IN) Route entry. 6600 * Returns: 6601 * BCM_E_XXX 6602 */ 6603 STATIC int 6604 _bcm_xgs3_nh_entry_init(int unit, bcm_l3_egress_t *nh_entry, 6605 _bcm_l3_cfg_t *l3cfg, _bcm_defip_cfg_t *lpm_cfg) 6606 { 6607 int port_tgid; /* Port/trunk id. */ 6608 #ifdef BCM_FIREBOLT_SUPPORT 6609 _bcm_l3_intf_cfg_t l3_intf; 6610 #endif /* BCM_FIREBOLT_SUPPORT */ 6611 6612 if ((NULL == nh_entry) || ((NULL == l3cfg) && (NULL == lpm_cfg)) || 6613 ((NULL != l3cfg) && (NULL != lpm_cfg))) { 6614 return (BCM_E_PARAM); 6615 } 6616 6617 /* Reset next hop entry. (We will use it for hash calc. */ 6618 bcm_l3_egress_t_init(nh_entry); 6619 6620 /* Set next hop interface index. */ 6621 nh_entry->intf = (l3cfg) ? l3cfg->l3c_intf : lpm_cfg->defip_intf; 6622 6623 /* Set next hop flags. */ 6624 nh_entry->flags = (l3cfg) ? l3cfg->l3c_flags : lpm_cfg->defip_flags; 6625 6626 #ifdef BCM_TRIDENT3_SUPPORT 6627 if (SOC_IS_TRIDENT3X(unit)) { 6628 nh_entry->flags2 = (l3cfg) ? l3cfg->l3c_flags2 : lpm_cfg->defip_flags2; 6629 } 6630 #endif /* BCM_TRIDENT3_SUPPORT */ 6631 /* Set port/trunk information. */ 6632 port_tgid = (l3cfg) ? l3cfg->l3c_port_tgid : lpm_cfg->defip_port_tgid; 6633 if (nh_entry->flags & BCM_L3_TGID) { 6634 nh_entry->trunk = port_tgid; 6635 } else { 6636 nh_entry->port = port_tgid; 6637 } 6638 6639 /* Set module id. */ 6640 nh_entry->module = (l3cfg) ? l3cfg->l3c_modid : lpm_cfg->defip_modid; 6641 6642 /* Set next hop mac address. */ 6643 sal_memcpy(nh_entry->mac_addr, (l3cfg) ? l3cfg->l3c_mac_addr : 6644 lpm_cfg->defip_mac_addr, sizeof(bcm_mac_t)); 6645 6646 #ifdef BCM_FIREBOLT_SUPPORT 6647 /* Firebolt devices need interface info to fill vid & tunnel next hop. */ 6648 if (SOC_IS_FBX(unit)) { 6649 sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 6650 6651 /* Read interface information. */ 6652 BCM_XGS3_L3_INTF_IDX_SET(l3_intf, nh_entry->intf); 6653 6654 BCM_XGS3_L3_MODULE_LOCK(unit); 6655 if (BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf) >= 0) { 6656 /* Set vid & istunnel to next hop entry. */ 6657 nh_entry->vlan = l3_intf.l3i_vid; 6658 } 6659 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6660 } 6661 #endif /* BCM_FIREBOLT_SUPPORT */ 6662 6663 return (BCM_E_NONE); 6664 } 6665 6666 /* 6667 * Purpose: 6668 * Entry-0 Nexthop Entry is reserved for BLACK_HOLE 6669 * Parameters: 6670 * unit - (IN) StrataSwitch #. 6671 * Returns: 6672 * BCM_E_XXX 6673 */ 6674 STATIC int 6675 _bcm_xgs3_l3_black_hole_nh_setup(int unit) 6676 { 6677 bcm_l3_egress_t nh_entry; /* next hop entry. */ 6678 int rv; 6679 6680 if (!SOC_WARM_BOOT(unit)) { 6681 bcm_l3_egress_t_init(&nh_entry); 6682 nh_entry.port = 0; 6683 nh_entry.intf = 0; 6684 nh_entry.flags = BCM_L3_DST_DISCARD; 6685 6686 BCM_XGS3_L3_MODULE_LOCK(unit); 6687 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_add)( 6688 unit, BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit), &nh_entry, 0); 6689 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6690 BCM_IF_ERROR_RETURN(rv); 6691 } 6692 6693 /* Set entry reference count. */ 6694 BCM_XGS3_L3_ENT_INIT((BCM_XGS3_L3_TBL_PTR(unit, next_hop)), 6695 BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit), _BCM_SINGLE_WIDE, 0); 6696 6697 #ifdef BCM_RIOT_SUPPORT 6698 if (BCMI_L3_NH_OVERLAY_VALID(unit)) { 6699 6700 if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) > 6701 BCM_XGS3_L3_TBL(unit, next_hop).split_maxused) { 6702 6703 BCM_XGS3_L3_TBL(unit, next_hop).split_maxused = 6704 BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit); 6705 } 6706 } else 6707 #endif 6708 { 6709 if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) > 6710 BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused) { 6711 6712 BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused = 6713 BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit); 6714 } 6715 } 6716 6717 return (BCM_E_NONE); 6718 } 6719 6720 /* 6721 * Function: 6722 * _bcm_xgs3_l3_l2cpu_nh_setup 6723 * Purpose: 6724 * The first Nexthop Entry is reserved for packet to be L2 switched 6725 * to the local CPU. This is used when the BCM_L3_L2TOCPU flag is used 6726 * in host add; or when BCM_L3_DEFIP_LOCAL/BCM_L3_DEFIP_CPU flags 6727 * are used when adding routes. 6728 * Parameters: 6729 * unit - (IN) StrataSwitch #. 6730 * Returns: 6731 * BCM_E_XXX 6732 */ 6733 STATIC int 6734 _bcm_xgs3_l3_l2cpu_nh_setup(int unit) 6735 { 6736 bcm_l3_egress_t nh_entry; /* Trap to cpu next hop entry. */ 6737 _bcm_l3_intf_cfg_t intf_info; /* Bridge to cpu interface. */ 6738 int rv; 6739 6740 if (!SOC_WARM_BOOT(unit)) { 6741 /* Zero structures. */ 6742 bcm_l3_egress_t_init(&nh_entry); 6743 6744 /* Set mac address to all ones. */ 6745 sal_memset(nh_entry.mac_addr, 0xff, sizeof(bcm_mac_t)); 6746 6747 /* Set module id to a local module. */ 6748 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &nh_entry.module)); 6749 6750 /* Set port to be a cpu port. */ 6751 nh_entry.port = CMIC_PORT(unit); 6752 6753 /* Set interface index. */ 6754 nh_entry.intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit); 6755 6756 /* Add next hop entry to hw. */ 6757 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_add)) { 6758 return (BCM_E_UNAVAIL); 6759 } 6760 6761 BCM_XGS3_L3_MODULE_LOCK(unit); 6762 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_add) ( 6763 unit, BCM_XGS3_L3_L2CPU_NH_IDX(unit), &nh_entry, 0); 6764 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6765 BCM_IF_ERROR_RETURN(rv); 6766 } 6767 6768 /* Set entry reference count. */ 6769 BCM_XGS3_L3_ENT_INIT((BCM_XGS3_L3_TBL_PTR(unit, next_hop)), 6770 BCM_XGS3_L3_L2CPU_NH_IDX(unit), _BCM_SINGLE_WIDE, 0); 6771 6772 #ifdef BCM_RIOT_SUPPORT 6773 if (BCMI_L3_NH_OVERLAY_VALID(unit)) { 6774 6775 if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) > 6776 BCM_XGS3_L3_TBL(unit, next_hop).split_maxused) { 6777 6778 BCM_XGS3_L3_TBL(unit, next_hop).split_maxused = 6779 BCM_XGS3_L3_L2CPU_NH_IDX(unit); 6780 } 6781 } else 6782 #endif 6783 { 6784 if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) > 6785 BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused) { 6786 6787 BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused = 6788 BCM_XGS3_L3_L2CPU_NH_IDX(unit); 6789 } 6790 } 6791 6792 if (!SOC_WARM_BOOT(unit)) { 6793 /* Create trap to cpu interface entry. */ 6794 /* Set mac address to all ones. */ 6795 sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t)); 6796 sal_memset(intf_info.l3i_mac_addr, 0xff, sizeof(bcm_mac_t)); 6797 6798 /* Set L2_SWITCHf flag to true. */ 6799 intf_info.l3i_flags = BCM_L3_L2ONLY; 6800 6801 /* Set interface index. */ 6802 intf_info.l3i_index = BCM_XGS3_L3_L2CPU_INTF_IDX(unit); 6803 6804 /* Add next hop entry to hw. */ 6805 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_add)) { 6806 BCM_XGS3_L3_MODULE_LOCK(unit); 6807 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_add) (unit, &intf_info); 6808 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6809 BCM_IF_ERROR_RETURN(rv); 6810 } else { 6811 return (BCM_E_UNAVAIL); 6812 } 6813 } 6814 6815 /* Mark interface index "inuse" */ 6816 if (!BCM_L3_INTF_USED_GET(unit, BCM_XGS3_L3_L2CPU_INTF_IDX(unit))) { 6817 BCM_L3_INTF_USED_SET(unit, BCM_XGS3_L3_L2CPU_INTF_IDX(unit)); 6818 } 6819 6820 return (BCM_E_NONE); 6821 } 6822 6823 6824 6825 /* 6826 * Function: 6827 * _bcm_xgs3_l3_l2cpu_nh_cb 6828 * Purpose: 6829 * To update the first Nexthop Entry if modid has been changed after init 6830 * Parameters: 6831 * unit - (IN) StrataSwitch #. 6832 * modid - (IN) Update modid 6833 * userdata - (IN) Pointer to any user data 6834 * Returns: 6835 * NONE 6836 */ 6837 STATIC void 6838 _bcm_xgs3_l3_l2cpu_nh_cb(int unit, soc_switch_event_t event, uint32 arg1, 6839 uint32 arg2, uint32 arg3, void* userdata) 6840 { 6841 6842 switch (event) { 6843 case SOC_SWITCH_EVENT_MODID_CHANGE: 6844 _bcm_xgs3_l3_l2cpu_nh_setup(unit); 6845 break; 6846 default: 6847 break; 6848 } 6849 6850 return; 6851 } 6852 6853 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 6854 /* 6855 * Function: 6856 * bcmi_xgs3_l3_ecmp_tbl_split_range_init 6857 * Purpose: 6858 * Initialize split indexes in L3 ECMP tables. 6859 * Parameters: 6860 * unit - (IN)SOC unit number. 6861 * Returns: 6862 * BCM_E_XXX. 6863 */ 6864 6865 STATIC void 6866 bcmi_xgs3_l3_ecmp_tbl_split_range_init(int unit, _bcm_l3_tbl_t *tbl_ptr) 6867 { 6868 #if defined(BCM_TRIDENT3_SUPPORT) 6869 _bcm_l3_bookkeeping_t *l3 = &_bcm_l3_bk_info[unit]; 6870 int num_banks; 6871 #endif 6872 /* Set up split table limits */ 6873 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 6874 #if defined(BCM_TRIDENT3_SUPPORT) 6875 if (SOC_IS_TRIDENT3X(unit)) { 6876 if ((tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, ecmp)) && l3->l3_ecmp_member_first_lkup_mem_size) { 6877 num_banks = l3->l3_ecmp_member_first_lkup_mem_size / BCMI_L3_ECMP_PER_BANK(unit) + 6878 ((l3->l3_ecmp_member_first_lkup_mem_size % BCMI_L3_ECMP_PER_BANK(unit))?1:0); 6879 tbl_ptr->split_idx = num_banks * BCMI_L3_ECMP_PER_BANK(unit); 6880 } else if ((tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp)) && l3->l3_ecmp_group_first_lkup_mem_size) { 6881 num_banks = l3->l3_ecmp_group_first_lkup_mem_size / BCMI_L3_ECMP_GROUP_PER_BANK(unit) + 6882 ((l3->l3_ecmp_group_first_lkup_mem_size % BCMI_L3_ECMP_GROUP_PER_BANK(unit))?1:0); 6883 tbl_ptr->split_idx = num_banks * BCMI_L3_ECMP_GROUP_PER_BANK(unit); 6884 } else { 6885 tbl_ptr->split_idx = (tbl_ptr->idx_max + 1)/2; 6886 } 6887 } else 6888 #endif 6889 { 6890 tbl_ptr->split_idx = (tbl_ptr->idx_max + 1)/2; 6891 } 6892 tbl_ptr->split_maxused = tbl_ptr->idx_min; 6893 tbl_ptr->idx_maxused = tbl_ptr->split_idx; 6894 } else { 6895 tbl_ptr->split_idx = 0; 6896 tbl_ptr->split_maxused = 0; 6897 } 6898 return; 6899 } 6900 #endif /* BCM_RIOT_SUPPORT || BCM_MULTI_LEVEL_ECMP_SUPPORT */ 6901 6902 /* 6903 * Function: 6904 * bcm_xgs3_l3_ecmp_group_init 6905 * Purpose: 6906 * Initialize internal L3 ecmp groups table. 6907 * Parameters: 6908 * unit - SOC unit number. 6909 * Returns: 6910 * BCM_E_XXX. 6911 */ 6912 STATIC int 6913 _bcm_xgs3_l3_ecmp_group_init(int unit) 6914 { 6915 int mem_sz; /* Ecmp group info memory size. */ 6916 int max_grp_sz; /* Maximum number of paths in ecmp group. */ 6917 _bcm_l3_tbl_t *tbl_ptr; /* Ecmp table pointer. */ 6918 int idx; 6919 #ifdef BCM_TRIDENT2_SUPPORT 6920 int vp_lag_idx_offset = 0; 6921 #endif 6922 6923 max_grp_sz = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 6924 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 6925 6926 /* 6927 * Calculate number of ecmp groups. 6928 */ 6929 tbl_ptr->idx_min = 0; 6930 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 6931 tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMP_COUNTm) - 1; 6932 } else { 6933 tbl_ptr->idx_max = (BCM_XGS3_L3_ECMP_TBL_SIZE(unit) / max_grp_sz) - 1; 6934 } 6935 6936 tbl_ptr->idx_maxused = tbl_ptr->idx_min; 6937 6938 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 6939 /* if there is split in table then set split ranges */ 6940 bcmi_xgs3_l3_ecmp_tbl_split_range_init(unit, tbl_ptr); 6941 vp_lag_idx_offset = tbl_ptr->split_idx; 6942 BCMI_L3_ECMP_OVERLAY_ENTRIES(unit) = vp_lag_idx_offset; 6943 #endif 6944 6945 /* 6946 * Keep track of ECMP table usage 6947 */ 6948 mem_sz = (tbl_ptr->idx_max + 1) * sizeof(_bcm_l3_tbl_ext_t); 6949 BCM_XGS3_L3_ALLOC(tbl_ptr->ext_arr, mem_sz, "l3_ecmp"); 6950 if (NULL == tbl_ptr->ext_arr) { 6951 return (BCM_E_MEMORY); 6952 } 6953 6954 for (idx=0; idx < tbl_ptr->idx_max+1; idx++) { 6955 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 0; 6956 } 6957 6958 #ifdef BCM_TOMAHAWK3_SUPPORT 6959 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 6960 WRITE_ECMP_GROUP_DLB_ID_OFFSETr(unit, 6961 BCM_TH3_L3_ECMP_DLB_START(unit)); 6962 } 6963 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) { 6964 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 6965 6966 /* 6967 * Calculate number of ecmp groups. 6968 */ 6969 tbl_ptr->idx_min = soc_mem_index_min(unit, ECMP_GROUP_HIERARCHICALm); 6970 6971 tbl_ptr->idx_max = soc_mem_index_max(unit, ECMP_GROUP_HIERARCHICALm); 6972 mem_sz = (soc_mem_index_count(unit, ECMP_GROUP_HIERARCHICALm)) * sizeof(_bcm_l3_tbl_ext_t); 6973 BCM_XGS3_L3_ALLOC(tbl_ptr->ext_arr, mem_sz, "l3_ecmp"); 6974 if (NULL == tbl_ptr->ext_arr) { 6975 return (BCM_E_MEMORY); 6976 } 6977 6978 for (idx=tbl_ptr->idx_min; idx <= tbl_ptr->idx_max; idx++) { 6979 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 0; 6980 } 6981 } 6982 #endif 6983 6984 #ifdef BCM_TRIDENT2_SUPPORT 6985 /* In Trident2, VP LAGs share the same table as ECMP group table. 6986 * The first N entries are reserved for VP LAGs, where N is the 6987 * value of the config property max_vp_lags. 6988 */ 6989 if (soc_feature(unit, soc_feature_vp_lag)) { 6990 int max_vp_lags; 6991 6992 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 6993 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 6994 for (idx=vp_lag_idx_offset; idx < max_vp_lags + vp_lag_idx_offset; 6995 idx++) { 6996 6997 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 1; 6998 } 6999 if (max_vp_lags > 0) { 7000 tbl_ptr->idx_maxused = max_vp_lags + vp_lag_idx_offset - 1; 7001 } 7002 } 7003 #endif /* BCM_TRIDENT2_SUPPORT */ 7004 7005 return BCM_E_NONE; 7006 } 7007 7008 #ifdef BCM_TRIDENT3_SUPPORT 7009 STATIC int 7010 bcmi_l3_hecmp_group_bank_sel(int unit, uint32 first_lkup_sz) 7011 { 7012 uint32 bank_sel_reg_val = 0; 7013 uint32 ol_bank_bit_value = 0; 7014 7015 if (first_lkup_sz) { 7016 if (first_lkup_sz <= BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)) { 7017 ol_bank_bit_value = ((1 << 7018 ((first_lkup_sz / BCMI_L3_ECMP_GROUP_PER_BANK(unit)) + 7019 ((first_lkup_sz % BCMI_L3_ECMP_GROUP_PER_BANK(unit)) ? 7020 1 : 0))) - 1); 7021 } else { 7022 LOG_ERROR(BSL_LS_BCM_L3, 7023 (BSL_META_U 7024 (unit, 7025 "ERROR : l3 ecmp group (%d) > total l3 ecmp group(%d).\n"), 7026 first_lkup_sz, 7027 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit))); 7028 return BCM_E_CONFIG; 7029 } 7030 } else { 7031 /* Maximum number of ECMP group and member banks is 8 in TD3 and 4 7032 * in HX5. 7033 */ 7034 ol_bank_bit_value = ((1 << 7035 (soc_reg_field_length 7036 (unit, 7037 INITIAL_ING_L3_ECMP_GROUP_BANK_SELr, 7038 BANK_SELf) / 2)) - 1); 7039 } 7040 7041 soc_reg_field_set(unit, ING_L3_ECMP_GROUP_BANK_SELr, 7042 &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value); 7043 SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_GROUP_BANK_SELr 7044 (unit, bank_sel_reg_val)); 7045 soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_GROUP_BANK_SELr, 7046 &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value); 7047 SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_GROUP_BANK_SELr 7048 (unit, bank_sel_reg_val)); 7049 7050 return BCM_E_NONE; 7051 } 7052 7053 STATIC int 7054 bcmi_l3_hecmp_bank_sel(int unit, uint32 first_lkup_sz) 7055 { 7056 uint32 bank_sel_reg_val = 0; 7057 uint32 ol_bank_bit_value = 0; 7058 7059 if (first_lkup_sz) { 7060 if (first_lkup_sz <= (soc_mem_index_count(unit, L3_ECMPm))) { 7061 ol_bank_bit_value = ((1 << 7062 ((first_lkup_sz / BCMI_L3_ECMP_PER_BANK(unit)) + 7063 ((first_lkup_sz % BCMI_L3_ECMP_PER_BANK(unit)) ? 7064 1 : 0))) - 1); 7065 } else { 7066 LOG_ERROR(BSL_LS_BCM_L3, 7067 (BSL_META_U 7068 (unit, 7069 "ERROR : l3 ecmp group (%d) > total l3 ecmp group(%d).\n"), 7070 first_lkup_sz, 7071 BCM_XGS3_L3_ECMP_MAX(unit))); 7072 return BCM_E_CONFIG; 7073 } 7074 } else { 7075 ol_bank_bit_value = ((1 << 7076 (soc_reg_field_length 7077 (unit, 7078 INITIAL_ING_L3_ECMP_BANK_SELr, 7079 BANK_SELf) / 2)) - 1); 7080 } 7081 7082 soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr, 7083 &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value); 7084 SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_BANK_SELr 7085 (unit, bank_sel_reg_val)); 7086 soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr, 7087 &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value); 7088 SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_BANK_SELr 7089 (unit, bank_sel_reg_val)); 7090 7091 return BCM_E_NONE; 7092 } 7093 #endif 7094 /* 7095 * Function: 7096 * _bcm_xgs3_l3_ecmp_table_init 7097 * Purpose: 7098 * Initialize HW ECMP table 7099 * Parameters: 7100 * unit - (IN) SOC unit number. 7101 * Returns: 7102 * BCM_E_XXX 7103 */ 7104 STATIC int 7105 _bcm_xgs3_l3_ecmp_table_init(int unit) 7106 { 7107 int idx; 7108 int ecmp_max, mem_sz; /* Ecmp entries info memory size. */ 7109 _bcm_l3_tbl_t *tbl_ptr; /* Ecmp table pointer. */ 7110 #if defined(BCM_TRIDENT3_SUPPORT) 7111 _bcm_l3_bookkeeping_t *l3; 7112 #endif /* BCM_TRIDENT3_SUPPORT */ 7113 7114 #ifdef BCM_TOMAHAWK_SUPPORT 7115 uint32 rval = 0; 7116 #endif /* BCM_TOMAHAWK_SUPPORT */ 7117 7118 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 7119 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 7120 ecmp_mode_hierarchical = BCM_TD3_L3_ECMP_MODE_HIERARCHICAL; 7121 ecmp_mode_single = BCM_TD3_L3_ECMP_MODE_SINGLE; 7122 } 7123 #endif /* BCM_TRIDENT3_SUPPORT */ 7124 7125 /* 7126 * Keep track of ECMP table usage. 7127 */ 7128 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 7129 tbl_ptr->idx_min = 0; 7130 7131 if (SOC_MEM_IS_VALID(unit, L3_ECMPm)) { 7132 tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMPm) - 1; 7133 } else { 7134 tbl_ptr->idx_max = -1; 7135 BCM_XGS3_L3_TBL(unit, ecmp_grp).idx_max = -1; 7136 } 7137 ecmp_max = tbl_ptr->idx_max; 7138 tbl_ptr->idx_maxused = tbl_ptr->idx_min; 7139 7140 7141 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 7142 /* if there is split in table then set split tables */ 7143 bcmi_xgs3_l3_ecmp_tbl_split_range_init(unit, tbl_ptr); 7144 #endif 7145 7146 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ecmp)) && 7147 soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ecmp))) { 7148 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 7149 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, ecmp)); 7150 } else { 7151 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0; 7152 } 7153 7154 #if defined(BCM_TRIDENT3_SUPPORT) 7155 l3 = &_bcm_l3_bk_info[unit]; 7156 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 7157 if (soc_esw_ecmp_protected_enabled(unit)) { 7158 int table_sz = 0; 7159 int first_lkup_sz = 0; 7160 int max_banks = 0; 7161 7162 /* One bank reserved for protection write/read. */ 7163 max_banks = (BCMI_L3_ECMP_MAX_BANKS(unit) - 1); 7164 table_sz = (BCMI_L3_ECMP_PER_BANK(unit) * max_banks); 7165 if (l3->l3_ecmp_member_first_lkup_mem_size == 0) { 7166 first_lkup_sz = ((max_banks / 2) * BCMI_L3_ECMP_PER_BANK(unit)); 7167 table_sz = (first_lkup_sz * 2); 7168 } else { 7169 first_lkup_sz = l3->l3_ecmp_member_first_lkup_mem_size; 7170 } 7171 tbl_ptr->split_idx = first_lkup_sz; 7172 tbl_ptr->idx_max = (table_sz - 1); 7173 tbl_ptr->idx_maxused = tbl_ptr->split_idx; 7174 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = table_sz; 7175 } 7176 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 7177 #endif /* BCM_TRIDENT3_SUPPORT */ 7178 7179 if (0 == BCM_XGS3_L3_ECMP_TBL_SIZE(unit)) { 7180 return (BCM_E_NONE); 7181 } 7182 7183 /* Default max ECMP to max allowed by hw */ 7184 #ifdef BCM_TOMAHAWK_SUPPORT 7185 if (soc_feature(unit, soc_feature_hierarchical_ecmp) || 7186 soc_feature(unit, soc_feature_multi_level_ecmp)) { 7187 rval = 0; 7188 BCM_IF_ERROR_RETURN(READ_ECMP_CONFIGr(unit, &rval)); 7189 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode = rval; 7190 /* 7191 * On TH, max path is 16k only for resilient hashing. 7192 * Set it to default of 128/1024 and use 16K only for RH. 7193 */ 7194 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 7195 ecmp_mode_hierarchical)) { 7196 #ifdef BCM_TOMAHAWK3_SUPPORT 7197 if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) { 7198 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 7199 BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS; 7200 } else 7201 #endif 7202 { 7203 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 128; 7204 } 7205 } else 7206 #ifdef BCM_TOMAHAWK3_SUPPORT 7207 if (soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) { 7208 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 7209 BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS; 7210 } else 7211 #endif 7212 { 7213 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 1024; 7214 } 7215 #ifdef BCM_TOMAHAWK3_SUPPORT 7216 if (SOC_IS_TOMAHAWK3(unit)) { 7217 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 32768; 7218 } else 7219 #endif 7220 if (SOC_IS_TOMAHAWK(unit)) { 7221 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 16384; 7222 } else { 7223 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 32768; 7224 } 7225 } else 7226 #endif /* BCM_TOMAHAWK_SUPPORT */ 7227 { 7228 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 7229 BCM_XGS3_L3_ECMP_MAX(unit); 7230 } 7231 7232 #ifdef BCM_TOMAHAWK_SUPPORT 7233 if (soc_feature(unit, soc_feature_fast_ecmp)) { 7234 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 128; 7235 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 8192; 7236 } 7237 #endif /* BCM_TOMAHAWK_SUPPORT */ 7238 7239 /* Ecmp is not in use until first ecmp route added. */ 7240 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_inuse = 0; 7241 7242 /* 7243 * Keep track of ECMP table usage 7244 */ 7245 mem_sz = (ecmp_max + 1) * sizeof(_bcm_l3_tbl_ext_t); 7246 BCM_XGS3_L3_ALLOC(tbl_ptr->ext_arr, mem_sz, "l3_ecmp"); 7247 if (NULL == tbl_ptr->ext_arr) { 7248 return (BCM_E_MEMORY); 7249 } 7250 7251 for (idx=0; idx < ecmp_max+1; idx++) { 7252 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 0; 7253 } 7254 7255 #ifdef BCM_TRIUMPH2_SUPPORT 7256 if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) || 7257 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 7258 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_buffer_init(unit)); 7259 } 7260 #endif /* BCM_TRIUMPH2_SUPPORT */ 7261 7262 #ifdef BCM_TRIUMPH2_SUPPORT 7263 BCM_XGS3_L3_MAX_ECMP_MODE(unit) = (SOC_IS_TRIUMPH3(unit)) ? TRUE : 7264 soc_property_get(unit, spn_L3_MAX_ECMP_MODE, 0); 7265 if (SOC_IS_TRIUMPH3(unit) || 7266 BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 7267 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit), 7268 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) * 7269 sizeof(uint16), 7270 "Array for max paths per ecmp group"); 7271 if (NULL == BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) { 7272 return (BCM_E_MEMORY); 7273 } 7274 7275 /* Max size of all groups initialized to zero */ 7276 sal_memset(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit), 0, 7277 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) * sizeof(uint16)); 7278 } 7279 #endif 7280 7281 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_init(unit)); 7282 7283 #ifdef BCM_TRIUMPH3_SUPPORT 7284 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 7285 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 7286 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 7287 #if defined(BCM_TOMAHAWK3_SUPPORT) 7288 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 7289 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_dlb_max_paths = 7290 BCM_TH3_L3_ECMP_DLB_MAX_PATHS; 7291 } else 7292 #endif 7293 { 7294 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_dlb_max_paths = 7295 soc_mem_field_length(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm, 7296 ECMP_MEMBER_BITMAPf); 7297 } 7298 BCM_XGS3_L3_ALLOC( 7299 BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit), 7300 SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2) * 7301 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit), 7302 "DLB member bitmap per ecmp group"); 7303 if (NULL == BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit)) { 7304 return (BCM_E_MEMORY); 7305 } 7306 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_init(unit)); 7307 } else 7308 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 7309 { 7310 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_init(unit)); 7311 } 7312 } 7313 #endif /* BCM_TRIUMPH3_SUPPORT */ 7314 7315 #ifdef BCM_TRIDENT2_SUPPORT 7316 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) && 7317 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 7318 BCM_IF_ERROR_RETURN(bcm_td2_ecmp_rh_init(unit)); 7319 } 7320 #endif /* BCM_TRIDENT2_SUPPORT */ 7321 7322 #ifdef BCM_TOMAHAWK_SUPPORT 7323 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 7324 BCM_IF_ERROR_RETURN(bcm_opt_ecmp_rh_init(unit)); 7325 } 7326 #endif /* BCM_TOMAHAWK_SUPPORT */ 7327 7328 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 7329 if (soc_feature(unit, soc_feature_dgm)) { 7330 BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit), 7331 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) * 7332 sizeof(uint16), 7333 "Array for alternate count per ecmp group"); 7334 if (NULL == BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)) { 7335 return (BCM_E_MEMORY); 7336 } 7337 7338 /* Max size of all groups initialized to zero */ 7339 sal_memset(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit), 0, 7340 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) * sizeof(uint16)); 7341 } 7342 #endif /* BCM_TOMAHAWK2_SUPPORT */ 7343 #ifdef BCM_TRIDENT3_SUPPORT 7344 if (SOC_IS_TRIDENT3X(unit)) { 7345 7346 if (l3->l3_ecmp_levels == 2) { 7347 BCM_IF_ERROR_RETURN( 7348 bcmi_l3_hecmp_group_bank_sel(unit, 7349 l3->l3_ecmp_group_first_lkup_mem_size)); 7350 7351 BCM_IF_ERROR_RETURN( 7352 bcmi_l3_hecmp_bank_sel(unit, 7353 l3->l3_ecmp_member_first_lkup_mem_size)); 7354 7355 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 128; 7356 } 7357 7358 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 7359 if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) { 7360 int first_lkup_sz; 7361 uint32 reg_val; 7362 uint32 bank_sel_bmp; 7363 7364 if (l3->l3_ecmp_levels == 2) { 7365 first_lkup_sz = tbl_ptr->split_idx; 7366 } else { 7367 first_lkup_sz = 0; 7368 } 7369 bank_sel_bmp = 7370 ((1 << ((first_lkup_sz / BCMI_L3_ECMP_PER_BANK(unit)) + 7371 ((first_lkup_sz % BCMI_L3_ECMP_PER_BANK(unit)) ? 7372 1 : 0))) - 1); 7373 7374 reg_val = 0; 7375 soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr, 7376 ®_val, BANK_SELf, bank_sel_bmp); 7377 SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_BANK_SELr 7378 (unit, reg_val)); 7379 soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr, 7380 ®_val, BANK_SELf, bank_sel_bmp); 7381 SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_BANK_SELr 7382 (unit, reg_val)); 7383 } 7384 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 7385 } 7386 #endif /* BCM_TRIDENT3_SUPPORT */ 7387 7388 return (BCM_E_NONE); 7389 } 7390 7391 7392 /* 7393 * Function: 7394 * bcm_xgs3_l3_tables_init 7395 * Purpose: 7396 * Initialize internal L3 tables and enable L3. 7397 * Parameters: 7398 * unit - SOC unit number. 7399 * Returns: 7400 * BCM_E_XXX. 7401 */ 7402 int 7403 bcm_xgs3_l3_tables_init(int unit) 7404 { 7405 int rv; /* Operation status. */ 7406 7407 /* Allocate/zero unit software tables. */ 7408 if (NULL == l3_module_data[unit]) { 7409 BCM_XGS3_L3_ALLOC(l3_module_data[unit], sizeof(_bcm_l3_module_data_t), 7410 "l3_module_data"); 7411 if (NULL == l3_module_data[unit]) { 7412 return (BCM_E_MEMORY); 7413 } 7414 7415 BCM_XGS3_L3_ALLOC(l3_module_data[unit]->l3_ecmp_info.ecmp_flags, 7416 sizeof(int) * BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit), 7417 "ECMP info flags"); 7418 if (NULL == l3_module_data[unit]->l3_ecmp_info.ecmp_flags) { 7419 return (BCM_E_MEMORY); 7420 } 7421 } else { 7422 l3_module_data[unit]->l3_op_flags = 0; 7423 sal_memset(l3_module_data[unit]->l3_ecmp_info.ecmp_flags, 0, 7424 sizeof(int) * BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); 7425 } 7426 7427 /* 7428 * Get hardware tables size. 7429 */ 7430 /* Init hw calls & memory addresses. */ 7431 rv = _bcm_xgs3_l3_hw_op_init(unit); 7432 if (BCM_FAILURE(rv)) { 7433 _bcm_xgs3_l3_free_resource(unit); 7434 return rv; 7435 } 7436 /* Flush all the tables in hw. */ 7437 if (!SAL_BOOT_QUICKTURN) { 7438 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_clear_all)) { 7439 BCM_XGS3_L3_MODULE_LOCK(unit); 7440 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_clear_all) (unit); 7441 BCM_XGS3_L3_MODULE_UNLOCK(unit); 7442 if (BCM_FAILURE(rv)) { 7443 _bcm_xgs3_l3_free_resource(unit); 7444 return rv; 7445 } 7446 } 7447 } 7448 7449 #ifdef BCM_TRIDENT_SUPPORT 7450 if (soc_feature(unit, soc_feature_trill) || 7451 soc_feature(unit, soc_feature_l2gre) || 7452 soc_feature(unit, soc_feature_vxlan)) { 7453 rv = _bcm_xgs3_trunk_nh_store_init (unit); 7454 if (BCM_FAILURE(rv)) { 7455 _bcm_xgs3_l3_free_resource(unit); 7456 return rv; 7457 } 7458 } 7459 #endif /* BCM_TRIDENT_SUPPORT */ 7460 7461 7462 7463 #ifdef BCM_TRIDENT2_SUPPORT 7464 if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) { 7465 rv = _bcm_td2_l3_ip4_options_profile_init(unit); 7466 if (BCM_FAILURE(rv)) { 7467 _bcm_xgs3_l3_free_resource(unit); 7468 return rv; 7469 } 7470 } 7471 if (soc_feature(unit, soc_feature_nat)) { 7472 rv = _bcm_esw_l3_nat_init(unit); 7473 if (BCM_FAILURE(rv)) { 7474 _bcm_xgs3_l3_free_resource(unit); 7475 return rv; 7476 } 7477 } 7478 #endif /* BCM_TRIDENT2_SUPPORT */ 7479 7480 /* Egress L3 interface table init. */ 7481 rv = _bcm_xgs3_l3_intf_init(unit); 7482 if (BCM_FAILURE(rv)) { 7483 _bcm_xgs3_l3_free_resource(unit); 7484 return rv; 7485 } 7486 7487 /* Ingress L3 interface table init. */ 7488 rv = _bcm_xgs3_l3_ing_intf_init(unit); 7489 if (BCM_FAILURE(rv)) { 7490 _bcm_xgs3_l3_free_resource(unit); 7491 return rv; 7492 } 7493 7494 /* Next hop table init. */ 7495 rv = _bcm_xgs3_l3_nh_init(unit); 7496 if (BCM_FAILURE(rv)) { 7497 _bcm_xgs3_l3_free_resource(unit); 7498 return rv; 7499 } 7500 7501 /* L3 host table init. */ 7502 rv = _bcm_xgs3_l3_table_init(unit); 7503 if (BCM_FAILURE(rv)) { 7504 _bcm_xgs3_l3_free_resource(unit); 7505 return rv; 7506 } 7507 7508 /* ECMP groups table init. */ 7509 rv = _bcm_xgs3_l3_ecmp_table_init(unit); 7510 if (BCM_FAILURE(rv)) { 7511 _bcm_xgs3_l3_free_resource(unit); 7512 return rv; 7513 } 7514 7515 /* Defip table init. */ 7516 rv = _bcm_xgs3_defip_table_init(unit); 7517 if (BCM_FAILURE(rv)) { 7518 _bcm_xgs3_l3_free_resource(unit); 7519 return rv; 7520 } 7521 7522 7523 if(!soc_feature(unit, soc_feature_no_tunnel)) { 7524 7525 /* Tunnels terminator table init. */ 7526 rv = soc_tunnel_term_init(unit); 7527 if (BCM_FAILURE(rv)) { 7528 _bcm_xgs3_l3_free_resource(unit); 7529 return rv; 7530 } 7531 7532 /* Tunnels initiator table init. */ 7533 rv = _bcm_xgs3_l3_tnl_initiator_init(unit); 7534 if (BCM_FAILURE(rv)) { 7535 _bcm_xgs3_l3_free_resource(unit); 7536 return rv; 7537 } 7538 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 7539 #if defined(BCM_TOMAHAWK3_SUPPORT) 7540 rv = _bcm_tnl_port_bitmap_profile_init(unit); 7541 if (BCM_FAILURE(rv)) { 7542 _bcm_xgs3_l3_free_resource(unit); 7543 return rv; 7544 } 7545 #endif 7546 } 7547 7548 #if defined(BCM_TRIDENT3_SUPPORT) 7549 if (SOC_IS_TRIDENT3X(unit)) { 7550 rv = _bcm_td3_tunnel_default_vlan_profile_init(unit); 7551 if (BCM_FAILURE(rv)) { 7552 _bcm_xgs3_l3_free_resource(unit); 7553 return rv; 7554 } 7555 } 7556 #endif 7557 7558 } else { /* !SOC_IS_HURRICANE && !SOC_IS_GREYHOUND */ 7559 if (soc_feature(unit, soc_feature_vxlan_lite)) { 7560 /* Tunnels initiator table init. */ 7561 rv = _bcm_xgs3_l3_tnl_initiator_init(unit); 7562 if (BCM_FAILURE(rv)) { 7563 _bcm_xgs3_l3_free_resource(unit); 7564 return rv; 7565 } 7566 } 7567 } 7568 7569 /* Tunnels dscp table init. */ 7570 rv = _bcm_xgs3_l3_tnl_dscp_init(unit); 7571 if (BCM_FAILURE(rv)) { 7572 _bcm_xgs3_l3_free_resource(unit); 7573 return rv; 7574 } 7575 7576 /* Adjacent mac table init. */ 7577 rv = _bcm_xgs3_l3_adj_mac_init(unit); 7578 if (BCM_FAILURE(rv)) { 7579 _bcm_xgs3_l3_free_resource(unit); 7580 return rv; 7581 } 7582 7583 /* Reset auxiliary counters. */ 7584 BCM_XGS3_L3_CNTRS_RESET(unit); 7585 7586 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 7587 defined(BCM_HAWKEYE_SUPPORT) 7588 if (soc_feature(unit, soc_feature_fp_based_routing)) { 7589 rv = _bcm_rp_l3_init(unit); 7590 if (BCM_FAILURE(rv)) { 7591 _bcm_xgs3_l3_free_resource(unit); 7592 return rv; 7593 } 7594 } 7595 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 7596 7597 /* Reserve BLACK_HOLE entry to Drop packets */ 7598 rv = _bcm_xgs3_l3_black_hole_nh_setup(unit); 7599 if (BCM_FAILURE(rv)) { 7600 _bcm_xgs3_l3_free_resource(unit); 7601 return rv; 7602 } 7603 7604 /* 7605 * Reserve the entry in L3 NextHop table to L2 switch packet CPU 7606 */ 7607 rv = _bcm_xgs3_l3_l2cpu_nh_setup(unit); 7608 if (BCM_FAILURE(rv)) { 7609 _bcm_xgs3_l3_free_resource(unit); 7610 return rv; 7611 } 7612 7613 /* Register a call back function to update modid */ 7614 rv = soc_event_register(unit, _bcm_xgs3_l3_l2cpu_nh_cb, NULL); 7615 if (BCM_FAILURE(rv)) { 7616 _bcm_xgs3_l3_free_resource(unit); 7617 return rv; 7618 } 7619 7620 #if defined(BCM_TRX_SUPPORT) 7621 if (soc_feature(unit, soc_feature_virtual_switching)) { 7622 rv = _bcm_virtual_init(unit, SOURCE_VPm, VFIm); 7623 if (BCM_FAILURE(rv)) { 7624 _bcm_xgs3_l3_free_resource(unit); 7625 return rv; 7626 } 7627 } 7628 #endif /* BCM_TRX_SUPPORT */ 7629 7630 #if defined(BCM_TRIDENT_SUPPORT) 7631 if (SOC_IS_TRIDENT(unit) 7632 #if defined(BCM_TRIDENT2_SUPPORT) 7633 || SOC_IS_TRIDENT2X(unit) 7634 #endif 7635 || SOC_IS_TOMAHAWKX(unit) 7636 #if defined(BCM_TRIDENT3_SUPPORT) 7637 || SOC_IS_TRIDENT3X(unit) 7638 #endif 7639 ) { 7640 rv = _bcm_td_l3_routed_int_pri_init(unit); 7641 if (BCM_FAILURE(rv)) { 7642 _bcm_xgs3_l3_free_resource(unit); 7643 return rv; 7644 } 7645 } 7646 #endif /* BCM_TRIDENT_SUPPORT */ 7647 7648 #if defined(BCM_TRIUMPH3_SUPPORT) 7649 if (SOC_IS_TRIUMPH3(unit)) { 7650 if (BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 7651 rv = _bcm_tr3_esm_host_tbl_init(unit); 7652 if (BCM_FAILURE(rv)) { 7653 _bcm_xgs3_l3_free_resource(unit); 7654 return rv; 7655 } 7656 } 7657 rv = _bcm_td_l3_routed_int_pri_init(unit); 7658 if (BCM_FAILURE(rv)) { 7659 _bcm_xgs3_l3_free_resource(unit); 7660 return rv; 7661 } 7662 } 7663 #endif /* BCM_TRIUMPH3_SUPPORT */ 7664 7665 #if defined(BCM_TOMAHAWK_SUPPORT) 7666 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 7667 rv = _bcm_th_macda_oui_profile_init(unit); 7668 if (BCM_FAILURE(rv)) { 7669 _bcm_th_macda_oui_profile_deinit(unit); 7670 _bcm_xgs3_l3_free_resource(unit); 7671 return rv; 7672 } 7673 rv = _bcm_th_vntag_etag_profile_init(unit); 7674 if (BCM_FAILURE(rv)) { 7675 _bcm_th_vntag_etag_profile_deinit(unit); 7676 _bcm_xgs3_l3_free_resource(unit); 7677 return rv; 7678 } 7679 } 7680 #endif /* BCM_TOMAHAWK_SUPPORT */ 7681 7682 #if defined(BCM_RIOT_SUPPORT) 7683 if (soc_feature(unit, soc_feature_riot)) { 7684 rv = _bcm_td2p_macda_oui_profile_init(unit); 7685 if (BCM_FAILURE(rv)) { 7686 _bcm_xgs3_l3_free_resource(unit); 7687 return rv; 7688 } 7689 } 7690 #endif /* BCM_RIOT_SUPPORT */ 7691 7692 #if defined(BCM_TRIDENT3_SUPPORT) && defined(BCM_WARM_BOOT_SUPPORT) 7693 if (soc_feature(unit, soc_feature_vfi_switched_l2_change_fields)) { 7694 if (SOC_WARM_BOOT(unit)) { 7695 rv = _bcm_td3_l2_change_fields_reinit(unit); 7696 if (BCM_FAILURE(rv)) { 7697 return rv; 7698 } 7699 } 7700 } 7701 #endif 7702 /* Set "resources allocated" flag. */ 7703 BCM_XGS3_L3_INITIALIZED(unit) = TRUE; 7704 7705 /* Enable routing on all ports. */ 7706 rv = bcm_xgs3_l3_enable(unit, TRUE); 7707 if (BCM_FAILURE(rv)) { 7708 _bcm_xgs3_l3_free_resource(unit); 7709 return rv; 7710 } 7711 #ifdef BCM_TRIDENT3_SUPPORT 7712 sal_memset(ecmp_grp_enhanced_hashing[unit], 0, 4096); 7713 #endif 7714 7715 return (BCM_E_NONE); 7716 } 7717 7718 /* 7719 * Function: 7720 * bcm_xgs3_l3_tables_cleanup 7721 * Purpose: 7722 * Disable L3 functionality and cleanup internal L3 tables. 7723 * Parameters: 7724 * unit - SOC unit number. 7725 * Returns: 7726 * BCM_E_XXX. 7727 */ 7728 int 7729 bcm_xgs3_l3_tables_cleanup(int unit) 7730 { 7731 /* Disable routing on all ports. */ 7732 if (0 == SOC_HW_ACCESS_DISABLE(unit)) { 7733 bcm_xgs3_l3_enable(unit, FALSE); 7734 } 7735 7736 7737 /* Free allocated resources. */ 7738 if (BCM_XGS3_L3_INITIALIZED(unit)) { 7739 _bcm_xgs3_l3_free_resource(unit); 7740 7741 /* Reset auxiliary counters. */ 7742 BCM_XGS3_L3_CNTRS_RESET(unit); 7743 7744 BCM_XGS3_L3_INITIALIZED(unit) = FALSE; 7745 7746 /* Unregister call back function */ 7747 soc_event_unregister(unit, _bcm_xgs3_l3_l2cpu_nh_cb, NULL); 7748 } 7749 return (BCM_E_NONE); 7750 } 7751 7752 7753 7754 /* 7755 * Function: 7756 * bcm_xgs3_l3_intf_get 7757 * Purpose: 7758 * Get an entry from L3 interface table. 7759 * Parameters: 7760 * unit - SOC unit number. 7761 * intf_info - Pointer to memory for interface information. 7762 * Returns: 7763 * BCM_E_XXX 7764 */ 7765 int 7766 bcm_xgs3_l3_intf_get(int unit, _bcm_l3_intf_cfg_t *intf_info) 7767 { 7768 bcm_l2_addr_t l2_addr; /* Layer 2 address for interface. */ 7769 int rv; 7770 7771 /* Make sure module was initialized. */ 7772 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 7773 return (BCM_E_INIT); 7774 } 7775 7776 /* Input parameters check. */ 7777 if (NULL == intf_info) { 7778 return (BCM_E_PARAM); 7779 } 7780 7781 /* Make sure ifindex is valid & interface is used. */ 7782 if (intf_info->l3i_index >= BCM_XGS3_L3_IF_TBL_SIZE(unit) || 7783 !BCM_L3_INTF_USED_GET(unit, intf_info->l3i_index)) { 7784 return (BCM_E_NOT_FOUND); 7785 } 7786 7787 /* Make sure hw call pointer was initialized. */ 7788 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 7789 return (BCM_E_UNAVAIL); 7790 } 7791 7792 /* Read interface from hardware. */ 7793 BCM_XGS3_L3_MODULE_LOCK(unit); 7794 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, intf_info); 7795 BCM_XGS3_L3_MODULE_UNLOCK(unit); 7796 BCM_IF_ERROR_RETURN(rv); 7797 7798 /* Restore 'BCM_L3_ADD_TO_ARL' flag if found in L2/MY_STATION tables */ 7799 bcm_l2_addr_t_init(&l2_addr, intf_info->l3i_mac_addr, intf_info->l3i_vid); 7800 if (BCM_E_NONE == bcm_esw_l2_addr_get(unit, intf_info->l3i_mac_addr, 7801 intf_info->l3i_vid, &l2_addr)) { 7802 if (l2_addr.flags & BCM_L2_L3LOOKUP) { 7803 intf_info->l3i_flags |= BCM_L3_ADD_TO_ARL; 7804 } 7805 } 7806 7807 /* Read vrf info from hardware. */ 7808 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_get)) { 7809 7810 BCM_XGS3_L3_MODULE_LOCK(unit); 7811 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_get) (unit, intf_info); 7812 BCM_XGS3_L3_MODULE_UNLOCK(unit); 7813 BCM_IF_ERROR_RETURN(rv); 7814 7815 } 7816 7817 /* Get interface group id . */ 7818 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_get)) { 7819 BCM_XGS3_L3_MODULE_LOCK(unit); 7820 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_get) (unit, intf_info); 7821 BCM_XGS3_L3_MODULE_UNLOCK(unit); 7822 BCM_IF_ERROR_RETURN(rv); 7823 } 7824 7825 return (BCM_E_NONE); 7826 } 7827 7828 /* 7829 * Function: 7830 * _bcm_xgs3_l3_intf_lookup 7831 * Purpose: 7832 * Get first entry from L3 interface table matching vlan id & mac. 7833 * Parameters: 7834 * unit - (IN)SOC unit number. 7835 * intf_info - (IN/OUT)Pointer to memory for interface information. 7836 * vid - (IN) Key vlan id. 7837 * mac - (IN) mac address. 7838 * Returns: 7839 * BCM_E_XXX 7840 */ 7841 int 7842 _bcm_xgs3_l3_intf_lookup(int unit, _bcm_l3_intf_cfg_t *intf_info, 7843 bcm_vlan_t vid, bcm_mac_t mac) 7844 { 7845 int idx; /* Iteration index. */ 7846 int max_lkup_cnt; /* Number of active interfaces, */ 7847 int index_min; /* First interface entry index. */ 7848 int index_max; /* Last interface entry index. */ 7849 int rv; 7850 _bcm_l3_intf_cfg_t intf_info_in; 7851 7852 /* Make sure hw call pointer was initialized. */ 7853 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 7854 return (BCM_E_UNAVAIL); 7855 } 7856 /* make a copy of input intf_info */ 7857 sal_memcpy(&intf_info_in, intf_info, sizeof(_bcm_l3_intf_cfg_t)); 7858 7859 /* Get interface table start & end index. */ 7860 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, intf)); 7861 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, intf)); 7862 7863 /* Don't iterate beyond number of active interfaces. */ 7864 max_lkup_cnt = BCM_XGS3_L3_IF_COUNT(unit); 7865 if (max_lkup_cnt <= 0) { 7866 return (BCM_E_NOT_FOUND); 7867 } 7868 7869 /* Loop over all valid interfaces. */ 7870 for (idx = index_min; idx <= index_max; idx++) { 7871 if (BCM_L3_INTF_USED_GET(unit, idx)) { 7872 /* Read interface from hardware. */ 7873 sal_memcpy(intf_info, &intf_info_in, sizeof(_bcm_l3_intf_cfg_t)); 7874 intf_info->l3i_index = idx; 7875 BCM_XGS3_L3_MODULE_LOCK(unit); 7876 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, intf_info); 7877 BCM_XGS3_L3_MODULE_UNLOCK(unit); 7878 BCM_IF_ERROR_RETURN(rv); 7879 7880 /* Check for match. */ 7881 if (intf_info->l3i_vid == vid) { 7882 /* Search by VID only. */ 7883 if (NULL == mac) { 7884 break; 7885 } 7886 /* Search by MAC & VID */ 7887 if (sal_memcmp(mac, intf_info->l3i_mac_addr, 7888 sizeof(bcm_mac_t)) == 0) { 7889 break; 7890 } /* Mac match. */ 7891 } 7892 /* Vid match. */ 7893 /* Decrement number of interface to search. */ 7894 max_lkup_cnt--; 7895 if (!max_lkup_cnt) { 7896 break; 7897 } 7898 } /* Interface is active. */ 7899 } /* Loop over interface table. */ 7900 7901 if (!max_lkup_cnt || (idx == BCM_XGS3_L3_IF_TBL_SIZE(unit))) { 7902 return (BCM_E_NOT_FOUND); 7903 } 7904 7905 /* Get vrf info if available. */ 7906 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_get)) { 7907 BCM_XGS3_L3_MODULE_LOCK(unit); 7908 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_get) (unit, intf_info); 7909 BCM_XGS3_L3_MODULE_UNLOCK(unit); 7910 BCM_IF_ERROR_RETURN(rv); 7911 } 7912 return (BCM_E_NONE); 7913 } 7914 7915 /* 7916 * Function: 7917 * bcm_xgs3_l3_intf_get_by_vid 7918 * Purpose: 7919 * Get first entry from L3 interface table matching vlan id. 7920 * Parameters: 7921 * unit - (IN)SOC unit number. 7922 * intf_info - (IN/OUT)Pointer to memory for interface information. 7923 * Returns: 7924 * BCM_E_XXX 7925 */ 7926 int 7927 bcm_xgs3_l3_intf_get_by_vid(int unit, _bcm_l3_intf_cfg_t *intf_info) 7928 { 7929 /* Make sure module was initialized. */ 7930 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 7931 return (BCM_E_INIT); 7932 } 7933 7934 /* Input parameters check. */ 7935 if (NULL == intf_info) { 7936 return (BCM_E_PARAM); 7937 } 7938 /* Perform lookup by VID. */ 7939 return _bcm_xgs3_l3_intf_lookup(unit, intf_info, intf_info->l3i_vid, NULL); 7940 } 7941 7942 7943 /* 7944 * Function: 7945 * _bcm_xgs3_l3_intf_l2_addr_set 7946 * Purpose: 7947 * Set interface mac address in l2 table. 7948 * Parameters: 7949 * unit - (IN) SOC unit number. 7950 * intf_info - (IN) Interface information. 7951 * Returns: 7952 * BCM_E_XXX 7953 */ 7954 STATIC int 7955 _bcm_xgs3_l3_intf_l2_addr_set(int unit, _bcm_l3_intf_cfg_t *intf_info) 7956 { 7957 bcm_l2_addr_t l2addr; /* Layer 2 address for interface. */ 7958 int rv = BCM_E_NONE; /* Operation return status. */ 7959 7960 /* Set l2 address info. */ 7961 bcm_l2_addr_t_init(&l2addr, intf_info->l3i_mac_addr, intf_info->l3i_vid); 7962 7963 #if defined(BCM_MIRAGE_SUPPORT) 7964 if (soc_feature(unit, soc_feature_fp_routing_mirage)) { 7965 /* Set l2 entry flags. */ 7966 l2addr.flags = BCM_L2_STATIC | BCM_L2_REPLACE_DYNAMIC; 7967 7968 /* Set l2 entry port to CPU port. */ 7969 l2addr.port = BCM_MIRAGE_L3_PORT; 7970 } else 7971 #endif /* BCM_MIRAGE_SUPPORT */ 7972 { 7973 /* Set l2 entry flags. */ 7974 l2addr.flags = BCM_L2_L3LOOKUP | BCM_L2_STATIC | BCM_L2_REPLACE_DYNAMIC; 7975 7976 /* Set l2 entry port to CPU port. */ 7977 l2addr.port = CMIC_PORT(unit); 7978 } 7979 7980 /* Set l2 entry module id to local module. */ 7981 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &l2addr.modid)); 7982 7983 /* Overwrite existing entry if any. */ 7984 bcm_esw_l2_addr_delete(unit, intf_info->l3i_mac_addr, intf_info->l3i_vid); 7985 7986 /* Add entry to l2 table. */ 7987 rv = bcm_esw_l2_addr_add(unit, &l2addr); 7988 7989 /* Set mac address installed indicator. */ 7990 if (rv == BCM_E_NONE) { 7991 BCM_L3_INTF_ARL_SET(unit, intf_info->l3i_index); 7992 } 7993 return rv; 7994 } 7995 7996 /* 7997 * Function: 7998 * _bcm_xgs3_l3_intf_create 7999 * Purpose: 8000 * Create l3 interface. 8001 * Parameters: 8002 * unit - (IN) SOC unit number. 8003 * intf_info - (IN) Interface information. 8004 * Returns: 8005 * BCM_E_XXX 8006 */ 8007 8008 STATIC int 8009 _bcm_xgs3_l3_intf_create(int unit, _bcm_l3_intf_cfg_t *intf_info) 8010 { 8011 int rv, rv1; 8012 int ingress_map_mode = 0; 8013 int inc_vlan_vrf_ref_count = FALSE; 8014 8015 /* Add interface to hardware. */ 8016 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_add)) { 8017 BCM_XGS3_L3_MODULE_LOCK(unit); 8018 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_add) (unit, intf_info); 8019 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8020 BCM_IF_ERROR_RETURN(rv); 8021 } 8022 8023 /* Write to interface group table. */ 8024 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_set)) { 8025 BCM_XGS3_L3_MODULE_LOCK(unit); 8026 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_set) (unit, intf_info); 8027 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8028 BCM_IF_ERROR_RETURN(rv); 8029 } 8030 8031 /* Set VRF_VFI table for primary interfaces. */ 8032 if ((!(intf_info->l3i_flags & BCM_L3_SECONDARY)) && 8033 (intf_info->l3i_vrf != BCM_L3_VRF_INVALID)) { 8034 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_bind)) { 8035 BCM_XGS3_L3_MODULE_LOCK(unit); 8036 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_bind) (unit, intf_info); 8037 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8038 BCM_IF_ERROR_RETURN(rv); 8039 inc_vlan_vrf_ref_count = TRUE; 8040 } 8041 } 8042 8043 #if defined(BCM_TRIDENT2_SUPPORT) 8044 if (soc_feature(unit, soc_feature_nat) 8045 #ifdef BCM_RIOT_SUPPORT 8046 && (!(BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid))) 8047 #endif 8048 ) { 8049 rv = _bcm_fb_l3_intf_nat_realm_id_set(unit, intf_info); 8050 BCM_IF_ERROR_RETURN(rv); 8051 8052 if (intf_info->l3i_flags & BCM_L3_SRC_DST_NAT_REALM_ID) { 8053 BCM_IF_ERROR_RETURN( 8054 _bcm_td2_nh_nat_id_update_by_l3_intf( 8055 unit, intf_info->l3i_index, intf_info->l3i_nat_realm_id)); 8056 } 8057 } 8058 8059 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit) && 8060 BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit))) { 8061 if (soc_feature(unit, soc_feature_l3_ip4_options_profile) 8062 #ifdef BCM_RIOT_SUPPORT 8063 && (!(BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid))) 8064 #endif 8065 ) { 8066 rv = _bcm_td2_l3_iif_ip4_options_profile_index_set(unit, intf_info); 8067 BCM_IF_ERROR_RETURN(rv); 8068 } 8069 } 8070 #endif 8071 #if defined(BCM_TRIUMPH_SUPPORT) 8072 /* Check if L3 Ingress Interface mode not set */ 8073 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 8074 if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, ALLOW_GLOBAL_ROUTEf) && 8075 intf_info->l3i_vid != 0) { 8076 /* Check if L3 Ingress Interface Map mode not set */ 8077 if (!(BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit))) { 8078 rv = _bcm_tr_l3_intf_global_route_enable_set(unit, 8079 intf_info->l3i_vid, 8080 1); 8081 BCM_IF_ERROR_RETURN(rv); 8082 } 8083 } 8084 } 8085 #endif /* BCM_TRIUMPH_SUPPORT */ 8086 8087 /* Add interface layer 2 address if required. */ 8088 if (intf_info->l3i_flags & BCM_L3_ADD_TO_ARL) { 8089 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL)) { 8090 LOG_ERROR(BSL_LS_BCM_L3, 8091 (BSL_META_U(unit, 8092 "Use of BCM_L3_ADD_TO_ARL flag is not allowed in l3 intf create \n"))); 8093 return BCM_E_CONFIG; 8094 } 8095 rv = _bcm_xgs3_l3_intf_l2_addr_set(unit, intf_info); 8096 8097 if (BCM_FAILURE(rv)) { /* Add to ARL failed, cleanup L3 intf */ 8098 if ((!(intf_info->l3i_flags & BCM_L3_SECONDARY)) 8099 && (intf_info->l3i_vrf != BCM_L3_VRF_INVALID)) { 8100 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 8101 ing_intf), intf_info->l3i_vid)) { 8102 /* Ref count on VLAN VRF is zero, hence 8103 * Clear VRF_VFI table for primary interfaces. */ 8104 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_unbind)) { 8105 BCM_XGS3_L3_MODULE_LOCK(unit); 8106 rv1 = BCM_XGS3_L3_HWCALL_EXEC(unit, 8107 if_vrf_unbind) (unit, intf_info); 8108 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8109 BCM_IF_ERROR_RETURN(rv1); 8110 } 8111 } 8112 } 8113 8114 /* Clear ingress & egress filter interface group table. */ 8115 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_set)) { 8116 intf_info->l3i_group = 0; 8117 BCM_XGS3_L3_MODULE_LOCK(unit); 8118 rv1 = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_set) (unit, intf_info); 8119 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8120 BCM_IF_ERROR_RETURN(rv1); 8121 } 8122 8123 /* Remove the interface. */ 8124 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_del)) { 8125 BCM_XGS3_L3_MODULE_LOCK(unit); 8126 rv1 = BCM_XGS3_L3_HWCALL_EXEC(unit, if_del) (unit, intf_info->l3i_index); 8127 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8128 BCM_IF_ERROR_RETURN(rv1); 8129 } 8130 8131 return rv; 8132 } 8133 } 8134 8135 /* Mark interface "inuse" in bitmap. */ 8136 if (!BCM_L3_INTF_USED_GET(unit, intf_info->l3i_index)) { 8137 BCM_L3_INTF_USED_SET(unit, intf_info->l3i_index); 8138 } 8139 8140 if (inc_vlan_vrf_ref_count) { 8141 #ifdef BCM_TRIUMPH_SUPPORT 8142 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 8143 BCM_IF_ERROR_RETURN 8144 (bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode)); 8145 } 8146 #endif 8147 if (!ingress_map_mode || 8148 SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) { 8149 /* Increment ref count on related VLAN VRF here */ 8150 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ing_intf), 8151 intf_info->l3i_vid, _BCM_SINGLE_WIDE); 8152 } 8153 } 8154 return (BCM_E_NONE); 8155 } 8156 8157 /* 8158 * Function: 8159 * _bcm_xgs3_egress_l3_intf_id_free 8160 * Purpose: 8161 * Free egress l3 interface id. 8162 * Parameters: 8163 * unit - (IN) SOC unit number. 8164 * id - (IN) Interface id 8165 * Returns: 8166 * BCM_E_XXX 8167 */ 8168 int 8169 _bcm_xgs3_egress_l3_intf_id_free(int unit, int id) 8170 { 8171 /* Input parameters check. */ 8172 if ((id < 0) || (id >= BCM_XGS3_L3_IF_TBL_SIZE(unit))) { 8173 return (BCM_E_PARAM); 8174 } 8175 8176 /* Free interface index. */ 8177 L3_LOCK(unit); 8178 BCM_L3_INTF_USED_CLR(unit, id); 8179 L3_UNLOCK(unit); 8180 8181 return (BCM_E_NONE); 8182 } 8183 8184 /* 8185 * Function: 8186 * _bcm_xgs3_egress_l3_intf_id_alloc 8187 * Purpose: 8188 * Allocate egress l3 interface id. 8189 * Parameters: 8190 * unit - (IN) SOC unit number. 8191 * id - (OUT) Allocated interface id 8192 * Returns: 8193 * BCM_E_XXX 8194 */ 8195 int 8196 _bcm_xgs3_egress_l3_intf_id_alloc(int unit, _bcm_l3_intf_cfg_t *intf_info) 8197 { 8198 int idx; /* Iteration index. */ 8199 int min_idx, max_idx; 8200 _bcm_l3_tbl_t *tbl_ptr; /* L3 egress intf table pointer. */ 8201 #ifdef BCM_RIOT_SUPPORT 8202 _bcm_l3_bookkeeping_t *l3_bk = L3_INFO(unit); 8203 #endif 8204 8205 /* get minimum and max values from table pointer. */ 8206 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf); 8207 8208 /* Input parameters check. */ 8209 if (NULL == intf_info) { 8210 return (BCM_E_PARAM); 8211 } 8212 8213 /* Make sure module was initialized. */ 8214 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 8215 return (BCM_E_INIT); 8216 } 8217 8218 #ifdef BCM_RIOT_SUPPORT 8219 if (BCMI_L3_INTF_OVERLAY_VALID(unit)) { 8220 if (l3_bk->l3_intf_overlay_alloc_mode > 0) { 8221 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 8222 min_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries + 1; 8223 max_idx = tbl_ptr->idx_max; 8224 } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) { 8225 min_idx = tbl_ptr->idx_min; 8226 max_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries; 8227 } else { 8228 return BCM_E_PARAM; 8229 } 8230 } else { 8231 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 8232 min_idx = tbl_ptr->idx_min; 8233 max_idx = l3_bk->l3_intf_overlay_entries -1; 8234 } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) { 8235 min_idx = l3_bk->l3_intf_overlay_entries; 8236 max_idx = tbl_ptr->idx_max; 8237 } else { 8238 return BCM_E_PARAM; 8239 } 8240 } 8241 } else if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 8242 LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit, 8243 "VFI is sent without allocating overlay interface memory size\n"))); 8244 8245 return (BCM_E_PARAM); 8246 } else 8247 #endif 8248 { 8249 min_idx = tbl_ptr->idx_min; 8250 max_idx = tbl_ptr->idx_max; 8251 } 8252 8253 L3_LOCK(unit); 8254 8255 /* Search for unused index. */ 8256 for (idx = min_idx; idx <= max_idx; idx++) { 8257 /* Skip cpu interface. */ 8258 if (idx == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) { 8259 continue; 8260 } 8261 8262 #ifdef BCM_TRIDENT2_SUPPORT 8263 if (idx == 0) { 8264 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit) && 8265 soc_feature(unit, soc_feature_l3_iif_zero_invalid)) { 8266 /* L3 egress interface ID 0 cannot be used if 8267 * both the following conditions are true: 8268 * (1) L3_INGRESS_INTF_MAP_MODE is set, enabling identical 8269 * mapping between L3 ingress interface and L3 egress 8270 * interface IDs. 8271 * (2) L3 ingress interface ID 0 cannot be used. 8272 */ 8273 continue; 8274 } 8275 } 8276 #endif /* BCM_TRIDENT2_SUPPORT */ 8277 8278 /* Check if interface index is used. */ 8279 if (!BCM_L3_INTF_USED_GET(unit, idx)) { 8280 /* Free index found. */ 8281 BCM_L3_INTF_USED_SET(unit, idx); 8282 intf_info->l3i_index = idx; 8283 break; 8284 } 8285 } 8286 8287 L3_UNLOCK(unit); 8288 8289 return (idx <= max_idx) ? BCM_E_NONE : BCM_E_FULL; 8290 } 8291 8292 8293 /* 8294 * Function: 8295 * bcm_xgs3_l3_intf_create 8296 * Purpose: 8297 * Create L3 interface 8298 * Parameters: 8299 * unit - (IN) SOC unit number. 8300 * intf_info - (IN) Interface information. 8301 * Returns: 8302 * BCM_E_XXX 8303 */ 8304 int 8305 bcm_xgs3_l3_intf_create(int unit, _bcm_l3_intf_cfg_t *intf_info) 8306 { 8307 int rv; /* Interface creation status. */ 8308 8309 /* Make sure module was initialized. */ 8310 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 8311 return (BCM_E_INIT); 8312 } 8313 8314 /* Input parameters check. */ 8315 if (NULL == intf_info) { 8316 return (BCM_E_PARAM); 8317 } 8318 8319 /* Make sure there are empty slots. */ 8320 if (BCM_XGS3_L3_IF_COUNT(unit) == BCM_XGS3_L3_IF_MAX_COUNT(unit)) { 8321 return (BCM_E_FULL); 8322 } 8323 8324 /* Allocate interface id. */ 8325 rv = _bcm_xgs3_egress_l3_intf_id_alloc(unit, intf_info); 8326 BCM_IF_ERROR_RETURN(rv); 8327 8328 /* Create interface */ 8329 rv = _bcm_xgs3_l3_intf_create(unit, intf_info); 8330 8331 if (BCM_FAILURE(rv)) { 8332 /* Unreserve interface id. */ 8333 BCM_IF_ERROR_RETURN(_bcm_xgs3_egress_l3_intf_id_free(unit, 8334 intf_info->l3i_index)); 8335 } 8336 8337 return rv; 8338 } 8339 8340 /* 8341 * Function: 8342 * bcm_xgs3_l3_intf_id_create 8343 * Purpose: 8344 * Create L3 interface with a specified index 8345 * Parameters: 8346 * unit - (IN) SOC unit number. 8347 * intf_info - (IN) Interface information. 8348 * Returns: 8349 * BCM_E_XXX 8350 */ 8351 int 8352 bcm_xgs3_l3_intf_id_create(int unit, _bcm_l3_intf_cfg_t *intf_info) 8353 { 8354 int min_idx, max_idx; 8355 _bcm_l3_tbl_t *tbl_ptr; 8356 #ifdef BCM_RIOT_SUPPORT 8357 _bcm_l3_bookkeeping_t *l3_bk = L3_INFO(unit); 8358 #endif 8359 /* Make sure module was initialized. */ 8360 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 8361 return (BCM_E_INIT); 8362 } 8363 8364 /* Input parameters check. */ 8365 if (NULL == intf_info) { 8366 return (BCM_E_PARAM); 8367 } 8368 8369 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf); 8370 8371 #ifdef BCM_RIOT_SUPPORT 8372 if (BCMI_L3_INTF_OVERLAY_VALID(unit)) { 8373 if (l3_bk->l3_intf_overlay_alloc_mode > 0) { 8374 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 8375 min_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries + 1; 8376 max_idx = tbl_ptr->idx_max; 8377 } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) { 8378 min_idx = tbl_ptr->idx_min; 8379 max_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries; 8380 } else { 8381 return BCM_E_PARAM; 8382 } 8383 } else { 8384 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 8385 min_idx = tbl_ptr->idx_min; 8386 max_idx = l3_bk->l3_intf_overlay_entries -1; 8387 } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) { 8388 min_idx = l3_bk->l3_intf_overlay_entries; 8389 max_idx = tbl_ptr->idx_max; 8390 } else { 8391 return BCM_E_PARAM; 8392 } 8393 } 8394 } else if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 8395 LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit, 8396 "VFI is sent without allocating overlay interface memory size\n"))); 8397 8398 return (BCM_E_PARAM); 8399 } else 8400 #endif 8401 { 8402 min_idx = tbl_ptr->idx_min; 8403 max_idx = tbl_ptr->idx_max; 8404 } 8405 /* Interface index sanity check. */ 8406 if ((intf_info->l3i_index < min_idx) || 8407 (intf_info->l3i_index > max_idx) || 8408 (intf_info->l3i_index == BCM_XGS3_L3_L2CPU_INTF_IDX(unit))) { 8409 return (BCM_E_PARAM); 8410 } 8411 8412 #ifdef BCM_TRIDENT2_SUPPORT 8413 if (intf_info->l3i_index == 0) { 8414 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit) && 8415 soc_feature(unit, soc_feature_l3_iif_zero_invalid)) { 8416 /* L3 egress interface ID 0 cannot be used if 8417 * both the following conditions are true: 8418 * (1) L3_INGRESS_INTF_MAP_MODE is set, enabling identical 8419 * mapping between L3 ingress interface and L3 egress 8420 * interface IDs. 8421 * (2) L3 ingress interface ID 0 cannot be used. 8422 */ 8423 return (BCM_E_PARAM); 8424 } 8425 } 8426 #endif /* BCM_TRIDENT2_SUPPORT */ 8427 8428 /* Create interface */ 8429 return _bcm_xgs3_l3_intf_create(unit, intf_info); 8430 } 8431 8432 /* 8433 * Function: 8434 * bcm_xgs3_l3_intf_lookup 8435 * Purpose: 8436 * See if an L3 interface exists by VID and MAC. 8437 * Parameters: 8438 * unit - (IN) SOC unit number. 8439 * intf_info - (IN) Interface information. 8440 * Returns: 8441 * BCM_E_NONE if entry exists and is found; 8442 * BCM_E_NOT_FOUND if the entry is not found. 8443 * Notes: 8444 * Returns the L3 interface info if found 8445 */ 8446 8447 int 8448 bcm_xgs3_l3_intf_lookup(int unit, _bcm_l3_intf_cfg_t *intf_info) 8449 { 8450 bcm_mac_t mac; /* Key mac. */ 8451 8452 /* Make sure module was initialized. */ 8453 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 8454 return (BCM_E_INIT); 8455 } 8456 8457 /* Input parameters check. */ 8458 if (NULL == intf_info) { 8459 return (BCM_E_PARAM); 8460 } 8461 8462 /* Set lookup key. */ 8463 sal_memcpy(mac, intf_info->l3i_mac_addr, sizeof(bcm_mac_t)); 8464 8465 /* Perform search by MAC & VID. */ 8466 return _bcm_xgs3_l3_intf_lookup(unit, intf_info, intf_info->l3i_vid, mac); 8467 8468 } 8469 8470 /* 8471 * Function: 8472 * bcm_xgs3_l3_intf_del 8473 * Purpose: 8474 * Delete L3 interface. 8475 * Parameters: 8476 * unit - (IN) SOC unit number. 8477 * intf_info - (IN) Interface information. 8478 * Returns: 8479 * BCM_E_XXX 8480 */ 8481 int 8482 bcm_xgs3_l3_intf_del(int unit, _bcm_l3_intf_cfg_t *intf_info) 8483 { 8484 int rv = BCM_E_UNAVAIL; /* Operation status. */ 8485 int first_error = BCM_E_NONE; /* First error occured. */ 8486 int ingress_map_mode = 0; 8487 #ifdef BCM_RIOT_SUPPORT 8488 soc_mem_t mem; /* Interface table memory. */ 8489 l3_max_entry_t l3_if_entry; /* Buffer to read interface info. */ 8490 uint32 *l3_if_entry_p; /* Interface read buffer address. */ 8491 int profiled_mac = 0; 8492 int macda_index = -1; 8493 #endif 8494 8495 /* Make sure module was initialized. */ 8496 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 8497 return (BCM_E_INIT); 8498 } 8499 8500 if (BCM_XGS3_L3_IF_COUNT(unit) == 0) { 8501 return (BCM_E_NOT_FOUND); 8502 } 8503 8504 8505 /* Verify interface index range. */ 8506 if ((intf_info->l3i_index < 0) || 8507 (intf_info->l3i_index >= BCM_XGS3_L3_IF_TBL_SIZE(unit))) { 8508 return (BCM_E_PARAM); 8509 } 8510 8511 /* Check that ifindex corresponds to an active interface. */ 8512 if (!BCM_L3_INTF_USED_GET(unit, intf_info->l3i_index)) { 8513 return (BCM_E_NOT_FOUND); 8514 } 8515 8516 /* Reserved interface entry, should not be touched. */ 8517 if (intf_info->l3i_index == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) { 8518 return (BCM_E_NONE); 8519 } 8520 8521 #ifdef BCM_RIOT_SUPPORT 8522 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) { 8523 /* Get interface table memory. */ 8524 mem = BCM_XGS3_L3_MEM(unit, intf); 8525 8526 /* Zero read buffer. */ 8527 l3_if_entry_p = (uint32 *)&l3_if_entry; 8528 sal_memset(l3_if_entry_p, 0, sizeof(l3_max_entry_t)); 8529 8530 /* Read interface table entry by index. */ 8531 BCM_IF_ERROR_RETURN 8532 (BCM_XGS3_MEM_READ (unit, mem, intf_info->l3i_index, l3_if_entry_p)); 8533 profiled_mac = soc_mem_field32_get(unit, mem, l3_if_entry_p, 8534 MAC_ADDRESS_OVERLAY_TYPEf); 8535 macda_index = soc_mem_field32_get(unit, mem, l3_if_entry_p, 8536 MAC_ADDRESS_PROFILE_IDXf); 8537 if ((profiled_mac) && (macda_index != -1)) { 8538 _bcm_mac_da_profile_entry_delete(unit, macda_index); 8539 } 8540 } 8541 #endif 8542 /* Get interface info. */ 8543 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 8544 BCM_XGS3_L3_MODULE_LOCK(unit); 8545 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, intf_info); 8546 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8547 } 8548 BCM_IF_ERROR_RETURN(rv); 8549 8550 /* Remove interface layer 2 address if required. */ 8551 if (BCM_L3_INTF_ARL_GET(unit, intf_info->l3i_index)) { 8552 rv = bcm_esw_l2_addr_delete(unit, intf_info->l3i_mac_addr, 8553 intf_info->l3i_vid); 8554 if ((rv < 0) && (first_error == BCM_E_NONE) && (rv != BCM_E_NOT_FOUND) ) { 8555 first_error = rv; 8556 } 8557 BCM_L3_INTF_ARL_CLR(unit, intf_info->l3i_index); 8558 } 8559 8560 /* Clear ingress & egress filter interface group table. */ 8561 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_set)) { 8562 intf_info->l3i_group = 0; 8563 BCM_XGS3_L3_MODULE_LOCK(unit); 8564 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_set) (unit, intf_info); 8565 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8566 if ((rv < 0) && (first_error == BCM_E_NONE)) { 8567 first_error = rv; 8568 } 8569 } 8570 8571 /* Remove the interface. */ 8572 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_del)) { 8573 BCM_XGS3_L3_MODULE_LOCK(unit); 8574 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_del) (unit, intf_info->l3i_index); 8575 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8576 if ((rv < 0) && (first_error == BCM_E_NONE)) { 8577 first_error = rv; 8578 } 8579 } 8580 8581 if (BCM_SUCCESS(first_error) && 8582 !(intf_info->l3i_flags & BCM_L3_SECONDARY)) { 8583 8584 /* Decrement ref count on VRF tied to this VLAN */ 8585 #ifdef BCM_TRIUMPH_SUPPORT 8586 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 8587 BCM_IF_ERROR_RETURN 8588 (bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode)); 8589 } 8590 #endif 8591 if (!ingress_map_mode || 8592 SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) { 8593 /* Decrement ref count on related VLAN VRF here */ 8594 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ing_intf), 8595 intf_info->l3i_vid, _BCM_SINGLE_WIDE); 8596 8597 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 8598 ing_intf), intf_info->l3i_vid)) { 8599 /* Ref count on related VLAN VRF is zero, so 8600 * clear VRF_VFI table for primary interfaces. */ 8601 if ((BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_unbind)) 8602 && (intf_info->l3i_vrf != BCM_L3_VRF_INVALID)) { 8603 BCM_XGS3_L3_MODULE_LOCK(unit); 8604 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_unbind) (unit, 8605 intf_info); 8606 BCM_XGS3_L3_MODULE_UNLOCK(unit); 8607 if ((rv < 0) && (first_error == BCM_E_NONE)) { 8608 first_error = rv; 8609 } 8610 } 8611 } 8612 } 8613 } 8614 8615 /* Unreserve interface id. */ 8616 rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf_info->l3i_index); 8617 return first_error; 8618 } 8619 8620 /* 8621 * Function: bcm_xgs3_l3_intf_del_all 8622 * Purpose: 8623 * Delete all L3 interfaces. 8624 * Parameters: 8625 * unit - (IN) SOC unit number. 8626 * Returns: 8627 * BCM_E_XXX 8628 */ 8629 int 8630 bcm_xgs3_l3_intf_del_all(int unit) 8631 { 8632 int idx; /* Interface index. */ 8633 _bcm_l3_intf_cfg_t intf; /* Interface info structure. */ 8634 int max_lkup_cnt; /* Number of active interfaces. */ 8635 8636 sal_memset(&intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 8637 8638 /* Make sure module was initialized. */ 8639 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 8640 return (BCM_E_INIT); 8641 } 8642 8643 /* Don't iterate beyond number of active interfaces. */ 8644 max_lkup_cnt = BCM_XGS3_L3_IF_COUNT(unit); 8645 if (max_lkup_cnt <= 0) { 8646 return (BCM_E_NONE); 8647 } 8648 8649 /* Iterate over all active interfaces. */ 8650 for (idx = 0; idx < BCM_XGS3_L3_IF_TBL_SIZE(unit); idx++) { 8651 if (BCM_L3_INTF_USED_GET(unit, idx)) { 8652 max_lkup_cnt--; 8653 if (!max_lkup_cnt) { 8654 break; 8655 } 8656 8657 /* Remove interface. */ 8658 intf.l3i_index = idx; 8659 BCM_IF_ERROR_RETURN(bcm_xgs3_l3_intf_del(unit, &intf)); 8660 } 8661 } 8662 return (BCM_E_NONE); 8663 } 8664 8665 /* 8666 * Function: 8667 * _bcm_xgs3_l3_flags_to_shr 8668 * Purpose: 8669 * Translate l3 specific flags to shared (table management) flags. 8670 * Parameters: 8671 * l3_flags - (IN) l3 table flags. 8672 * shr_flags - (OUT) Shared flags. 8673 * Returns: 8674 * BCM_E_XXX 8675 */ 8676 STATIC INLINE int 8677 _bcm_xgs3_l3_flags_to_shr(uint32 l3_flags, uint32 *shr_flags) 8678 { 8679 uint32 flag = 0; 8680 8681 if (NULL == shr_flags) { 8682 return (BCM_E_PARAM); 8683 } 8684 8685 if (l3_flags & BCM_L3_REPLACE) { 8686 flag |= _BCM_L3_SHR_UPDATE; 8687 } 8688 8689 if (l3_flags & BCM_L3_WITH_ID) { 8690 flag |= _BCM_L3_SHR_WITH_ID; 8691 } 8692 8693 *shr_flags = flag; 8694 8695 return (BCM_E_NONE); 8696 } 8697 8698 /* 8699 * Function: 8700 * _bcm_xgs3_l3_flags_to_egr_obj 8701 * Purpose: 8702 * Translate l3 specific flags to Egress Object flags. 8703 * Parameters: 8704 * l3_flags - (IN) l3 table flags. 8705 * egr_obj - (OUT) Egress Object 8706 * Returns: 8707 * BCM_E_XXX 8708 */ 8709 8710 STATIC INLINE int 8711 _bcm_xgs3_l3_flags_to_egr_obj (uint32 l3_flags, bcm_l3_egress_t *egr) 8712 { 8713 /* Input parameters check. */ 8714 if (NULL == egr) { 8715 return (BCM_E_PARAM); 8716 } 8717 8718 if (l3_flags & BCM_L3_KEEP_SRCMAC) { 8719 egr->flags |= BCM_L3_KEEP_SRCMAC; 8720 } 8721 8722 if (l3_flags & BCM_L3_KEEP_DSTMAC) { 8723 egr->flags |= BCM_L3_KEEP_DSTMAC; 8724 } 8725 8726 if (l3_flags & BCM_L3_KEEP_VLAN) { 8727 egr->flags |= BCM_L3_KEEP_VLAN; 8728 } 8729 8730 if (l3_flags & BCM_L3_KEEP_TTL) { 8731 egr->flags |= BCM_L3_KEEP_TTL; 8732 } 8733 8734 #ifdef BCM_GREYHOUND_SUPPORT 8735 /* Greyhound's L3 egress process need BCM_L3_IPMC for IPMC logic */ 8736 if (l3_flags & BCM_L3_IPMC) { 8737 egr->flags |= BCM_L3_IPMC; 8738 } 8739 #endif /* BCM_GREYHOUND_SUPPORT */ 8740 8741 return (BCM_E_NONE); 8742 8743 } 8744 8745 /* 8746 * Function: 8747 * _bcm_xgs3_tunnel_flags_to_shr 8748 * Purpose: 8749 * Translate tunnel specific flags to shared (table management) flags. 8750 * Parameters: 8751 * tnl_flags - (IN) Tunnel table flags. 8752 * shr_flags - (OUT) Shared flags. 8753 * Returns: 8754 * BCM_E_XXX 8755 */ 8756 STATIC INLINE int 8757 _bcm_xgs3_tunnel_flags_to_shr(uint32 tnl_flags, uint32 *shr_flags) 8758 { 8759 /* 8760 * Reserve entry Zero in EGR_IP_TUNNEL memory. This reserved entry 8761 * will not be allocated. The purpose of this entry is that 8762 * any interface which points to this entry will be treated 8763 * as a tunnel with no encapsulation or 'NO-protocol" tunnel. 8764 */ 8765 uint32 flag = _BCM_L3_SHR_SKIP_INDEX_ZERO; 8766 8767 if (NULL == shr_flags) { 8768 return (BCM_E_PARAM); 8769 } 8770 8771 if (tnl_flags & BCM_TUNNEL_REPLACE) { 8772 flag |= _BCM_L3_SHR_UPDATE; 8773 } 8774 8775 *shr_flags = flag; 8776 return (BCM_E_NONE); 8777 } 8778 8779 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 8780 /* 8781 * Function: 8782 * bcmi_xgs3_tbl_alloc_mode_get 8783 * Purpose: 8784 * get allocation configuration. 8785 * Parameters: 8786 * unit - (IN)SOC unit number. 8787 * data - (IN) Software table operation entry . 8788 * alloc_mode - (OUT) allocation mode. 8789 * Returns: 8790 * BCM_E_NONE 8791 */ 8792 STATIC int 8793 bcmi_xgs3_tbl_alloc_mode_get(int unit, _bcm_l3_tbl_op_t *data, 8794 int *alloc_mode) 8795 { 8796 #if defined(BCM_RIOT_SUPPORT) 8797 _bcm_l3_bookkeeping_t *l3_bk_info = &_bcm_l3_bk_info[unit]; 8798 #endif 8799 8800 *alloc_mode = 0; 8801 if ( BCM_XGS3_L3_TBL_PTR(unit, next_hop) == data->tbl_ptr) { 8802 #if defined(BCM_RIOT_SUPPORT) 8803 *alloc_mode = l3_bk_info->l3_nh_overlay_alloc_mode; 8804 #endif 8805 } 8806 8807 return BCM_E_NONE; 8808 } 8809 #endif 8810 8811 /* 8812 * Function: 8813 * bcmi_xgs3_tbl_idx_range_get 8814 * Purpose: 8815 * Generic table get range for table. 8816 * Parameters: 8817 * unit - (IN)SOC unit number. 8818 * idx_min - (OUT) ptr of min index. 8819 * idx_max - (OUT) ptr of max index. 8820 * used_idx - (OUT) ptr of used entries. 8821 * data - (IN/OUT) Software table operation entry . 8822 * Returns: 8823 * BCM_E_NONE 8824 */ 8825 8826 STATIC int 8827 bcmi_xgs3_tbl_idx_range_get(int unit, int *idx_min, int *idx_max, 8828 int **used_idx, _bcm_l3_tbl_op_t *data) 8829 { 8830 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 8831 #if defined(BCM_TRIDENT2_SUPPORT) 8832 _bcm_l3_bookkeeping_t *l3; 8833 #endif 8834 8835 tbl_ptr = data->tbl_ptr; 8836 /* Set up the limits for indexes */ 8837 *idx_min = tbl_ptr->idx_min; 8838 *idx_max = tbl_ptr->idx_max; 8839 *used_idx = &tbl_ptr->idx_maxused; 8840 #if defined(BCM_TRIDENT2_SUPPORT) 8841 l3 = &_bcm_l3_bk_info[unit]; 8842 if (l3->l3_nh_reserve_for_ecmp && 8843 (tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, next_hop))) { 8844 *idx_min = BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); 8845 } 8846 #endif 8847 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 8848 /* Set up indexes if there is split in table. 8849 * Overlay and underlay domains are configurable for some tables. 8850 * By default, overlay entry is allocated from lower portion of table. 8851 * If "alloc mode" is 1, overlay entry is allocated from higher 8852 * portion of table 8853 */ 8854 if (tbl_ptr->split_idx > 0) { 8855 int alloc_mode = 1; 8856 8857 bcmi_xgs3_tbl_alloc_mode_get(unit, data, &alloc_mode); 8858 if (alloc_mode) { 8859 if ((data->oper_flags & _BCM_L3_SHR_OVERLAY_OBJECT) ) { 8860 *idx_min = tbl_ptr->split_idx; 8861 } else { 8862 *idx_max = tbl_ptr->split_idx - 1; 8863 *used_idx = &tbl_ptr->split_maxused; 8864 } 8865 } else { 8866 if ((data->oper_flags & _BCM_L3_SHR_OVERLAY_OBJECT) ) { 8867 *idx_max = tbl_ptr->split_idx - 1; 8868 *used_idx = &tbl_ptr->split_maxused; 8869 } else { 8870 *idx_min = tbl_ptr->split_idx; 8871 } 8872 } 8873 } 8874 #endif 8875 8876 #if defined(BCM_TOMAHAWK_SUPPORT) 8877 if (soc_feature(unit, soc_feature_th_nh_no_overlap_ecmp) && 8878 (data->oper_flags & _BCM_L3_SHR_NO_ECMP_OVERLAP)) { 8879 /* SW WAR for IFP qualifier bcmFieldQualifyDstL3Egress 8880 Let NHI won't overlap ECMP indexes */ 8881 *idx_min = soc_mem_index_max(unit, L3_ECMP_COUNTm) + 1; 8882 } 8883 #endif /* BCM_TOMAHAWK_SUPPORT */ 8884 8885 return BCM_E_NONE; 8886 } 8887 8888 /* 8889 * Function: 8890 * _bcm_xgs3_tbl_free_idx_get 8891 * Purpose: 8892 * Generic table get unused table entry index. 8893 * Parameters: 8894 * unit - (IN)SOC unit number. 8895 * data - (IN/OUT) Software table operation entry . 8896 * Returns: 8897 * BCM_E_NONE - if free entry was found. 8898 * BCM_E_FULL - if no free entry found. 8899 */ 8900 int 8901 _bcm_xgs3_tbl_free_idx_get(int unit, _bcm_l3_tbl_op_t *data) 8902 { 8903 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 8904 int width; /* Entry width. */ 8905 int lkup_idx; /* Iteration index. */ 8906 int idx; /* Iteration index 2 */ 8907 int idx_min, idx_max, *maxused_idx; 8908 8909 tbl_ptr = data->tbl_ptr; 8910 width = data->width; 8911 8912 /* get range for min and max indexes */ 8913 bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, data); 8914 8915 if (!(data->oper_flags & _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL)) { 8916 /* Try to identify matching/free entry */ 8917 for (lkup_idx = idx_min; 8918 lkup_idx <= idx_max; lkup_idx += width) { 8919 8920 if (!lkup_idx && (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) { 8921 continue; 8922 } 8923 8924 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) { 8925 idx = width; 8926 while (--idx) { 8927 /* Check if free slots can accomodate wide entry. */ 8928 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx + idx)) { 8929 break; 8930 } 8931 } 8932 if (idx) { 8933 /* There is no room to accomodate wide entry. */ 8934 continue; 8935 } 8936 data->entry_index = lkup_idx; 8937 return (BCM_E_NONE); 8938 } 8939 } 8940 } else { 8941 for (lkup_idx = idx_min; 8942 lkup_idx <= idx_max; lkup_idx++) { 8943 8944 if (!lkup_idx && (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) { 8945 continue; 8946 } 8947 8948 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) { 8949 /* Check if a contiguous chunk of 'data.width' 8950 * entries are available starting from lkup_idx */ 8951 for (idx = lkup_idx; 8952 (idx < (lkup_idx + width)) && (idx <= idx_max); 8953 idx++) { 8954 8955 if(BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx)) { 8956 break; 8957 } 8958 } 8959 8960 if (idx == (lkup_idx + width)) { 8961 /* Empty slot with 'data.width' entries available */ 8962 data->entry_index = lkup_idx; 8963 return (BCM_E_NONE); 8964 } 8965 } 8966 } 8967 } 8968 return (BCM_E_FULL); 8969 } 8970 8971 /* 8972 * Function: 8973 * _bcm_xgs3_tbl_match 8974 * Purpose: 8975 * Generic table match routine. 8976 * Identify identical entry in the table if exists or return 8977 * first free entry available for write. 8978 * Parameters: 8979 * unit - (IN)SOC unit number. 8980 * data - (IN/OUT)Table entry operation info. 8981 * Returns: 8982 * BCM_E_NONE - if matching entry was found. 8983 * BCM_E_NOT_FOUND - if no matching entry found. 8984 * BCM_E_FULL - if no unused entry found. 8985 */ 8986 STATIC int 8987 _bcm_xgs3_tbl_match(int unit, _bcm_l3_tbl_op_t *data) 8988 { 8989 int lkup_idx = BCM_XGS3_L3_INVALID_INDEX; /* Iteration index. */ 8990 int unused_idx = BCM_XGS3_L3_INVALID_INDEX;/* Unused table index. */ 8991 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 8992 uint16 entry_hash; /* Entry hash. */ 8993 int cmp_result; /* Comparison result. */ 8994 int width; /* Entry width. */ 8995 int idx; /* Iteration index 2 */ 8996 int rv; /* Return status. */ 8997 int idx_min, idx_max, *maxused_idx; 8998 8999 tbl_ptr = data->tbl_ptr; 9000 width = data->width; 9001 9002 /* Calculate entry data hash. */ 9003 (*(data->hash_func)) (unit, data->entry_buffer, &entry_hash); 9004 /* get range for min and max indexes */ 9005 idx_min = tbl_ptr->idx_min; 9006 idx_max = tbl_ptr->idx_max; 9007 maxused_idx = &tbl_ptr->idx_maxused; 9008 9009 /* Try to identify matching/free entry */ 9010 for (lkup_idx = idx_min; 9011 lkup_idx <= *maxused_idx; lkup_idx += width) { 9012 9013 if (!lkup_idx && (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) { 9014 continue; 9015 } 9016 9017 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) { 9018 /* If entry is unused preserve free index. */ 9019 if (unused_idx == BCM_XGS3_L3_INVALID_INDEX) { 9020 idx = width; 9021 while (--idx) { 9022 /* Check if free slots can accomodate wide entry. */ 9023 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx + idx)) { 9024 break; 9025 } 9026 } 9027 if (idx) { 9028 /* There is no room to accomodate wide entry. */ 9029 continue; 9030 } 9031 unused_idx = lkup_idx; 9032 } 9033 continue; 9034 } 9035 9036 /* Compare valid entry hash(signature). */ 9037 if (!BCM_XGS3_L3_ENT_HASH_CMP(tbl_ptr, lkup_idx, entry_hash)) { 9038 continue; 9039 } 9040 9041 /* If hash matches compare the entry itself. */ 9042 rv = ((*(data->cmp_func))(unit, data->entry_buffer, 9043 lkup_idx, &cmp_result)); 9044 if (rv == BCM_E_NOT_FOUND) { 9045 continue; 9046 } else if (rv < 0) { 9047 return rv; 9048 } 9049 9050 /* Check comparison result. */ 9051 if (cmp_result == BCM_L3_CMP_EQUAL) { 9052 data->entry_index = lkup_idx; 9053 return (BCM_E_NONE); 9054 } 9055 } /* Loop over all the entries. */ 9056 9057 /* Return free entry if found. */ 9058 bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, data); 9059 9060 if (!((idx_min == tbl_ptr->idx_min) && (idx_max == tbl_ptr->idx_max))) { 9061 unused_idx = BCM_XGS3_L3_INVALID_INDEX; 9062 } 9063 if (BCM_XGS3_L3_INVALID_INDEX != unused_idx) { 9064 data->entry_index = unused_idx; 9065 } else { 9066 /* Set the lkup index so that it can get index from proper range. */ 9067 if ((idx_min == 0) && 9068 (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) { 9069 /* index 0 is reserved */ 9070 idx_min = idx_min + width; 9071 } 9072 lkup_idx = idx_min; 9073 9074 /* 9075 * If last entry in table is multi wide entry then maxused will point 9076 * to first index of multi wide entry. But rest of the indexes of 9077 * full entry are also ref-counted during ADD. Make sure that in 9078 * the next entry ADD, we dont return the index which is already used. 9079 */ 9080 while ((lkup_idx <= idx_max) && 9081 (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx))) { 9082 lkup_idx += width; 9083 } 9084 /* Check if we have run out of space for required entry width. */ 9085 if ((idx_max - lkup_idx) >= (width - 1)) { 9086 data->entry_index = lkup_idx; 9087 } else { 9088 return (BCM_E_FULL); 9089 } 9090 } 9091 return (BCM_E_NOT_FOUND); 9092 } 9093 9094 /* 9095 * Function: 9096 * _bcm_xgs3_tbl_add 9097 * Purpose: 9098 * Generic table add routine. 9099 * Allocate table index & write an entry to into it. 9100 * Routine trying to match new entry to an existing one, 9101 * if match found reference cound is incremented, otherwise 9102 * new index allocated & entry added to hw. 9103 * Parameters: 9104 * unit - (IN)SOC unit number. 9105 * data - (IN/OUT)Table entry operation info. 9106 * 9107 9108 * Returns: 9109 * BCM_E_XXX 9110 */ 9111 int 9112 _bcm_xgs3_tbl_add(int unit, _bcm_l3_tbl_op_t *data) 9113 { 9114 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 9115 int l3_match_disable; /* L3 match disable flag. */ 9116 uint16 entry_hash; /* Entry hash. */ 9117 int rv; /* Return status. */ 9118 int tmpidx; 9119 int idx_min, idx_max, *maxused_idx; 9120 #ifdef BCM_TOMAHAWK_SUPPORT 9121 _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL; 9122 #endif /* BCM_TOMAHAWK_SUPPORT */ 9123 9124 /* Input parameters check. */ 9125 if (NULL == data) { 9126 return (BCM_E_PARAM); 9127 } 9128 9129 if ((NULL == data->entry_buffer) || (NULL == data->tbl_ptr) || 9130 (NULL == data->hash_func) || (NULL == data->cmp_func) || 9131 (NULL == data->add_func)) { 9132 return (BCM_E_PARAM); 9133 } 9134 9135 tbl_ptr = data->tbl_ptr; 9136 /* Get l3 switch mode from module flags. */ 9137 l3_match_disable = data->oper_flags & _BCM_L3_SHR_MATCH_DISABLE; 9138 9139 /* Calculate entry data hash. */ 9140 (*(data->hash_func)) (unit, data->entry_buffer, &entry_hash); 9141 BCM_XGS3_L3_MODULE_LOCK(unit); 9142 /* get range for min and max indexes */ 9143 bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, data); 9144 9145 if(data->oper_flags & _BCM_L3_SHR_WITH_ID) { 9146 9147 /* Check index range */ 9148 if ((data->entry_index < idx_min) || 9149 (data->entry_index > idx_max)) { 9150 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9151 return (BCM_E_PARAM); 9152 } 9153 9154 /* Entry is currently used make sure replace flag is set. */ 9155 if (BCM_XGS3_L3_ENT_REF_CNT(data->tbl_ptr, data->entry_index)) { 9156 if (!(data->oper_flags & _BCM_L3_SHR_UPDATE)) { 9157 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9158 return (BCM_E_EXISTS); 9159 } 9160 } 9161 } else { 9162 if (l3_match_disable) { 9163 /* Get free index to write the entry. */ 9164 rv = _bcm_xgs3_tbl_free_idx_get(unit, data); 9165 if (BCM_FAILURE(rv)) { 9166 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9167 return rv; 9168 } 9169 9170 #ifdef BCM_TOMAHAWK3_SUPPORT 9171 /* When Tomahawk3 Failover with fixed egress nh offset is enable, 9172 all free allocated index (for primary nh) must be < prot_offset. 9173 Protected nh will be created by _BCM_L3_SHR_WITH_ID and 9174 egr->failover_id = _FAILOVER_FIXED_NH_OFFSET_ON */ 9175 if ((data->tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, next_hop)) && 9176 (FAILOVER_INFO(unit)->prot_offset > 0) && 9177 (data->entry_index >= FAILOVER_INFO(unit)->prot_offset)) { 9178 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9179 return BCM_E_FULL; /* primary nh index FULL */ 9180 } 9181 #endif 9182 9183 } else { 9184 /* Try to identify matching/free entry */ 9185 rv = _bcm_xgs3_tbl_match(unit, data); 9186 if ((rv < 0) && (BCM_E_NOT_FOUND != rv)) { 9187 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9188 return rv; 9189 } 9190 9191 /* If identical entry found -> just increment reference count */ 9192 if (BCM_E_NONE == rv) { 9193 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, data->entry_index, 9194 data->width); 9195 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9196 return (BCM_E_NONE); 9197 } 9198 } 9199 } 9200 9201 /* Update table maxused index. */ 9202 tmpidx = *maxused_idx; 9203 if (*maxused_idx < data->entry_index) { 9204 *maxused_idx = data->entry_index; 9205 } 9206 9207 #ifdef BCM_TOMAHAWK_SUPPORT 9208 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 9209 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 9210 ecmp_mode_hierarchical) && 9211 ((data->tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp)) 9212 #ifdef BCM_TOMAHAWK3_SUPPORT 9213 || (data->tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp)) 9214 #endif 9215 )) { 9216 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 9217 /* 9218 * In Hierarchical ECMP mode, ECMP groups in the 2nd half of group 9219 * table cannot have members in the first half of member table 9220 */ 9221 if ((data->entry_index >= (soc_mem_index_count(unit, L3_ECMP_COUNTm) / 2)) && 9222 (ecmp_tbl_ptr->idx_min == 0)) { 9223 ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1; 9224 } 9225 } 9226 #endif /* BCM_TOMAHAWK_SUPPORT */ 9227 9228 if (!(data->oper_flags & _BCM_L3_SHR_WRITE_DISABLE)) { 9229 /* Set the entry to hw. */ 9230 9231 rv = (*(data->add_func)) (unit, data->entry_index, data->entry_buffer, data->info); 9232 9233 if (rv < 0) { 9234 *maxused_idx = tmpidx; 9235 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9236 return rv; 9237 } 9238 } 9239 9240 if ((data->oper_flags & _BCM_L3_SHR_WITH_ID) && (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, data->entry_index) > 1)) { 9241 /* Update hash */ 9242 BCM_XGS3_L3_ENT_HASH_UPDATE(tbl_ptr, data->entry_index, data->width, entry_hash); 9243 } else { 9244 /* Update hash & reference count info. */ 9245 BCM_XGS3_L3_ENT_INIT(tbl_ptr, data->entry_index, data->width, entry_hash); 9246 } 9247 9248 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9249 return (BCM_E_NONE); 9250 } 9251 9252 9253 void 9254 _bcm_xgs3_nh_ref_cnt_incr(int unit, unsigned idx) 9255 { 9256 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, next_hop), 9257 idx, _BCM_SINGLE_WIDE); 9258 } 9259 9260 void 9261 _bcm_xgs3_nh_ref_cnt_get(int unit, uint32 idx, int ecmp, uint32 *ref_count) 9262 { 9263 /* 9264 * By default, when an egress object is created, the reference count will be 9265 * 1 to indicate that the entry is valid. So, when this object is referenced 9266 * by a route, the ref count shall be increemented. So, 1 is decremented 9267 * here 9268 */ 9269 9270 if (ecmp != 0) { 9271 #ifdef BCM_TOMAHAWK3_SUPPORT 9272 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 9273 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 9274 ecmp_mode_hierarchical) && 9275 (idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 9276 *ref_count = 9277 BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), 9278 idx) - 1; 9279 } else 9280 #endif 9281 { 9282 *ref_count = 9283 BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), 9284 idx) - 1; 9285 } 9286 } else { 9287 *ref_count = 9288 BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop), 9289 idx) - 1; 9290 } 9291 } 9292 9293 9294 /* 9295 * Function: 9296 * _bcm_xgs3_tbl_del 9297 * Purpose: 9298 * Generic table delete routine. 9299 * Entry kept if reference counter is not equal to 1 (other 9300 * instances still reference the same entry). 9301 * Parameters: 9302 * unit - (IN)SOC unit number. 9303 * data - (IN/OUT)Table entry operation info. 9304 * 9305 * Returns: 9306 * BCM_E_XXX 9307 */ 9308 int 9309 _bcm_xgs3_tbl_del(int unit, _bcm_l3_tbl_op_t *data) 9310 { 9311 int index; /* Temp index. */ 9312 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 9313 int idx_min, *maxused_idx; 9314 9315 /* Input parameters check. */ 9316 if (NULL == data) { 9317 return (BCM_E_PARAM); 9318 } 9319 9320 if (NULL == data->delete_func) { 9321 return (BCM_E_PARAM); 9322 } 9323 9324 tbl_ptr = data->tbl_ptr; 9325 /* Set up the limits for indexes */ 9326 idx_min = tbl_ptr->idx_min; 9327 maxused_idx = &tbl_ptr->idx_maxused; 9328 9329 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 9330 if ((tbl_ptr->split_idx > 0)) { 9331 if ((data->entry_index < tbl_ptr->split_idx)) { 9332 maxused_idx = &tbl_ptr->split_maxused; 9333 } else { 9334 idx_min = tbl_ptr->split_idx; 9335 } 9336 } 9337 #endif 9338 9339 /* Preserve next hop index */ 9340 index = data->entry_index; 9341 /* Check index sanity. */ 9342 if ((index < idx_min) || (index > tbl_ptr->idx_max)) { 9343 return (BCM_E_NONE); 9344 } 9345 9346 /* If entry is not currently used return. */ 9347 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, index)) { 9348 return (BCM_E_NONE); 9349 } 9350 9351 /* if not just clean but also need to delete entry, handle ref count */ 9352 if (!(data->oper_flags & _BCM_L3_SHR_CLEAN)) { 9353 /* If entry used by other hosts/routes just decrement ref count. */ 9354 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, index) > 1) { 9355 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, index, data->width); 9356 return (BCM_E_NONE); 9357 } 9358 9359 /* Use count is exactly one, remove the entry. */ 9360 9361 /* Reset entry usecount & hash. */ 9362 BCM_XGS3_L3_ENT_RESET(tbl_ptr, index, data->width); 9363 9364 /* Back up idx_maxused if needed. */ 9365 if (index == *maxused_idx) { 9366 while ((!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, index)) && 9367 index > idx_min) { 9368 index -= 1; 9369 } 9370 *maxused_idx = index; 9371 } 9372 } 9373 9374 if (data->oper_flags & _BCM_L3_SHR_WRITE_DISABLE) { 9375 return (BCM_E_NONE); 9376 } 9377 9378 return (*(data->delete_func)) (unit, data->entry_index, data->info); 9379 } 9380 9381 /* 9382 * Function: 9383 * bcm_xgs3_nh_get 9384 * Purpose: 9385 * Parameters: 9386 * unit - (IN)SOC unit number. 9387 * nh_idx - (IN)Next hop index. 9388 * nh_info - (OUT)Buffer to fill next hop info. 9389 * Returns: 9390 * BCM_E_XXX 9391 */ 9392 int 9393 bcm_xgs3_nh_get(int unit, int nh_idx, bcm_l3_egress_t *nh_info) 9394 { 9395 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 9396 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) 9397 uint32 entry_type=0; /* Next Hop Entry_type */ 9398 uint32 label_action=-1; /* MPLS Label Action */ 9399 #endif /* BCM_TRIUMPH_SUPPORT && BCM_MPLS_SUPPORT */ 9400 9401 /* Make sure module was initialized. */ 9402 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 9403 return (BCM_E_INIT); 9404 } 9405 9406 /* Input parameters check. */ 9407 if (NULL == nh_info) { 9408 return (BCM_E_PARAM); 9409 } else { 9410 bcm_l3_egress_t_init (nh_info); 9411 } 9412 9413 /* Make sure entry is inuse. */ 9414 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_idx)) { 9415 return (BCM_E_NOT_FOUND); 9416 } 9417 9418 /* Get next hop entry from hw. */ 9419 if (BCM_XGS3_L3_HWCALL_CHECK(unit, nh_get)) { 9420 BCM_XGS3_L3_MODULE_LOCK(unit); 9421 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_get) (unit, nh_idx, nh_info); 9422 BCM_XGS3_L3_MODULE_UNLOCK(unit); 9423 BCM_IF_ERROR_RETURN(rv); 9424 } 9425 #if defined(BCM_TRIDENT2_SUPPORT) 9426 if ( soc_feature(unit, soc_feature_vxlan)) { 9427 rv = bcm_td2_vxlan_egress_get(unit, nh_info, nh_idx); 9428 BCM_IF_ERROR_RETURN(rv); 9429 } 9430 #endif /* BCM_TRIDENT2_SUPPORT */ 9431 #if defined(BCM_GREYHOUND2_SUPPORT) 9432 if (soc_feature(unit, soc_feature_vxlan_lite)) { 9433 rv = bcmi_gh2_vxlan_egress_get(unit, nh_info, nh_idx); 9434 BCM_IF_ERROR_RETURN(rv); 9435 } 9436 #endif /* BCM_GREYHOUND2_SUPPORT */ 9437 #if defined(BCM_TRIUMPH3_SUPPORT) 9438 if ( soc_feature(unit, soc_feature_l2gre)) { 9439 rv = bcm_tr3_l2gre_egress_get(unit, nh_info, nh_idx); 9440 BCM_IF_ERROR_RETURN(rv); 9441 } 9442 #endif /* BCM_TRIUMPH3_SUPPORT */ 9443 9444 #if defined(BCM_TRIDENT_SUPPORT) 9445 if ( soc_feature(unit, soc_feature_trill)) { 9446 rv = bcm_td_trill_egress_get(unit, nh_info, nh_idx); 9447 BCM_IF_ERROR_RETURN(rv); 9448 } 9449 #endif /* BCM_TRIDENT_SUPPORT */ 9450 9451 #if defined(BCM_TRIDENT3_SUPPORT) 9452 if ( soc_feature(unit, soc_feature_flex_flow)) { 9453 rv = _bcm_td3_flow_egress_get(unit, nh_info, nh_idx); 9454 BCM_IF_ERROR_RETURN(rv); 9455 } 9456 #endif /* BCM_TRIDENT3_SUPPORT */ 9457 9458 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) 9459 if (SOC_IS_TR_VL(unit) && (soc_feature(unit, soc_feature_mpls))) { 9460 BCM_IF_ERROR_RETURN( 9461 bcm_tr_mpls_get_entry_type(unit, nh_idx, &entry_type)); 9462 if (entry_type == 1) { 9463 BCM_IF_ERROR_RETURN( 9464 bcm_tr_mpls_get_label_action(unit, nh_idx, &label_action)); 9465 9466 switch (label_action) { 9467 case _BCM_MPLS_ACTION_NOOP: 9468 case _BCM_MPLS_ACTION_PUSH: 9469 9470 BCM_IF_ERROR_RETURN( 9471 bcm_tr_mpls_l3_label_get (unit, nh_idx, nh_info)); 9472 break; 9473 9474 case _BCM_MPLS_ACTION_SWAP: 9475 case _BCM_MPLS_ACTION_PRESERVED: 9476 #if defined(BCM_TOMAHAWK3_SUPPORT) 9477 if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) { 9478 BCM_IF_ERROR_RETURN( 9479 bcm_th3_mpls_swap_nh_info_get (unit, nh_info, nh_idx)); 9480 } else 9481 #endif 9482 { 9483 9484 BCM_IF_ERROR_RETURN( 9485 bcm_tr_mpls_swap_nh_info_get (unit, nh_info, nh_idx)); 9486 } 9487 break; 9488 9489 default: 9490 break; 9491 } 9492 } 9493 } 9494 #endif /* BCM_TRX_SUPPORT && BCM_MPLS_SUPPORT */ 9495 9496 #if defined(BCM_TRIUMPH2_SUPPORT) 9497 if (soc_feature(unit, soc_feature_failover)) { 9498 int prot_nh_index =-1; 9499 int prot_mc_group=-1; 9500 rv = _bcm_esw_failover_prot_nhi_get (unit, nh_idx, 9501 &nh_info->failover_id, &prot_nh_index, &prot_mc_group); 9502 if ( rv != BCM_E_NONE ) { 9503 return rv; 9504 } else { 9505 if (prot_nh_index != -1) { 9506 if (nh_info->failover_id != 0) { 9507 nh_info->failover_if_id = prot_nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit); 9508 } 9509 } 9510 if (prot_mc_group != -1) { 9511 nh_info->failover_mc_group = prot_mc_group; 9512 } 9513 } 9514 } 9515 #endif /* BCM_TRIUMPH2_SUPPORT */ 9516 return rv; 9517 } 9518 9519 /* 9520 * Function: 9521 * _bcm_xgs3_nh_ent_cmp 9522 * Purpose: 9523 * Routine compares next hop entry with entry in the chip 9524 * with specified index. 9525 * NOTE: It is safer to compare entries in hw format after 9526 * proper validation & mapping of api data. 9527 * Hence next hop entry expected to be in HW format! 9528 * Please see _bcm_xgs3_nh_map_api_data_to_hw. 9529 * 9530 * Parameters: 9531 * unit - (IN) SOC unit number. 9532 * buf - (IN) First nh entry to compare. 9533 * index - (IN) Entry index in the chip to compare. 9534 * cmp_result - (OUT)Compare result. 9535 * Returns: 9536 * BCM_E_XXX 9537 */ 9538 STATIC int 9539 _bcm_xgs3_nh_ent_cmp(int unit, void *buf, int index, int *cmp_result) 9540 { 9541 bcm_l3_egress_t nh_hw; /* Next hop entry from hw. */ 9542 bcm_l3_egress_t *nh_entry; /* Next hop entry from api. */ 9543 9544 if ((NULL == buf) || (NULL == cmp_result)) 9545 return (BCM_E_PARAM); 9546 9547 /* Get api entry info. */ 9548 nh_entry = (bcm_l3_egress_t *) buf; 9549 9550 /* Get next hop entry from hw. */ 9551 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, index, &nh_hw)); 9552 9553 #ifdef BCM_GREYHOUND_SUPPORT 9554 if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)){ 9555 if (nh_entry->flags & BCM_L3_IPMC) { 9556 9557 /* Entry type */ 9558 if (!(nh_hw.flags & BCM_L3_IPMC)) { 9559 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9560 return (BCM_E_NONE); 9561 } 9562 9563 /* INTF_NUM */ 9564 if (nh_hw.intf != nh_entry->intf) { 9565 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9566 return (BCM_E_NONE); 9567 } 9568 9569 /* L3MC_USE_CONFIGURED_MAC */ 9570 if ((nh_hw.flags ^ nh_entry->flags) & BCM_L3_KEEP_DSTMAC) { 9571 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9572 return (BCM_E_NONE); 9573 } 9574 9575 /* MAC_ADDRESS */ 9576 if (sal_memcmp(nh_hw.mac_addr, nh_entry->mac_addr, 9577 sizeof(bcm_mac_t))) { 9578 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9579 return (BCM_E_NONE); 9580 } 9581 9582 *cmp_result = BCM_L3_CMP_EQUAL; 9583 return (BCM_E_NONE); 9584 } 9585 } 9586 #endif /* BCM_GREYHOUND_SUPPORT */ 9587 9588 /* 9589 * Compare entries in hw format. Should never fail, we just read it. 9590 * NOTE bcm_xgs3_nh_get returns entry in API format. 9591 */ 9592 _bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_hw); 9593 9594 /* Compare trunk flag */ 9595 if ((nh_hw.flags & BCM_L3_TGID) != (nh_entry->flags & BCM_L3_TGID)) { 9596 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9597 return (BCM_E_NONE); 9598 } 9599 9600 /* Compare port/trunk id. */ 9601 if (nh_hw.port != nh_entry->port) { 9602 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9603 return (BCM_E_NONE); 9604 } 9605 9606 /* Module Id. */ 9607 if (nh_hw.module != nh_entry->module) { 9608 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9609 return (BCM_E_NONE); 9610 } 9611 9612 /* Interface compare. */ 9613 if (nh_hw.intf != nh_entry->intf) { 9614 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9615 return (BCM_E_NONE); 9616 } 9617 9618 /* Mac compare */ 9619 if (sal_memcmp(nh_hw.mac_addr, nh_entry->mac_addr, sizeof(bcm_mac_t))) { 9620 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9621 return (BCM_E_NONE); 9622 } 9623 #ifdef BCM_FIREBOLT_SUPPORT 9624 /* Tunnel type compare. */ 9625 if (SOC_IS_FBX(unit)) { 9626 /* If the intf is reserved, bypass vlan check */ 9627 if (nh_hw.intf != BCM_XGS3_L3_L2CPU_INTF_IDX(unit) && 9628 !BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) { 9629 /* Vlan id compare. */ 9630 if (nh_hw.vlan != nh_entry->vlan) { 9631 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9632 return (BCM_E_NONE); 9633 } 9634 } 9635 } 9636 #endif /* BCM_FIREBOLT_SUPPORT */ 9637 9638 /* Encap ID compare */ 9639 if (nh_hw.encap_id != nh_entry->encap_id) { 9640 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9641 return (BCM_E_NONE); 9642 } 9643 9644 /* BCM_L3_IPMC flag compare */ 9645 if ((nh_hw.flags & BCM_L3_IPMC) != (nh_entry->flags & BCM_L3_IPMC)) { 9646 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9647 return (BCM_E_NONE); 9648 } 9649 9650 /* Multicast group. */ 9651 if (((nh_hw.flags2 & BCM_L3_FLAGS2_MC_GROUP) != (nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP)) || 9652 ((nh_hw.flags2 & BCM_L3_FLAGS2_MC_GROUP) && (nh_hw.mc_group != nh_entry->mc_group))) { 9653 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 9654 return (BCM_E_NONE); 9655 } 9656 9657 *cmp_result = BCM_L3_CMP_EQUAL; 9658 return (BCM_E_NONE); 9659 } 9660 9661 #ifdef BCM_TRIDENT3_SUPPORT 9662 STATIC int 9663 _bcm_l3_get_flex_entry_width (int unit, bcm_l3_egress_t *nh_info, uint32 *width) { 9664 9665 uint32 view_id; 9666 soc_flow_db_mem_view_info_t mem_view_info; 9667 9668 BCM_IF_ERROR_RETURN( 9669 soc_flow_db_ffo_to_mem_view_id_get(unit, 9670 nh_info->flow_handle, 9671 nh_info->flow_option_handle, 9672 SOC_FLOW_DB_FUNC_EGRESS_OBJ_ID, 9673 &view_id)); 9674 9675 BCM_IF_ERROR_RETURN( 9676 soc_flow_db_mem_view_info_get(unit, 9677 view_id, 9678 &mem_view_info)); 9679 9680 if (mem_view_info.width > 2*BCMI_TD3_EGR_L3_NEXTHOP_WIDTH) { 9681 return BCM_E_INTERNAL; 9682 } 9683 else if (mem_view_info.width > BCMI_TD3_EGR_L3_NEXTHOP_WIDTH) { 9684 *width = _BCM_DOUBLE_WIDE; 9685 } 9686 else { 9687 *width = _BCM_SINGLE_WIDE; 9688 } 9689 return BCM_E_NONE; 9690 } 9691 #endif 9692 9693 /* 9694 * Function: 9695 * bcm_xgs3_nh_add 9696 * Purpose: 9697 * Allocate NextHop table index & Write NextHop entry. 9698 * Routine trying to match new entry to an existing one, 9699 * if match found reference cound is incremented, otherwise 9700 * new index allocated & entry added to hw. 9701 * Parameters: 9702 * unit - (IN)SOC unit number. 9703 * flags - (IN)Egress object flags. 9704 * nh_info - (IN)Next hop entry info. 9705 * index - (OUT)Next hop index. 9706 * Returns: 9707 * BCM_E_XXX 9708 */ 9709 int 9710 bcm_xgs3_nh_add(int unit, uint32 flags, bcm_l3_egress_t *nh_info, int *index) 9711 { 9712 _bcm_l3_tbl_op_t data; /* Operation data. */ 9713 9714 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT 9715 uint32 *nh_multi_count; 9716 int backup_min_index; 9717 ing_l3_next_hop_entry_t ing_nh; 9718 int i = 0; 9719 int rv = BCM_E_NONE; 9720 #endif 9721 9722 /* Make sure module was initialized. */ 9723 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 9724 return (BCM_E_INIT); 9725 } 9726 9727 /* Input parameters check. */ 9728 if (NULL == nh_info) { 9729 return (BCM_E_PARAM); 9730 } 9731 9732 if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) { 9733 /* Make sure hw call is defined. */ 9734 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_add)) { 9735 return (BCM_E_UNAVAIL); 9736 } 9737 9738 /* Convert API next hop entry to HW space format. */ 9739 BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_map_api_data_to_hw(unit, nh_info)); 9740 } 9741 9742 /* Initialization */ 9743 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 9744 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 9745 data.width = _BCM_SINGLE_WIDE; 9746 data.oper_flags = flags; 9747 data.entry_buffer = (void *)nh_info; 9748 data.hash_func = _bcm_xgs3_nh_hash_calc; 9749 data.cmp_func = _bcm_xgs3_nh_ent_cmp; 9750 data.add_func = BCM_XGS3_L3_HWCALL(unit, nh_add); 9751 if (flags & _BCM_L3_SHR_WITH_ID) { 9752 data.entry_index = *index; 9753 } 9754 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT 9755 backup_min_index = data.tbl_ptr->idx_min; 9756 if (_BCM_FAILOVER_IS_MULTI_LEVEL(nh_info->failover_id)) { 9757 if (((BCM_XGS3_L3_EGRESS_IDX_VALID(unit, nh_info->failover_if_id) || 9758 BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, nh_info->failover_if_id )) && 9759 (bcmi_l3_nh_multi_count_get(unit, *index) < 4)) || 9760 (nh_info->failover_mc_group > 0)) { 9761 /* if user wants to create a failover nhi with 9762 * a multi level failover and different NH, then we 9763 * will have to reserve two NHs as we will point to 9764 * a separate prot nhi table of double wide entry. 9765 */ 9766 9767 data.width = _BCM_DOUBLE_WIDE; 9768 /* Set up the limits for indexes */ 9769 backup_min_index = data.tbl_ptr->idx_min; 9770 data.tbl_ptr->idx_min = 2; 9771 } 9772 } 9773 #endif 9774 #ifdef BCM_TRIDENT3_SUPPORT 9775 /* Get view id corresponding to the specified flow. */ 9776 9777 if (soc_feature(unit, soc_feature_flex_flow) && 9778 nh_info->flow_handle != 0) { 9779 9780 BCM_IF_ERROR_RETURN( 9781 _bcm_l3_get_flex_entry_width(unit, nh_info, (uint32 *) &data.width)); 9782 } 9783 #endif 9784 /* Add next hop table entry. */ 9785 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_add(unit, &data)); 9786 *index = data.entry_index; 9787 #ifdef BCM_TRIDENT_SUPPORT 9788 if (soc_feature(unit, soc_feature_trill) && 9789 (nh_info->flags & BCM_L3_TRILL_ONLY)) { 9790 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9791 data.width, _BCM_L3_TRILL_ONLY); 9792 } 9793 #endif /* BCM_TRIDENT_SUPPORT */ 9794 #ifdef BCM_TRIUMPH3_SUPPORT 9795 if (soc_feature(unit, soc_feature_l2gre) && 9796 (nh_info->flags & BCM_L3_L2GRE_ONLY)) { 9797 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9798 data.width, _BCM_L3_L2GRE_ONLY); 9799 } 9800 #endif /* BCM_TRIUMPH3_SUPPORT */ 9801 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 9802 if ((soc_feature(unit, soc_feature_vxlan) || 9803 soc_feature(unit, soc_feature_vxlan_lite)) && 9804 (nh_info->flags & BCM_L3_VXLAN_ONLY)) { 9805 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9806 data.width, _BCM_L3_VXLAN_ONLY); 9807 } 9808 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 9809 #ifdef BCM_TRIDENT3_SUPPORT 9810 if (soc_feature(unit, soc_feature_flex_flow) && 9811 (nh_info->flags2 & BCM_L3_FLOW_ONLY)) { 9812 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9813 data.width, _BCM_L3_FLOW_ONLY); 9814 } 9815 #endif /* BCM_TRIDENT3_SUPPORT */ 9816 #ifdef BCM_TRIDENT_SUPPORT 9817 if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 9818 (nh_info->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) { 9819 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9820 data.width, _BCM_L3_FIELD_ONLY); 9821 } 9822 #endif 9823 #ifdef BCM_TRIDENT2_SUPPORT 9824 if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) && 9825 (nh_info->flags2 & BCM_L3_FLAGS2_MPLS_PHP)) { 9826 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9827 data.width, _BCM_L3_MPLS_PHP); 9828 } 9829 #endif /* BCM_TRIDENT2_SUPPORT */ 9830 #ifdef BCM_TRIDENT2_SUPPORT 9831 if (soc_feature(unit, soc_feature_fcoe) && 9832 (nh_info->flags2 & BCM_L3_FLAGS2_FCOE_ONLY)) { 9833 BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index, 9834 data.width, _BCM_L3_FCOE_ONLY); 9835 } 9836 #endif 9837 9838 if ((BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, data.entry_index) == 1) && 9839 !((data.oper_flags & _BCM_L3_SHR_WITH_ID) && 9840 (data.oper_flags & _BCM_L3_SHR_UPDATE))) { 9841 BCM_XGS3_L3_NH_CNT(unit)+= data.width; 9842 } 9843 9844 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT 9845 data.tbl_ptr->idx_min = backup_min_index; 9846 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 9847 if (bcmi_l3_nh_multi_count_get(unit, *index) < 4) { 9848 nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit); 9849 nh_multi_count[*index] = data.width; 9850 } 9851 /* 9852 * In the allocated NHs, we will have to write some info. 9853 * Otherwise, we may neglect this NH while recovering from 9854 * warmboot thinking that this is null entry. 9855 */ 9856 if (data.width > 1) { 9857 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, 1); 9858 for (i=1; i<data.width; i++) { 9859 rv = soc_mem_write (unit, ING_L3_NEXT_HOPm, 9860 MEM_BLOCK_ALL, data.entry_index + i, &ing_nh); 9861 if (BCM_FAILURE(rv)) { 9862 return rv; 9863 } 9864 } 9865 } 9866 } 9867 #endif 9868 return (BCM_E_NONE); 9869 } 9870 9871 /* 9872 * Function: 9873 * bcm_xgs3_nh_del 9874 * Purpose: 9875 * Delete NextHop entry. 9876 * Entry kept if reference counter not equals to 1(Other hosts/routes 9877 * reference the same entry). 9878 * 9879 * Parameters: 9880 * unit - (IN)SOC unit number. 9881 * flags - (IN)Egress object flags. 9882 * nh_index - (IN)next hop index. 9883 * Returns: 9884 * BCM_E_XXX 9885 */ 9886 int 9887 bcm_xgs3_nh_del(int unit, uint32 flags, int nh_index) 9888 { 9889 _bcm_l3_tbl_op_t data; /* Operation data. */ 9890 int rv = BCM_E_NONE; 9891 int no_of_elements = 1; 9892 int i = 0; 9893 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT 9894 uint32 *nh_multi_count; 9895 #endif 9896 9897 /* Make sure module was initialized. */ 9898 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 9899 return (BCM_E_INIT); 9900 } 9901 9902 /* For egress mode, nh_index could be BCM_XGS3_L3_INVALID_INDEX */ 9903 if (nh_index < 0) { 9904 return (BCM_E_NONE); 9905 } 9906 9907 if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) { 9908 /* Make sure hw call is registred. */ 9909 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_del)) { 9910 return (BCM_E_UNAVAIL); 9911 } 9912 } 9913 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT 9914 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 9915 nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit); 9916 no_of_elements = nh_multi_count[nh_index];; 9917 } 9918 no_of_elements = ((no_of_elements > 1)? no_of_elements : 1); 9919 #endif 9920 9921 #if defined(BCM_TRIDENT3_SUPPORT) 9922 if (soc_feature(unit, soc_feature_flex_flow) && 9923 (flags & _BCM_L3_SHR_WIDE_FLEX_ENTRY)) { 9924 no_of_elements = 2; 9925 } 9926 #endif 9927 /* Initialization */ 9928 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 9929 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 9930 data.entry_index = nh_index; 9931 data.width = _BCM_SINGLE_WIDE; 9932 data.oper_flags = flags; 9933 data.delete_func = BCM_XGS3_L3_HWCALL(unit, nh_del); 9934 9935 /* Don't touch reserved trap to cpu entry. */ 9936 if (nh_index == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) { 9937 if (BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, nh_index) > 1) { 9938 BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, nh_index, 9939 _BCM_SINGLE_WIDE); 9940 } 9941 return (BCM_E_NONE); 9942 } 9943 for (i=0; i<no_of_elements; i++) { 9944 /* Delete next hop table entry. */ 9945 data.entry_index = nh_index + i; 9946 if (BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, nh_index+i) == 1) { 9947 BCM_XGS3_L3_NH_CNT(unit)--; 9948 } 9949 9950 /* Delete next hop table entry. */ 9951 rv = _bcm_xgs3_tbl_del(unit, &data) ; 9952 if (BCM_FAILURE(rv)) { 9953 return rv; 9954 } 9955 } 9956 return BCM_E_NONE; 9957 } 9958 9959 /* 9960 * Function: 9961 * bcm_xgs3_get_nh_from_egress_object 9962 * Purpose: 9963 * Extract next hop id/Ecmp group id from egress object. 9964 * Increment next hop/ecmp group reference count 9965 * Parameters: 9966 * unit - (IN)SOC unit number. 9967 * intf - (IN)L3 egress object id. 9968 * mpath_flag - (OUT) multipath indicator 9969 * ref_count - (IN) Flag to increment reference_count. 9970 * index - (OUT)Next hop index. 9971 * Returns: 9972 * BCM_E_XXX 9973 */ 9974 int 9975 bcm_xgs3_get_nh_from_egress_object(int unit, bcm_if_t intf, 9976 uint32 *mpath_flag, int ref_count, int *index) 9977 { 9978 int width; 9979 9980 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 9981 BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 9982 9983 /* Extract next hop index from unipath egress object. */ 9984 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 9985 *index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 9986 } else { 9987 *index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 9988 } 9989 *mpath_flag = 0; 9990 9991 /* Make sure next hop is in use. */ 9992 if (!BCM_XGS3_L3_ENT_REF_CNT 9993 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index)) { 9994 return (BCM_E_PARAM); 9995 } 9996 9997 /* Increment next hop reference count. */ 9998 if (ref_count) { 9999 BCM_XGS3_L3_ENT_REF_CNT_INC 10000 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index, _BCM_SINGLE_WIDE); 10001 } 10002 } else if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) { 10003 10004 /* Extract ecmp group index from multipath egress object. */ 10005 *index = intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 10006 10007 *mpath_flag = BCM_L3_MULTIPATH; 10008 10009 /* Make sure ecmp group is in use. */ 10010 #ifdef BCM_TOMAHAWK3_SUPPORT 10011 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 10012 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 10013 ecmp_mode_hierarchical) && (*index < 10014 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 10015 if (!BCM_XGS3_L3_ENT_REF_CNT 10016 (BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), *index)) { 10017 return (BCM_E_PARAM); 10018 } 10019 } else 10020 #endif 10021 if (!BCM_XGS3_L3_ENT_REF_CNT 10022 (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), *index)) { 10023 return (BCM_E_PARAM); 10024 } 10025 10026 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 10027 width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 10028 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 10029 } else { 10030 width = _BCM_SINGLE_WIDE; 10031 } 10032 10033 if (SOC_IS_SCORPION(unit)) { 10034 BCM_IF_ERROR_RETURN( 10035 bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, intf, &width, NULL)); 10036 } 10037 10038 /* Increment ecmp group reference count. */ 10039 if (ref_count) { 10040 #if defined(BCM_TOMAHAWK3_SUPPORT) 10041 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 10042 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 10043 ecmp_mode_hierarchical) && (*index < 10044 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 10045 BCM_XGS3_L3_ENT_REF_CNT_INC 10046 (BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), *index, width); 10047 } else 10048 #endif 10049 { 10050 BCM_XGS3_L3_ENT_REF_CNT_INC 10051 (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), *index, width); 10052 } 10053 } 10054 } else if (BCM_XGS3_PROXY_EGRESS_IDX_VALID(unit, intf)) { 10055 /* Extract ecmp group index from multipath egress object. */ 10056 *index = intf - BCM_XGS3_PROXY_EGRESS_IDX_MIN(unit); 10057 10058 *mpath_flag = 0; 10059 /* Make sure next hop is in use. */ 10060 if (!BCM_XGS3_L3_ENT_REF_CNT 10061 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index)) { 10062 return (BCM_E_PARAM); 10063 } 10064 10065 /* Increment next hop reference count. */ 10066 if (ref_count) { 10067 BCM_XGS3_L3_ENT_REF_CNT_INC 10068 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index, _BCM_SINGLE_WIDE); 10069 } 10070 } else { 10071 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 10072 /* This is a valid for TR3 and TD2, i.e., egress mode is set, but 10073 * the intf passed does not correspond to an egress object 10074 * indicating that a host entry with embedded next hop has 10075 * been specified */ 10076 if (intf >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 10077 return BCM_E_PARAM; 10078 } 10079 *index = BCM_XGS3_L3_INVALID_INDEX; 10080 return (BCM_E_NONE); 10081 } else { 10082 /* Invalid egress object id specified. */ 10083 return (BCM_E_PARAM); 10084 } 10085 } 10086 return (BCM_E_NONE); 10087 } 10088 10089 /* 10090 * Function: 10091 * bcm_xgs3_get_ref_count_from_nhi 10092 * Purpose: 10093 * Extract egress/multipath object from next hop id/Ecmp group 10094 * Decrement next hop/ecmp group reference count 10095 * Parameters: 10096 * unit - (IN)SOC unit number. 10097 * flags - (IN)Caller flags (eg Multipath route). 10098 * ref_count - (IN) pointer to reference_count. 10099 * index - (OUT)Next hop index. 10100 * Returns: 10101 * BCM_E_XXX 10102 */ 10103 int 10104 bcm_xgs3_get_ref_count_from_nhi(int unit, uint32 flags, int *ref_count, int nh_ecmp_index) 10105 { 10106 int count=0; 10107 int width; 10108 _bcm_l3_tbl_t *tbl_ptr; /* ECMP table pointer. */ 10109 10110 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 10111 10112 if ((flags & BCM_L3_MULTIPATH)) { 10113 10114 /* Make sure ecmp group is in use. */ 10115 #if defined(BCM_TOMAHAWK3_SUPPORT) 10116 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 10117 ecmp_mode_hierarchical) && (nh_ecmp_index < 10118 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) && 10119 (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) { 10120 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 10121 } 10122 #endif 10123 count = BCM_XGS3_L3_ENT_REF_CNT 10124 (tbl_ptr, nh_ecmp_index); 10125 10126 if (count <= 1) { 10127 *ref_count = count; 10128 return (BCM_E_NONE); 10129 } 10130 10131 width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 10132 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 10133 10134 /* Decrement ecmp group reference count. */ 10135 BCM_XGS3_L3_ENT_REF_CNT_DEC 10136 (tbl_ptr, nh_ecmp_index, width); 10137 *ref_count = BCM_XGS3_L3_ENT_REF_CNT 10138 (tbl_ptr, nh_ecmp_index); 10139 10140 } else { 10141 10142 /* Make sure next hop is in use. */ 10143 count = BCM_XGS3_L3_ENT_REF_CNT 10144 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_ecmp_index); 10145 10146 if (count <= 1) { 10147 *ref_count = count; 10148 return (BCM_E_NONE); 10149 } 10150 10151 /* Decrement next hop reference count. */ 10152 BCM_XGS3_L3_ENT_REF_CNT_DEC 10153 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_ecmp_index, _BCM_SINGLE_WIDE); 10154 10155 *ref_count = BCM_XGS3_L3_ENT_REF_CNT 10156 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_ecmp_index); 10157 10158 } 10159 return (BCM_E_NONE); 10160 } 10161 10162 /* 10163 * Function: 10164 * _bcm_xgs3_nh_init_add 10165 * Purpose: 10166 * Initialize next hop entry. 10167 * Allocate NextHop table index & Write NextHop entry. 10168 * Routine trying to match new entry to an existing one, 10169 * if match found reference cound is incremented, otherwise 10170 * new index allocated & entry added to hw. 10171 * Parameters: 10172 * unit - (IN)SOC unit number. 10173 * l3cfg - (IN)L3 host entry. 10174 * OR <- We always get next hop index either for host OR for a route. 10175 * lpm_cfg - (IN)Route entry. 10176 * index - (OUT)Next hop index. 10177 * Returns: 10178 * BCM_E_XXX 10179 */ 10180 10181 int 10182 _bcm_xgs3_nh_init_add(int unit, _bcm_l3_cfg_t *l3cfg, 10183 _bcm_defip_cfg_t *lpm_cfg, int *index) 10184 { 10185 bcm_if_t intf; /* Egress interface index. */ 10186 uint32 flags=0; /* Next hop entry flags. */ 10187 bcm_l3_egress_t nh_entry; /* Next hop entry. */ 10188 10189 /* Input parameters check. */ 10190 if ((NULL == index) || ((NULL == l3cfg) && (NULL == lpm_cfg)) || 10191 ((NULL != l3cfg) && (NULL != lpm_cfg))) { 10192 return (BCM_E_PARAM); 10193 } 10194 10195 10196 10197 /* Check if egress switching mode is enabled. */ 10198 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 10199 /* Get egress object id. */ 10200 intf = (NULL != l3cfg) ? l3cfg->l3c_intf : lpm_cfg->defip_intf; 10201 flags = (NULL != lpm_cfg) ? (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) 10202 : (l3cfg->l3c_flags & BCM_L3_MULTIPATH); 10203 if (l3cfg != NULL) { 10204 if (l3cfg->l3c_flags & BCM_L3_L2TOCPU) { 10205 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit); 10206 } else { 10207 return bcm_xgs3_get_nh_from_egress_object(unit, intf, &flags, 1, index); 10208 } 10209 } else { 10210 if (lpm_cfg->defip_flags & BCM_L3_DEFIP_LOCAL) { 10211 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit); 10212 } else { 10213 return bcm_xgs3_get_nh_from_egress_object(unit, intf, &flags, 1, 10214 index); 10215 } 10216 } 10217 } 10218 10219 *index = BCM_XGS3_L3_INVALID_INDEX; 10220 /* Check if traffic should be trapped to cpu. */ 10221 if (l3cfg) { 10222 if (l3cfg->l3c_flags & BCM_L3_L2TOCPU) { 10223 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit); 10224 } 10225 } else if (lpm_cfg->defip_flags & BCM_L3_DEFIP_LOCAL) { 10226 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit); 10227 } 10228 /* If packet should be trapped increment reference count and return. */ 10229 if (*index == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) { 10230 BCM_XGS3_L3_ENT_REF_CNT_INC((BCM_XGS3_L3_TBL_PTR(unit, next_hop)), 10231 BCM_XGS3_L3_L2CPU_NH_IDX(unit), _BCM_SINGLE_WIDE); 10232 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit); 10233 return (BCM_E_NONE); 10234 } 10235 10236 /* Real entry required -> init next hop entry. */ 10237 BCM_IF_ERROR_RETURN 10238 (_bcm_xgs3_nh_entry_init(unit, &nh_entry, l3cfg, lpm_cfg)); 10239 10240 /* Add next hop entry. */ 10241 /* coverity[negative_returns : FALSE] */ 10242 return bcm_xgs3_nh_add(unit, 0, &nh_entry, index); 10243 } 10244 10245 /* 10246 * Function: 10247 * _bcm_xgs3_l3_get_nh_info 10248 * Purpose: 10249 * Fill next hop info for l3 entry. 10250 * Parameters: 10251 * unit - SOC unit number. 10252 * l3cfg - L3 entry to fill. 10253 * nh_idx - Next hop index. 10254 * Returns: 10255 * BCM_E_XXX 10256 */ 10257 int 10258 _bcm_xgs3_l3_get_nh_info(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 10259 { 10260 bcm_l3_egress_t nh_info; /* Next hop info buffer. */ 10261 10262 /* In egress switching mode - set egress object id only. */ 10263 /* Depends on whether it is a regular L3 next hop or a WLAN DVP */ 10264 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 10265 #ifdef BCM_TRIUMPH2_SUPPORT 10266 egr_l3_next_hop_entry_t next_hop; 10267 int entry_type; 10268 if (soc_feature(unit, soc_feature_l3_extended_host_entry) && 10269 nh_idx == BCM_XGS3_L3_INVALID_INDEX) { 10270 /* Embedded next hop entry, NH idx is not valid */ 10271 return (BCM_E_NONE); 10272 } 10273 10274 if (soc_feature(unit, soc_feature_wlan)) { 10275 BCM_IF_ERROR_RETURN 10276 (READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_idx, &next_hop)); 10277 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &next_hop, 10278 nh_entry_type_field[unit]); 10279 if (entry_type == 4) { 10280 l3cfg->l3c_intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 10281 } else { 10282 l3cfg->l3c_intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit); 10283 } 10284 } else 10285 #endif 10286 if(l3cfg->l3c_flags & BCM_L3_MULTIPATH) { 10287 l3cfg->l3c_intf = nh_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 10288 } else { 10289 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info)); 10290 if ((nh_info.encap_id > 0 && 10291 nh_info.encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) 10292 #ifdef BCM_RIOT_SUPPORT 10293 || (BCMI_RIOT_IS_ENABLED(unit) && 10294 _bcm_vp_is_vfi_type(unit, nh_info.port)) 10295 #endif /* BCM_RIOT_SUPPORT */ 10296 ) { 10297 l3cfg->l3c_intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 10298 } else { 10299 l3cfg->l3c_intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit); 10300 } 10301 } 10302 return (BCM_E_NONE); 10303 } 10304 10305 /* If next hop is trap to cpu - don't read nh table. */ 10306 if (nh_idx == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) { 10307 /* Set flags to bridge to cpu. */ 10308 l3cfg->l3c_flags |= BCM_L3_L2TOCPU; 10309 /* Set interface index to last one in the table. */ 10310 l3cfg->l3c_intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit); 10311 /* Set module id to a local module. */ 10312 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &l3cfg->l3c_modid)); 10313 /* No vlan/interface info. */ 10314 l3cfg->l3c_vid = 0; 10315 l3cfg->l3c_tunnel = 0; 10316 /* Set port to be a cpu port. */ 10317 l3cfg->l3c_port_tgid = CMIC_PORT(unit); 10318 /* Reset mac address. */ 10319 sal_memset(l3cfg->l3c_mac_addr, 0, sizeof(bcm_mac_t)); 10320 /* Set host flags to trap to cpu. */ 10321 l3cfg->l3c_flags |= BCM_L3_L2TOCPU; 10322 return (BCM_E_NONE); 10323 } 10324 10325 /* Get next hop entry from hw. */ 10326 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info)); 10327 10328 /* Fill next hop info to l3 entry. */ 10329 if (nh_info.flags & BCM_L3_TGID) { /* Trunk */ 10330 l3cfg->l3c_flags |= BCM_L3_TGID; 10331 } 10332 /* Set module id. */ 10333 l3cfg->l3c_modid = nh_info.module; 10334 /* Set trunk/port info. */ 10335 l3cfg->l3c_port_tgid = 10336 (nh_info.flags & BCM_L3_TGID) ? nh_info.trunk : nh_info.port; 10337 /* Set interface index. */ 10338 l3cfg->l3c_intf = nh_info.intf; 10339 /* Set physical address. */ 10340 sal_memcpy(l3cfg->l3c_mac_addr, nh_info.mac_addr, sizeof(bcm_mac_t)); 10341 /* Get tunnel id info. */ 10342 BCM_IF_ERROR_RETURN 10343 (_bcm_xgs3_l3_get_tunnel_id(unit, nh_info.intf, &l3cfg->l3c_tunnel)); 10344 #ifdef BCM_FIREBOLT_SUPPORT 10345 if (SOC_IS_FBX(unit)) { 10346 l3cfg->l3c_vid = nh_info.vlan; 10347 } 10348 #endif /* BCM_FIREBOLT_SUPPORT */ 10349 return (BCM_E_NONE); 10350 } 10351 10352 /* 10353 * Function: 10354 * _bcm_xgs3_l3_ecmp_1k_groups_info_get 10355 * Purpose: 10356 * Get ecmp group size and base idx for the chips with 1K ecmp groups, 10357 * especially for TD+ with configurable 256/1k ecmp groups meantime. 10358 * Parameters: 10359 * unit - (IN) SOC unit number. 10360 * grp_idx - (IN) ECMP group idx. 10361 * l3_ecmp_count - (IN) Buffer for l3_ecmp_count hw entry. 10362 * group_size - (OUT) Ecmp group size. 10363 * base_idx - (OUT) Ecmp base entry 10364 * Returns: 10365 * BCM_E_XXX. 10366 */ 10367 STATIC int 10368 _bcm_xgs3_l3_ecmp_1k_groups_info_get(int unit, int grp_idx, void *l3_ecmp_count, 10369 int *group_size, int *base_idx) 10370 { 10371 uint32 ing_config_2; 10372 uint8 ecmp_hash_16bits = 1; /*1k ecmp groups by default*/ 10373 #if defined(BCM_TOMAHAWK3_SUPPORT) 10374 int lb_mode; 10375 #endif 10376 #if defined(BCM_TOMAHAWK_SUPPORT) 10377 int weighted = 0; 10378 #endif 10379 soc_mem_t mem = L3_ECMP_COUNTm; 10380 10381 #if defined(BCM_TOMAHAWK3_SUPPORT) 10382 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 10383 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 10384 ecmp_mode_hierarchical) && (grp_idx < 10385 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 10386 mem = ECMP_GROUP_HIERARCHICALm; 10387 } 10388 #endif 10389 10390 if (!l3_ecmp_count){ 10391 return BCM_E_PARAM; 10392 } 10393 10394 if ((!group_size) && (!base_idx)){ 10395 return BCM_E_PARAM; 10396 } 10397 10398 /*for TD+*/ 10399 if (SOC_IS_TRIDENT(unit)) { 10400 ecmp_hash_16bits = 0; 10401 if (SOC_REG_IS_VALID(unit, ING_CONFIG_2r)) { 10402 SOC_IF_ERROR_RETURN(READ_ING_CONFIG_2r(unit, &ing_config_2)); 10403 ecmp_hash_16bits = 10404 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 10405 ECMP_HASH_16BITSf); 10406 } 10407 if (!ecmp_hash_16bits) { 10408 if (group_size) { 10409 *group_size = soc_mem_field32_get(unit, mem, l3_ecmp_count, COUNT_0f); 10410 } 10411 if (base_idx) { 10412 *base_idx = soc_mem_field32_get(unit, mem, l3_ecmp_count, BASE_PTR_0f); 10413 } 10414 } 10415 } 10416 10417 if (ecmp_hash_16bits) { 10418 if (group_size) { 10419 *group_size = soc_mem_field32_get(unit, mem, 10420 l3_ecmp_count, COUNTf); 10421 #if defined(BCM_TOMAHAWK3_SUPPORT) 10422 if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) { 10423 lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit, l3_ecmp_count, 10424 LB_MODEf); 10425 switch (lb_mode) { 10426 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_256: 10427 *group_size = 256 - 1; 10428 weighted = 1; 10429 break; 10430 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_512: 10431 *group_size = 512 - 1; 10432 weighted = 1; 10433 break; 10434 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_1024: 10435 *group_size = 1024 - 1; 10436 weighted = 1; 10437 break; 10438 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_2048: 10439 *group_size = 2048 - 1; 10440 weighted = 1; 10441 break; 10442 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_4096: 10443 *group_size = 4096 - 1; 10444 weighted = 1; 10445 break; 10446 } 10447 } 10448 #endif 10449 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 10450 if (soc_feature(unit, soc_feature_dgm)) { 10451 *group_size += BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[grp_idx]; 10452 } 10453 #endif 10454 } 10455 if (base_idx) { 10456 *base_idx = soc_mem_field32_get(unit, mem, l3_ecmp_count, BASE_PTRf); 10457 } 10458 } 10459 10460 #ifdef BCM_TOMAHAWK_SUPPORT 10461 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 10462 group_size) { 10463 if (!weighted && (bcm_opt_ecmp_group_is_rh(unit, grp_idx) || 10464 (!BCM_XGS3_L3_MAX_ECMP_MODE(unit) && (grp_idx & 0x1) && 10465 bcm_opt_ecmp_group_is_rh(unit, grp_idx - 1)))) { 10466 int min = 6; int max = 14; 10467 if ((SOC_IS_TOMAHAWK2(unit)) || 10468 (SOC_IS_TOMAHAWK3(unit))) { 10469 max = 15; 10470 } 10471 if (*group_size > max || *group_size < min) { 10472 return BCM_E_INTERNAL; 10473 } else { 10474 *group_size = 1 << *group_size; 10475 } 10476 /* will be added back outside */ 10477 (*group_size)--; 10478 } 10479 } 10480 #endif 10481 return BCM_E_NONE; 10482 } 10483 10484 /* 10485 * Function: 10486 * _bcm_xgs3_l3_ecmp_grp_info_set 10487 * Purpose: 10488 * Set ecmp group size and base_idx for the chips with 1k ecmp groups, 10489 * especially for TD+ with configurable 256/1k ecmp groups meantime. 10490 * Parameters: 10491 * unit - (IN)SOC unit number. 10492 * grp_idx - (IN)ECMP group idx. 10493 * l3_ecmp_count - (IN)Buffer for l3_ecmp_count hw entry. 10494 * initial_l3_ecmp_group - (IN)Buffer for initial_l3_ecmp_group hw entry. 10495 * initial_l3_ecmp_flag- (IN)If set initial_l3_ecmp_group hw entry. 10496 * group_size - (IN)ecmp group size. 10497 * base_idx- (IN)ecmp base entry. 10498 * alternate_cnt- (IN)alternate_cnt for DGM. 10499 * ecmp_flags - (IN) ecmp flags 10500 * Returns: 10501 * BCM_E_XXX. 10502 */ 10503 int 10504 _bcm_xgs3_l3_ecmp_grp_info_set(int unit, int grp_idx, 10505 void *l3_ecmp_count, 10506 void *initial_l3_ecmp_group, 10507 int initial_l3_ecmp_flag, 10508 int group_size, int base_idx, 10509 int alternate_cnt, 10510 uint32 ecmp_flags) 10511 { 10512 uint32 ing_config_2; 10513 uint8 ecmp_hash_16bits = 1; /*1k ecmp groups by default*/ 10514 soc_mem_t mem = L3_ECMP_COUNTm; 10515 #ifdef BCM_TOMAHAWK3_SUPPORT 10516 int lb_mode = 0; 10517 #endif 10518 10519 if (!l3_ecmp_count){ 10520 return BCM_E_PARAM; 10521 } 10522 10523 if (initial_l3_ecmp_flag 10524 && (!initial_l3_ecmp_group)) { 10525 return BCM_E_PARAM; 10526 } 10527 10528 /*TD+ only for 256 ECMP groups*/ 10529 if (SOC_IS_TRIDENT(unit)) { 10530 SOC_IF_ERROR_RETURN 10531 (READ_ING_CONFIG_2r(unit, &ing_config_2)); 10532 ecmp_hash_16bits = 10533 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 10534 ECMP_HASH_16BITSf); 10535 if (!ecmp_hash_16bits) { 10536 if (group_size != -1) { 10537 if (!group_size) { 10538 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_0f, group_size); 10539 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_1f, group_size); 10540 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_2f, group_size); 10541 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_3f, group_size); 10542 10543 if (initial_l3_ecmp_flag) { 10544 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10545 initial_l3_ecmp_group, COUNT_0f, group_size); 10546 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10547 initial_l3_ecmp_group, COUNT_1f, group_size); 10548 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10549 initial_l3_ecmp_group, COUNT_2f, group_size); 10550 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10551 initial_l3_ecmp_group, COUNT_3f, group_size); 10552 } 10553 } else { 10554 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_0f, group_size - 1); 10555 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_1f, group_size - 1); 10556 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_2f, group_size - 1); 10557 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_3f, group_size - 1); 10558 10559 if (initial_l3_ecmp_flag) { 10560 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10561 initial_l3_ecmp_group, COUNT_0f, group_size - 1); 10562 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10563 initial_l3_ecmp_group, COUNT_1f, group_size - 1); 10564 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10565 initial_l3_ecmp_group, COUNT_2f, group_size - 1); 10566 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10567 initial_l3_ecmp_group, COUNT_3f, group_size - 1); 10568 } 10569 } 10570 } 10571 10572 if (base_idx != -1) { 10573 /* Set group base pointer. */ 10574 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 10575 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, 10576 BASE_PTR_0f, base_idx); 10577 } 10578 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_1f)) { 10579 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, 10580 BASE_PTR_1f, base_idx); 10581 } 10582 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_2f)) { 10583 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, 10584 BASE_PTR_2f, base_idx); 10585 } 10586 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_3f)) { 10587 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, 10588 BASE_PTR_3f, base_idx); 10589 } 10590 10591 if (initial_l3_ecmp_flag) { 10592 if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_0f)) { 10593 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10594 initial_l3_ecmp_group, BASE_PTR_0f, base_idx); 10595 } 10596 if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_1f)) { 10597 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10598 initial_l3_ecmp_group, BASE_PTR_1f, base_idx); 10599 } 10600 if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_2f)) { 10601 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10602 initial_l3_ecmp_group, BASE_PTR_2f, base_idx); 10603 } 10604 if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_3f)) { 10605 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10606 initial_l3_ecmp_group, BASE_PTR_3f, base_idx); 10607 } 10608 } 10609 10610 } 10611 } 10612 } 10613 #if defined(BCM_TOMAHAWK3_SUPPORT) 10614 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 10615 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical) 10616 && (ecmp_flags & BCM_L3_ECMP_OVERLAY)) { 10617 mem = ECMP_GROUP_HIERARCHICALm; 10618 } 10619 #endif 10620 /*For all chips with 1k ECMP groups*/ 10621 if (ecmp_hash_16bits) { 10622 if (group_size != -1) { 10623 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 10624 if (soc_feature(unit, soc_feature_dgm) && group_size) { 10625 group_size -= alternate_cnt; 10626 if (group_size < 0) { 10627 return BCM_E_INTERNAL; 10628 } 10629 } 10630 #endif 10631 if (!group_size) { 10632 soc_mem_field32_set(unit, mem, 10633 l3_ecmp_count, COUNTf, group_size); 10634 if (initial_l3_ecmp_flag) { 10635 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10636 initial_l3_ecmp_group, COUNTf, group_size); 10637 } 10638 } else { 10639 #ifdef BCM_TOMAHAWK_SUPPORT 10640 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 10641 if (ecmp_flags & BCM_L3_ECMP_RH_OPT) { 10642 switch (group_size) { 10643 case 64: group_size = 6; 10644 break; 10645 case 128: group_size = 7; 10646 break; 10647 case 256: group_size = 8; 10648 break; 10649 case 512: group_size = 9; 10650 break; 10651 case 1024: group_size = 10; 10652 break; 10653 case 2048: group_size = 11; 10654 break; 10655 case 4096: group_size = 12; 10656 break; 10657 case 8192: group_size = 13; 10658 break; 10659 case 16384: group_size = 14; 10660 break; 10661 case 32768: group_size = 15; 10662 if (SOC_IS_TOMAHAWK2(unit) || SOC_IS_TOMAHAWK3(unit)) { 10663 break; 10664 } 10665 /* else fall through */ 10666 default: 10667 return BCM_E_INTERNAL; 10668 } 10669 group_size++; 10670 } 10671 } 10672 #endif 10673 10674 #ifdef BCM_TOMAHAWK3_SUPPORT 10675 if ((soc_feature(unit, soc_feature_l3_ecmp_weighted)) && 10676 (ecmp_flags & BCM_L3_ECMP_WEIGHTED)) { 10677 /* For Weighted ECMP with group size larger than 128 10678 COUNT field is ignored */ 10679 switch (group_size) { 10680 case 256: 10681 lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_256; 10682 break; 10683 case 512: 10684 lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_512; 10685 break; 10686 case 1024: 10687 lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_1024; 10688 break; 10689 case 2048: 10690 lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_2048; 10691 break; 10692 case 4096: 10693 lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_4096; 10694 break; 10695 default: 10696 return BCM_E_PARAM; 10697 } 10698 soc_mem_field32_set(unit, mem, l3_ecmp_count, 10699 LB_MODEf, lb_mode); 10700 BCM_IF_ERROR_RETURN(bcm_opt_ecmp_lb_mode_set(unit, grp_idx, lb_mode)); 10701 } else 10702 #endif 10703 { 10704 soc_mem_field32_set(unit, mem, 10705 l3_ecmp_count, COUNTf, group_size-1); 10706 } 10707 10708 if (initial_l3_ecmp_flag) { 10709 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10710 initial_l3_ecmp_group, COUNTf, group_size - 1); 10711 } 10712 } 10713 } 10714 10715 if (base_idx != -1) { 10716 if (SOC_MEM_FIELD_VALID(unit, mem, BASE_PTRf)) { 10717 soc_mem_field32_set(unit, mem, 10718 l3_ecmp_count, BASE_PTRf, base_idx); 10719 } 10720 if (initial_l3_ecmp_flag) { 10721 if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTRf)) { 10722 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 10723 initial_l3_ecmp_group, BASE_PTRf, base_idx); 10724 } 10725 } 10726 } 10727 10728 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 10729 if (soc_feature(unit, soc_feature_dgm)) { 10730 BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[grp_idx] = alternate_cnt; 10731 } 10732 #endif 10733 } 10734 10735 return BCM_E_NONE; 10736 } 10737 10738 /* 10739 * Function: 10740 * _bcm_xgs3_l3_ecmp_grp_info_get 10741 * Purpose: 10742 * Get ecmp group size and base idx. 10743 * Parameters: 10744 * unit - (IN) SOC unit number. 10745 * grp_idx - (IN) Index of ECMP group count table. 10746 * group_size - (OUT) Ecmp group size. 10747 * base_idx - (OUT) Ecmp base entry 10748 * Returns: 10749 * BCM_E_XXX. 10750 */ 10751 int 10752 _bcm_xgs3_l3_ecmp_grp_info_get(int unit, int grp_idx, 10753 int *group_size, int *base_idx) 10754 { 10755 uint32 hw_buf[SOC_MAX_MEM_WORDS]; 10756 uint32 base_0, base_1; 10757 uint32 count_0, count_1, count_2, count_3, total_count; 10758 soc_mem_t mem = L3_ECMP_COUNTm; 10759 10760 #if defined(BCM_TOMAHAWK3_SUPPORT) 10761 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 10762 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 10763 ecmp_mode_hierarchical) && (grp_idx < 10764 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 10765 mem = ECMP_GROUP_HIERARCHICALm; 10766 } 10767 #endif 10768 if (!SOC_MEM_IS_VALID(unit, mem)) { 10769 return BCM_E_NONE; 10770 } 10771 10772 sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 10773 SOC_IF_ERROR_RETURN( 10774 soc_mem_read(unit, mem, MEM_BLOCK_ANY, 10775 grp_idx, hw_buf)); 10776 10777 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 10778 BCM_IF_ERROR_RETURN( 10779 _bcm_xgs3_l3_ecmp_1k_groups_info_get(unit, grp_idx, hw_buf, 10780 group_size, base_idx)); 10781 if (group_size) { 10782 *group_size += 1; 10783 } 10784 } else if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, COUNT_0f)) { 10785 10786 base_0 = base_1 = count_0 = count_1 = count_2 = count_3 = 0; 10787 count_0 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10788 hw_buf, COUNT_0f) + 1); 10789 if (soc_feature(unit, soc_feature_ecmp_1k_paths_4_subgroups)) { 10790 count_1 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10791 hw_buf, COUNT_1f) + 1); 10792 count_2 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10793 hw_buf, COUNT_2f) + 1); 10794 count_3 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10795 hw_buf, COUNT_3f) + 1); 10796 10797 base_0 = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10798 hw_buf, BASE_PTR_0f); 10799 base_1 = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10800 hw_buf, BASE_PTR_1f); 10801 total_count = count_0; 10802 if (base_1 != base_0) { 10803 total_count += (count_1 + count_2 + count_3); 10804 } 10805 } else { 10806 total_count = count_0; 10807 } 10808 if (group_size) { 10809 *group_size = total_count; 10810 } 10811 10812 if (base_idx) { 10813 *base_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10814 hw_buf, BASE_PTR_0f); 10815 } 10816 } else { 10817 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, COUNTf)) { 10818 if (group_size) { 10819 *group_size = (soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10820 hw_buf, COUNTf) + 1); 10821 } 10822 } 10823 10824 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTRf)) { 10825 if (base_idx) { 10826 *base_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 10827 hw_buf, BASE_PTRf); 10828 } 10829 } 10830 } 10831 10832 return BCM_E_NONE; 10833 } 10834 10835 /* 10836 * Function: 10837 * _bcm_xgs3_ecmp_max_grp_size_get 10838 * Purpose: 10839 * Get maximum number of next hop entries in ecmp group 10840 * Parameters: 10841 * unit - (IN)SOC unit number. 10842 * ecmp_group_id - (IN)Ecmp group id. 10843 * *grp_sz - (OUT)Ecmp group size. 10844 * Returns: 10845 * void 10846 */ 10847 int 10848 _bcm_xgs3_ecmp_max_grp_size_get(int unit, int ecmp_group_id, int *grp_sz) 10849 { 10850 int max_group_size; /* Maximum ecmp group size. */ 10851 int rv = BCM_E_NONE; 10852 10853 #if defined(BCM_TRX_SUPPORT) 10854 10855 #ifdef BCM_TRIUMPH2_SUPPORT 10856 if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 10857 if (BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) { 10858 /* 1k ecmp grp */ 10859 *grp_sz = BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_group_id]; 10860 return BCM_E_NONE; 10861 } 10862 } 10863 #endif 10864 10865 if ((SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) && (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))){ 10866 rv = _bcm_xgs3_l3_ecmp_grp_info_get(unit, 10867 ecmp_group_id + 1, grp_sz, NULL); 10868 if (BCM_FAILURE(rv)) { 10869 return rv; 10870 } 10871 } else 10872 #endif /* BCM_TRX_SUPPORT */ 10873 { 10874 10875 /* Set number of next hop entries in ecmp group. */ 10876 max_group_size = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 10877 10878 /* Return max group size to the caller. */ 10879 *grp_sz = max_group_size; 10880 } 10881 return rv; 10882 } 10883 10884 /* 10885 * Function: 10886 * _bcm_xgs3_ecmp_max_grp_size_set 10887 * Purpose: 10888 * Set maximum number of next hop entries in ecmp group. 10889 * Parameters: 10890 * unit - (IN)SOC unit number. 10891 * ecmp_group_id - (IN)Ecmp group id. 10892 * max_grp_sz - (IN)Ecmp max group size. 10893 * ecmp_flags - (IN)Ecmp group flags 10894 * Returns: 10895 * void 10896 */ 10897 #if defined(BCM_TRX_SUPPORT) 10898 STATIC INLINE int 10899 _bcm_xgs3_ecmp_max_grp_size_set(int unit, int ecmp_group_id, 10900 int max_grp_sz, uint32 ecmp_flags) 10901 { 10902 #if defined(BCM_TRX_SUPPORT) 10903 uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry. */ 10904 int rv = BCM_E_NONE; 10905 int subgrp_cnt = 0; 10906 10907 #ifdef BCM_TRIUMPH2_SUPPORT 10908 if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 10909 if (BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) { 10910 /* 1k ecmp grp */ 10911 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_group_id] = max_grp_sz; 10912 return BCM_E_NONE; 10913 } 10914 } 10915 #endif 10916 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 10917 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 10918 sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 10919 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 10920 rv = _bcm_xgs3_l3_ecmp_grp_info_set(unit, (ecmp_group_id + 1), 10921 hw_buf, NULL, 0, max_grp_sz, -1, 0, ecmp_flags); 10922 if (BCM_FAILURE(rv)) { 10923 return rv; 10924 } 10925 } else if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, COUNTf)) { 10926 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 10927 COUNTf, max_grp_sz -1); 10928 } else if (soc_feature(unit, soc_feature_ecmp_1k_paths_4_subgroups) 10929 && (max_grp_sz >= 256)) { 10930 subgrp_cnt = ((max_grp_sz + 3) / 4); 10931 rv = soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 10932 (ecmp_group_id + 1), hw_buf); 10933 if (BCM_FAILURE(rv)) { 10934 return rv; 10935 } 10936 soc_mem_field32_set(unit, L3_ECMP_COUNTm, 10937 hw_buf, COUNT_0f, (subgrp_cnt - 1)); 10938 soc_mem_field32_set(unit, L3_ECMP_COUNTm, 10939 hw_buf, COUNT_1f, (subgrp_cnt - 1)); 10940 soc_mem_field32_set(unit, L3_ECMP_COUNTm, 10941 hw_buf, COUNT_2f, (subgrp_cnt - 1)); 10942 soc_mem_field32_set(unit, L3_ECMP_COUNTm, 10943 hw_buf, COUNT_3f, 10944 ((max_grp_sz - (3 * subgrp_cnt) - 1))); 10945 } else { 10946 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 10947 COUNT_0f, max_grp_sz - 1); 10948 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 10949 COUNT_1f, max_grp_sz - 1); 10950 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 10951 COUNT_2f, max_grp_sz - 1); 10952 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 10953 COUNT_3f, max_grp_sz - 1); 10954 } 10955 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 10956 (ecmp_group_id + 1), hw_buf); 10957 if (BCM_FAILURE(rv)) { 10958 return rv; 10959 } 10960 return BCM_E_NONE; 10961 } else { 10962 return BCM_E_PARAM; 10963 } 10964 } 10965 #endif /* BCM_TRX_SUPPORT */ 10966 10967 return BCM_E_UNAVAIL; 10968 } 10969 #endif /* BCM_TRX_SUPPORT */ 10970 10971 /* 10972 * Function: 10973 * _bcm_xgs3_ecmp_grp_size_get 10974 * Purpose: 10975 * Get number of next hop entries in ecmp group 10976 * Parameters: 10977 * unit - (IN)SOC unit number. 10978 * ecmp_group_id - (IN)Ecmp group id. 10979 * nh_arr - (IN)Ecmp group memeber next hop entries. 10980 * *grp_sz - (OUT)Ecmp group size. 10981 * Returns: 10982 * void 10983 */ 10984 STATIC INLINE void 10985 _bcm_xgs3_ecmp_grp_size_get(int unit, int ecmp_group_id, 10986 int *nh_arr, int *grp_sz) 10987 { 10988 int ecmp_max_paths=0; /* Maximum number of paths for group. */ 10989 int ecmp_count; /* Ecmp group next hop count. */ 10990 int idx; /* Iteration index. */ 10991 10992 /* Calculate maximum group size. */ 10993 /* for rh, it's dynamic_size*/ 10994 (void) _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_id, &ecmp_max_paths); 10995 10996 /* Check real group size. */ 10997 ecmp_count = 0; 10998 for (idx = 0; idx < ecmp_max_paths; idx++) { 10999 if (nh_arr[idx] != 0) { 11000 ecmp_count++; 11001 } else { 11002 break; 11003 } 11004 } 11005 *grp_sz = ecmp_count; 11006 return; 11007 } 11008 11009 /* 11010 * Function: 11011 * _bcm_xgs3_ecmp_tbl_read 11012 * Purpose: 11013 * Read up to max_cnt values from ecmp table. 11014 * Parameters: 11015 * unit - (IN)SOC unit number. 11016 * ecmp_group_idx - (IN)First ecmp entry index to read. 11017 * ecmp_grp - (OUT)Buffer to fill group info. 11018 * ecmp_count - (OUT)Actual ecmp group size. 11019 * Returns: 11020 * BCM_E_XXX 11021 */ 11022 STATIC INLINE int 11023 _bcm_xgs3_ecmp_tbl_read(int unit, int ecmp_group_idx, 11024 int *ecmp_grp, int *ecmp_count) 11025 { 11026 int rv = BCM_E_UNAVAIL; /* Operation return value. */ 11027 int max_group_size = 0; 11028 _bcm_l3_tbl_t *tbl_ptr; /* ECMP table pointer. */ 11029 11030 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 11031 #ifdef BCM_TOMAHAWK3_SUPPORT 11032 if ((ecmp_group_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) && 11033 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical) 11034 && (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) { 11035 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 11036 } 11037 #endif 11038 11039 /* Make sure entry is inuse. */ 11040 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, 11041 ecmp_group_idx)) { 11042 return (BCM_E_NOT_FOUND); 11043 } 11044 11045 /* for rh, it's dynamic_size*/ 11046 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_group_size); 11047 if (rv < 0) { 11048 return rv; 11049 } 11050 11051 /* Read ecmp group members from hw. */ 11052 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ecmp_grp_get) && max_group_size) { 11053 BCM_XGS3_L3_MODULE_LOCK(unit); 11054 rv = BCM_XGS3_L3_HWCALL_EXEC (unit, ecmp_grp_get) (unit, ecmp_group_idx, 11055 max_group_size, 11056 ecmp_grp); 11057 BCM_XGS3_L3_MODULE_UNLOCK(unit); 11058 } 11059 11060 /* Get group size. */ 11061 if (ecmp_count) { 11062 _bcm_xgs3_ecmp_grp_size_get(unit, ecmp_group_idx, ecmp_grp, ecmp_count); 11063 } 11064 return rv; 11065 } 11066 11067 /* 11068 * Function: 11069 * _bcm_xgs3_ecmp_grp_hash_calc 11070 * Purpose: 11071 * Calculate ecmp group next hops hash(signature). 11072 * Parameters: 11073 * unit - (IN)SOC unit number. 11074 * buf - (IN)Next hop entry information. 11075 * hash - (OUT) Hash(signature) calculated value. 11076 * Returns: 11077 * BCM_X_XXX 11078 */ 11079 STATIC int 11080 _bcm_xgs3_ecmp_grp_hash_calc(int unit, void *buf_ecmp, uint16 *hash) 11081 { 11082 int *buf = NULL; 11083 _bcm_l3_ecmp_group_buffer_t *ecmp_buf = buf_ecmp; 11084 11085 if ((NULL == ecmp_buf) || (NULL == hash) || 11086 (NULL == ecmp_buf->group_buffer)) { 11087 return (BCM_E_PARAM); 11088 } 11089 11090 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &buf)); 11091 11092 if (ecmp_buf->dlb_group_buffer) { 11093 /* DLB ECMP group excluding filler */ 11094 sal_memcpy (buf, ecmp_buf->dlb_group_buffer, 11095 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) * sizeof(int)); 11096 } else { 11097 sal_memcpy (buf, ecmp_buf->group_buffer, 11098 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) * sizeof(int)); 11099 } 11100 11101 _shr_sort(buf, BCM_XGS3_L3_ECMP_MAX_PATHS(unit), sizeof(int), 11102 _bcm_xgs3_cmp_int); 11103 /* Calculate hash of next hop indexes, which are members in the group. */ 11104 *hash = _shr_crc16(0, (uint8 *) buf, 11105 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) * sizeof(int)); 11106 sal_free(buf); 11107 return (BCM_E_NONE); 11108 } 11109 11110 /* 11111 * Function: 11112 * _bcm_xgs3_ecmp_grp_cmp 11113 * Purpose: 11114 * Compare ecmp group next hop members with group in hw. 11115 * Parameters: 11116 * unit - (IN)SOC unit number. 11117 * buf - (IN)Next hop indexes. 11118 * grp_idx - (IN)ECMP group index in hw. 11119 * cmp_result - (OUT)Comparison result. 11120 * Returns: 11121 * BCM_E_XXX 11122 */ 11123 STATIC int 11124 _bcm_xgs3_ecmp_grp_cmp(int unit, void *buf, int grp_idx, int *cmp_result) 11125 { 11126 int ecmp_max_paths = 0; /* Maximum number of ecmp paths. */ 11127 int ecmp_count = 0; /* Count indexes in the group. */ 11128 int *ecmp_grp; /* Ecmp group from hw. */ 11129 int *nh_idx; /* Ecmp group buffer pointer. */ 11130 int idx; /* Iteration index. */ 11131 int rv; /* Operation return status. */ 11132 int count = 0; /* Count indexes in the group. */ 11133 int *dlb_ecmp_grp = NULL; /* DLB ecmp group excluding filler. */ 11134 int *cmp_grp = NULL; 11135 _bcm_l3_ecmp_group_buffer_t *ecmp_buf = buf; 11136 11137 /* Input parameters sanity check. */ 11138 if ((NULL == cmp_result) || (NULL == ecmp_buf) || 11139 (NULL == ecmp_buf->group_buffer)) { 11140 return (BCM_E_PARAM); 11141 } 11142 11143 /* Get maximum ecmp group size for group index. */ 11144 /*for rh, it's dynamic_size*/ 11145 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, grp_idx, &ecmp_max_paths); 11146 if (rv < 0) { 11147 return rv; 11148 } 11149 11150 /* Get next hops array. */ 11151 if (ecmp_buf->dlb_group_buffer) { 11152 nh_idx = ecmp_buf->dlb_group_buffer; 11153 } else { 11154 nh_idx = ecmp_buf->group_buffer; 11155 } 11156 11157 /* Get ecmp group size. */ 11158 _bcm_xgs3_ecmp_grp_size_get(unit, grp_idx, nh_idx, &ecmp_count); 11159 11160 /* Allocate ecmp group buffer. */ 11161 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 11162 11163 /* Read ecmp group from hw. */ 11164 rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, ecmp_grp, &count); 11165 if (BCM_FAILURE(rv)) { 11166 sal_free(ecmp_grp); 11167 return (rv); 11168 } 11169 11170 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 11171 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 11172 bcm_l3_egress_ecmp_t ecmp; 11173 int location_offset = 0; 11174 int primary_count = 0; 11175 int i = 0, j = 0; 11176 SHR_BITDCL *group_bitmap_ptr = NULL; 11177 11178 bcm_l3_egress_ecmp_t_init(&ecmp); 11179 11180 ecmp.ecmp_intf = grp_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 11181 11182 rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, &ecmp); 11183 if (BCM_FAILURE(rv)) { 11184 sal_free(ecmp_grp); 11185 return (rv); 11186 } 11187 11188 if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp.dynamic_mode)) { 11189 group_bitmap_ptr = 11190 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, grp_idx); 11191 11192 if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 11193 SHR_BITCOUNT_RANGE(group_bitmap_ptr, primary_count, 11194 0, ecmp_max_paths / 2); 11195 /* Only alternate members exist */ 11196 if (0 == primary_count) { 11197 location_offset = ecmp_max_paths / 2; 11198 } 11199 } 11200 11201 /* Allocate DLB ecmp group buffer. */ 11202 rv = _bcm_xgs3_l3_ecmp_group_alloc(unit, &dlb_ecmp_grp); 11203 if (BCM_FAILURE(rv)) { 11204 sal_free(ecmp_grp); 11205 return (rv); 11206 } 11207 11208 /* Exclude filler members from expanded DLB group */ 11209 for (i = 0; i < count; i++) { 11210 if (SHR_BITGET(group_bitmap_ptr, i + location_offset)) { 11211 dlb_ecmp_grp[j++] = ecmp_grp[i]; 11212 } 11213 } 11214 } 11215 } 11216 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 11217 11218 cmp_grp = dlb_ecmp_grp ? dlb_ecmp_grp : ecmp_grp; 11219 11220 /* Sort the NH members if they have not been sorted */ 11221 11222 if ((BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, grp_idx, \ 11223 BCM_L3_ECMP_PATH_NO_SORTING)) 11224 || (SOC_IS_TOMAHAWK3(unit) && BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, grp_idx, \ 11225 BCM_L3_ECMP_WEIGHTED)) 11226 ) { 11227 _shr_sort(cmp_grp, ecmp_count, sizeof(int), _bcm_xgs3_cmp_int); 11228 } 11229 11230 /* Compare ecmp groups. */ 11231 if (sal_memcmp(nh_idx, cmp_grp, (ecmp_count * sizeof(int)))) { 11232 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 11233 sal_free(ecmp_grp); 11234 if (dlb_ecmp_grp) { 11235 sal_free(dlb_ecmp_grp); 11236 } 11237 return (BCM_E_NONE); 11238 } 11239 11240 /* Make sure group doesn't contain any additional indexes. */ 11241 for (idx = ecmp_count; idx < ecmp_max_paths; idx++) { 11242 if (cmp_grp[idx]) { 11243 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 11244 sal_free(ecmp_grp); 11245 if (dlb_ecmp_grp) { 11246 sal_free(dlb_ecmp_grp); 11247 } 11248 return (BCM_E_NONE); 11249 } 11250 } 11251 sal_free(ecmp_grp); 11252 if (dlb_ecmp_grp) { 11253 sal_free(dlb_ecmp_grp); 11254 } 11255 *cmp_result = BCM_L3_CMP_EQUAL; 11256 return (BCM_E_NONE); 11257 } 11258 11259 /* 11260 * Function: 11261 * _bcm_xgs3_ecmp_group_del 11262 * Purpose: 11263 * Delete ecmp group 11264 * Parameters: 11265 * unit - (IN)SOC unit number. 11266 * ecmp_group_id - (IN)Ecmp group id. 11267 * flags - (IN)_BCM_L3_SHR_CLEAN 11268 * Returns: 11269 * BCM_E_XXX 11270 */ 11271 STATIC int 11272 _bcm_xgs3_ecmp_group_del(int unit, int ecmp_group_id, uint32 flags) 11273 { 11274 _bcm_l3_tbl_op_t data; 11275 _bcm_l3_ecmp_group_info_t ecmp_info; 11276 #ifdef BCM_TRX_SUPPORT 11277 int max_paths = 0; 11278 uint32 ing_config_2; 11279 uint8 ecmp_hash_16bits; 11280 #endif 11281 11282 /* Initialization */ 11283 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 11284 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 11285 #ifdef BCM_TOMAHAWK3_SUPPORT 11286 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 11287 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11288 ecmp_mode_hierarchical) && (ecmp_group_id < 11289 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 11290 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 11291 } 11292 #endif 11293 data.oper_flags = flags; 11294 11295 /* Check hw call is defined. */ 11296 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, ecmp_grp_del)) { 11297 return (BCM_E_UNAVAIL); 11298 } 11299 11300 /* Calculate ECMP group id. */ 11301 if ((ecmp_group_id > data.tbl_ptr->idx_max) || 11302 (ecmp_group_id < data.tbl_ptr->idx_min)) { 11303 return (BCM_E_PARAM); 11304 } 11305 11306 data.entry_index = ecmp_group_id; 11307 sal_memset(&ecmp_info, 0, sizeof(ecmp_info)); 11308 11309 #ifdef BCM_TRX_SUPPORT 11310 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 11311 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 11312 /* for rh, it's dynamic_size */ 11313 BCM_IF_ERROR_RETURN 11314 (_bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_id, 11315 &max_paths)); 11316 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 11317 if (!soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 11318 max_paths > 1024) { 11319 max_paths = 1024; 11320 } 11321 /*For TD+*/ 11322 if (SOC_IS_TRIDENT(unit)){ 11323 SOC_IF_ERROR_RETURN 11324 (READ_ING_CONFIG_2r(unit, &ing_config_2)); 11325 ecmp_hash_16bits = 11326 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 11327 ECMP_HASH_16BITSf); 11328 if ((!ecmp_hash_16bits) && (max_paths > 256)) { 11329 max_paths = 256; 11330 } 11331 } 11332 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11333 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11334 } else if (SOC_IS_TRIDENT(unit)) { 11335 if (max_paths > 256) { 11336 max_paths = 256; 11337 } 11338 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11339 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11340 } else if (SOC_IS_SCORPION(unit)) { 11341 if (max_paths > 256) { 11342 max_paths = 256; 11343 } 11344 data.width = max_paths; 11345 } else if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 11346 SOC_IS_SABER2(unit) || SOC_IS_GREYHOUND2(unit)) { 11347 if (max_paths > 64) { 11348 max_paths = 64; 11349 } 11350 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11351 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11352 } else if (SOC_IS_MONTEREY(unit)) { 11353 if (max_paths > 256) { 11354 max_paths = 256; 11355 } 11356 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11357 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11358 } else if SOC_IS_KATANAX(unit) { 11359 if (max_paths > 1024) { 11360 max_paths = 1024; 11361 } 11362 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11363 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11364 } else { 11365 if (max_paths > 32) { 11366 max_paths = 32; 11367 } 11368 data.width = max_paths; 11369 if (SOC_IS_TRIUMPH2(unit) || 11370 SOC_IS_APOLLO(unit) || 11371 SOC_IS_VALKYRIE2(unit) || 11372 SOC_IS_KATANAX(unit)) { 11373 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11374 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11375 } 11376 } 11377 ecmp_info.max_paths = max_paths; 11378 } else { 11379 return (BCM_E_PARAM); 11380 } 11381 } else 11382 #endif 11383 { 11384 ecmp_info.max_paths = _BCM_SINGLE_WIDE; 11385 data.width = _BCM_SINGLE_WIDE; 11386 } 11387 data.info = &ecmp_info; 11388 data.delete_func = BCM_XGS3_L3_HWCALL(unit, ecmp_grp_del); 11389 11390 /* Delete ECMP group table entry. */ 11391 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_del(unit, &data)); 11392 11393 return (BCM_E_NONE); 11394 } 11395 11396 11397 /* 11398 * Function: 11399 * bcm_xgs3_ecmp_group_del 11400 * Purpose: 11401 * 1. delete ecmp group members 11402 * 2. if _BCM_L3_SHR_CLEAN is not been setup : 11403 * update a reference count of existing group 11404 * if it is used by other prefixes 11405 * Parameters: 11406 * unit - (IN)SOC unit number. 11407 * ecmp_group_id - (IN)Ecmp group id. 11408 * flags - (IN)_BCM_L3_SHR_CLEAN 11409 * Returns: 11410 * BCM_E_XXX 11411 */ 11412 int 11413 bcm_xgs3_ecmp_group_del(int unit, int ecmp_group_id, uint32 flags) 11414 { 11415 _bcm_l3_tbl_t *tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 11416 #ifdef BCM_TRIDENT2_SUPPORT 11417 int max_vp_lags = 0; 11418 int ol_ecmp_in_use = 0; 11419 int split_idx = 0; 11420 #endif 11421 int min_ul_grp = 0; 11422 11423 /* Delete ECMP group table entry. */ 11424 BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, flags)); 11425 11426 11427 /* if just need to clean group members, return here */ 11428 if (flags & _BCM_L3_SHR_CLEAN) { 11429 return BCM_E_NONE; 11430 } 11431 11432 #ifdef BCM_TOMAHAWK3_SUPPORT 11433 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 11434 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11435 ecmp_mode_hierarchical) && (ecmp_group_id < 11436 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 11437 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 11438 } 11439 #endif 11440 11441 /* update ecmp group ref count */ 11442 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_id)) { 11443 BCM_XGS3_L3_ECMP_GRP_CNT(unit)--; 11444 if (BCM_XGS3_L3_ECMP_GRP_CNT(unit) == 0) { 11445 BCM_XGS3_L3_ECMP_IN_USE(unit) = 0; 11446 } 11447 } 11448 11449 /* update ecmp_inuse flag if last ECMP group is gone */ 11450 #ifdef BCM_TRIDENT2_SUPPORT 11451 if (soc_feature(unit, soc_feature_vp_lag)) { 11452 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 11453 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 11454 } 11455 11456 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 11457 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 11458 ol_ecmp_in_use = 1; 11459 split_idx = tbl_ptr->split_idx; 11460 11461 if ((tbl_ptr->split_maxused == (tbl_ptr->idx_min)) && 11462 (!BCM_XGS3_L3_ENT_REF_CNT( 11463 tbl_ptr, tbl_ptr->split_maxused))) { 11464 11465 ol_ecmp_in_use = 0; 11466 } 11467 } 11468 #endif 11469 /* if max_vp_lags has valid value or if this is RIOT/hierarchical ECMP flow then 11470 idx_maxused is not 0 and has to be checked with offset value and not 0. */ 11471 if ((max_vp_lags > 0) || (split_idx)) { 11472 if (max_vp_lags > 0) { 11473 if (((max_vp_lags + split_idx - 1) == tbl_ptr->idx_maxused) && 11474 (ol_ecmp_in_use == 0)) { 11475 11476 if (!BCM_XGS3_L3_ENT_REF_CNT 11477 (tbl_ptr, (max_vp_lags + split_idx))) { 11478 11479 BCM_XGS3_L3_ECMP_IN_USE(unit) = 0; 11480 } 11481 } 11482 } else { 11483 11484 if ((split_idx == tbl_ptr->idx_maxused) && 11485 (ol_ecmp_in_use == 0)) { 11486 11487 if (!BCM_XGS3_L3_ENT_REF_CNT 11488 (tbl_ptr, split_idx)) { 11489 11490 BCM_XGS3_L3_ECMP_IN_USE(unit) = 0; 11491 } 11492 } 11493 } 11494 } else 11495 #endif 11496 #ifdef BCM_TOMAHAWK3_SUPPORT 11497 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 11498 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11499 ecmp_mode_hierarchical)) { 11500 min_ul_grp = (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)) / 2; 11501 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 11502 } 11503 #endif 11504 if (((min_ul_grp == tbl_ptr->idx_maxused) || 11505 (0 == tbl_ptr->idx_maxused)) && /* No group allocated */ 11506 (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, 0) == 0)) { 11507 BCM_XGS3_L3_ECMP_IN_USE(unit) = 0; 11508 } 11509 return (BCM_E_NONE); 11510 } 11511 11512 /* 11513 * Function: 11514 * _bcm_xgs3_ecmp_group_add 11515 * Purpose: 11516 * Write ecmp group to the hw. 11517 * Parameters: 11518 * unit - (IN)SOC unit number. 11519 * flags - (IN)BCM_L3_REPLACE && BCM_L3_WITH_ID 11520 * ecmp_count - (IN)Ecmp group next hops count. 11521 * max_paths - (IN)Ecmp group max next hops count. 11522 * ecmp_group - (IN)Ecmp group. 11523 * group_index - (IN|OUT)Ecmp group index 11524 * primary_count- (IN)Ecmp primary_count 11525 * dlb_member_bitmap - (IN) ECMP DLB members. 11526 * Returns: 11527 * BCM_E_XXX 11528 */ 11529 STATIC int 11530 _bcm_xgs3_ecmp_group_add(int unit, uint32 flags, uint32 ecmp_flags, 11531 int ecmp_count, int max_paths, int *ecmp_group, 11532 int *group_index, int primary_count, 11533 SHR_BITDCL *dlb_member_bitmap) 11534 { 11535 _bcm_l3_tbl_op_t data; /* Operation data. */ 11536 _bcm_l3_ecmp_group_info_t ecmp_info; 11537 _bcm_l3_ecmp_group_buffer_t ecmp_buffer; 11538 int *dlb_ecmp_group = NULL; 11539 int rv = BCM_E_NONE; 11540 #ifdef BCM_TRX_SUPPORT 11541 uint32 ing_config_2; 11542 uint8 ecmp_hash_16bits; 11543 #endif 11544 11545 #ifdef BCM_TOMAHAWK_SUPPORT 11546 int old_grp_tbl_idx_max = 0; 11547 int old_grp_tbl_idx_min = 0; 11548 _bcm_l3_tbl_t *grp_tbl_ptr = NULL; 11549 int old_ecmp_tbl_idx_max = 0; 11550 int old_ecmp_tbl_idx_min = 0; 11551 _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL; 11552 #endif /* BCM_TOMAHAWK_SUPPORT */ 11553 11554 /* Make sure ecmp group write call is defined for the device. */ 11555 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, ecmp_grp_add)) { 11556 return (BCM_E_UNAVAIL); 11557 } 11558 11559 /* 11560 * Next hop indexes must be sorted in the group 11561 * in order to produce identical hash every time. 11562 */ 11563 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) || 11564 !((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) || 11565 #if defined(BCM_TRIDENT3_SUPPORT) 11566 SOC_IS_TRIDENT3X(unit) || 11567 #endif 11568 SOC_IS_TOMAHAWKX(unit)) && 11569 ((ecmp_flags & BCM_L3_ECMP_PATH_NO_SORTING) || 11570 (SOC_IS_TOMAHAWK3(unit) && (ecmp_flags & BCM_L3_ECMP_WEIGHTED)) 11571 ))) { 11572 11573 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 11574 if (soc_feature(unit, soc_feature_dgm) && 11575 (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) { 11576 11577 /* first sort primary, then sort alternate if exist. 11578 * assume primary and alternate can be seperated via primary_count. 11579 */ 11580 _shr_sort(ecmp_group, primary_count, sizeof(int), _bcm_xgs3_cmp_int); 11581 if (ecmp_count - primary_count) { 11582 _shr_sort(&ecmp_group[primary_count], ecmp_count - primary_count, 11583 sizeof(int), _bcm_xgs3_cmp_int); 11584 } 11585 } else 11586 #endif 11587 { 11588 _shr_sort(ecmp_group, ecmp_count, sizeof(int), _bcm_xgs3_cmp_int); 11589 } 11590 } 11591 11592 /* Initialization */ 11593 sal_memset(&ecmp_info, 0, sizeof(ecmp_info)); 11594 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 11595 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 11596 data.oper_flags = flags; 11597 11598 #if defined(BCM_TOMAHAWK3_SUPPORT) 11599 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 11600 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11601 ecmp_mode_hierarchical)) { 11602 if (ecmp_flags & BCM_L3_ECMP_OVERLAY) { 11603 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 11604 } 11605 } 11606 #endif 11607 11608 ecmp_info.alternate_cnt = 0; 11609 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 11610 if (soc_feature(unit, soc_feature_dgm) && 11611 (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) { 11612 ecmp_info.alternate_cnt = ecmp_count - primary_count; 11613 } 11614 #endif 11615 11616 #ifdef BCM_TRX_SUPPORT 11617 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 11618 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 11619 /* Limit Max_paths */ 11620 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 11621 11622 #ifdef BCM_TOMAHAWK_SUPPORT 11623 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 11624 !(ecmp_flags & BCM_L3_ECMP_RH_OPT)) { 11625 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11626 ecmp_mode_hierarchical)) { 11627 #ifdef BCM_TOMAHAWK3_SUPPORT 11628 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 11629 (ecmp_flags & BCM_L3_ECMP_OVERLAY)) { 11630 11631 /* Overlay ECMP member count must be a power of 2 */ 11632 if ((ecmp_count & (ecmp_count - 1)) != 0) { 11633 return (BCM_E_PARAM); 11634 } 11635 } else if (soc_feature(unit, soc_feature_l3_ecmp_weighted) && 11636 (ecmp_flags & BCM_L3_ECMP_WEIGHTED)) { 11637 if (max_paths > 11638 BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS) { 11639 max_paths = 11640 BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS; 11641 } 11642 } else 11643 #endif 11644 if (max_paths > 128) { 11645 max_paths = 128; 11646 } 11647 } 11648 11649 if (soc_feature(unit, soc_feature_fast_ecmp)) { 11650 if (max_paths > 128) { 11651 max_paths = 128; 11652 } 11653 } 11654 11655 if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11656 ecmp_mode_single) { 11657 #ifdef BCM_TOMAHAWK3_SUPPORT 11658 if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) { 11659 if (ecmp_flags & BCM_L3_ECMP_WEIGHTED) { 11660 if (max_paths > 11661 BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS) { 11662 max_paths = 11663 BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS; 11664 } 11665 } else { 11666 if (max_paths > 11667 BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS) { 11668 max_paths = 11669 BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS; 11670 } 11671 } 11672 } else 11673 #endif 11674 if (max_paths > 1024) { 11675 max_paths = 1024; 11676 } 11677 } 11678 } 11679 #endif /* BCM_TOMAHAWK_SUPPORT */ 11680 11681 if (SOC_IS_TRIDENT(unit)){ 11682 SOC_IF_ERROR_RETURN 11683 (READ_ING_CONFIG_2r(unit, &ing_config_2)); 11684 ecmp_hash_16bits = 11685 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 11686 ECMP_HASH_16BITSf); 11687 if ((!ecmp_hash_16bits) && (max_paths > 256)) { 11688 max_paths = 256; 11689 } 11690 } 11691 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11692 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11693 } else if (SOC_IS_TRIDENT(unit)) { 11694 if (max_paths > 256) { 11695 max_paths = 256; 11696 } 11697 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11698 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11699 } else if (SOC_IS_SCORPION(unit)) { 11700 if (max_paths > 256) { 11701 max_paths = 256; 11702 } 11703 data.width = max_paths; 11704 data.oper_flags |= _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 11705 } else if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 11706 SOC_IS_SABER2(unit) || SOC_IS_GREYHOUND2(unit)) { 11707 if (max_paths > 64) { 11708 max_paths = 64; 11709 } 11710 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11711 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11712 } else if (SOC_IS_MONTEREY(unit)) { 11713 if (max_paths > 256) { 11714 max_paths = 256; 11715 } 11716 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11717 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11718 } else if SOC_IS_KATANAX(unit) { 11719 if (max_paths > 1024) { 11720 max_paths = 1024; 11721 } 11722 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11723 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11724 } else { 11725 if (max_paths > 32) { 11726 max_paths = 32; 11727 } 11728 data.width = max_paths; 11729 if (SOC_IS_TRIUMPH2(unit) || 11730 SOC_IS_APOLLO(unit) || 11731 SOC_IS_VALKYRIE2(unit) || 11732 SOC_IS_KATANAX(unit)) { 11733 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11734 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11735 } 11736 11737 } 11738 ecmp_info.max_paths = max_paths; 11739 } else { 11740 return (BCM_E_PARAM); 11741 } 11742 } else 11743 #endif /* BCM_TRX_SUPPORT */ 11744 { 11745 data.width = _BCM_SINGLE_WIDE; 11746 ecmp_info.max_paths = _BCM_SINGLE_WIDE; 11747 } 11748 ecmp_info.ecmp_flags = ecmp_flags; 11749 data.info = &ecmp_info; 11750 if (flags & _BCM_L3_SHR_WITH_ID) { 11751 data.entry_index = *group_index; 11752 } 11753 ecmp_buffer.group_buffer = ecmp_group; 11754 11755 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 11756 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized) && 11757 dlb_member_bitmap) { 11758 int i =0, j = 0, offset = 0; 11759 11760 if (soc_feature(unit, soc_feature_dgm) && 11761 (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) { 11762 if (0 == primary_count) { 11763 offset = ecmp_info.max_paths/2; 11764 } 11765 } 11766 11767 /* Allocate ecmp dlb group buffer. */ 11768 BCM_IF_ERROR_RETURN( 11769 _bcm_xgs3_l3_ecmp_group_alloc(unit, &dlb_ecmp_group)); 11770 11771 for (i = 0; i < ecmp_count; i++) { 11772 if (SHR_BITGET(dlb_member_bitmap, i + offset)) { 11773 dlb_ecmp_group[j++] = ecmp_group[i]; 11774 } 11775 } 11776 11777 ecmp_buffer.dlb_group_buffer = dlb_ecmp_group; 11778 } else 11779 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 11780 { 11781 ecmp_buffer.dlb_group_buffer = NULL; 11782 } 11783 11784 data.entry_buffer = (void *)&ecmp_buffer; 11785 11786 data.hash_func = _bcm_xgs3_ecmp_grp_hash_calc; 11787 data.cmp_func = _bcm_xgs3_ecmp_grp_cmp; 11788 data.add_func = BCM_XGS3_L3_HWCALL(unit, ecmp_grp_add); 11789 #ifdef BCM_TOMAHAWK_SUPPORT 11790 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 11791 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11792 ecmp_mode_hierarchical)) { 11793 grp_tbl_ptr = data.tbl_ptr; 11794 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 11795 old_grp_tbl_idx_max = grp_tbl_ptr->idx_max; 11796 old_grp_tbl_idx_min = grp_tbl_ptr->idx_min; 11797 old_ecmp_tbl_idx_max = ecmp_tbl_ptr->idx_max; 11798 old_ecmp_tbl_idx_min = ecmp_tbl_ptr->idx_min; 11799 if (ecmp_flags & BCM_L3_ECMP_OVERLAY) { 11800 /* 11801 * For ECMP group at Level 1, ecmp group can only be added 11802 * in first half of ECMP table 11803 */ 11804 if (!soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) { 11805 grp_tbl_ptr->idx_max = grp_tbl_ptr->idx_max/2; 11806 } 11807 ecmp_tbl_ptr->idx_max = ecmp_tbl_ptr->idx_max/2; 11808 } else if (ecmp_flags & BCM_L3_ECMP_UNDERLAY) { 11809 /* 11810 * For ECMP group at Level 2, ecmp group can only be added 11811 * in second half of ECMP table 11812 */ 11813 grp_tbl_ptr->idx_min = (grp_tbl_ptr->idx_max/2) + 1; 11814 ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1; 11815 } 11816 } 11817 #ifdef BCM_TOMAHAWK3_SUPPORT 11818 /* If DLB group setup min and max so that the grp is allocated from 11819 the DLB range. Otherwise make sure the group allocated doesnt 11820 fall in the DLB range. */ 11821 if ((soc_feature(unit, soc_feature_th3_style_dlb) && 11822 !(ecmp_flags & BCM_L3_ECMP_OVERLAY))) { 11823 grp_tbl_ptr = data.tbl_ptr; 11824 old_grp_tbl_idx_max = grp_tbl_ptr->idx_max; 11825 old_grp_tbl_idx_min = grp_tbl_ptr->idx_min; 11826 if (!dlb_ecmp_group) { 11827 grp_tbl_ptr->idx_max = BCM_TH3_L3_ECMP_DLB_START(unit) - 1; 11828 } else { 11829 grp_tbl_ptr->idx_min = BCM_TH3_L3_ECMP_DLB_START(unit) + 11830 (soc_property_get(unit, 11831 spn_DLB_FLOW_MONITOR_EN, 0) ? 11832 ((BCM_XGS3_L3_MAX_ECMP_MODE(unit)) ? 11833 1 : 2) : 0); 11834 } 11835 } 11836 #endif 11837 #endif /* BCM_TOMAHAWK_SUPPORT */ 11838 11839 /* Add ecmp group. */ 11840 rv = _bcm_xgs3_tbl_add(unit, &data); 11841 #ifdef BCM_TOMAHAWK_SUPPORT 11842 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 11843 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11844 ecmp_mode_hierarchical)) { 11845 grp_tbl_ptr->idx_max = old_grp_tbl_idx_max; 11846 grp_tbl_ptr->idx_min = old_grp_tbl_idx_min; 11847 ecmp_tbl_ptr->idx_max = old_ecmp_tbl_idx_max; 11848 ecmp_tbl_ptr->idx_min = old_ecmp_tbl_idx_min; 11849 } 11850 #ifdef BCM_TOMAHAWK3_SUPPORT 11851 else if (soc_feature(unit, soc_feature_th3_style_dlb)) { 11852 grp_tbl_ptr->idx_max = old_grp_tbl_idx_max; 11853 grp_tbl_ptr->idx_min = old_grp_tbl_idx_min; 11854 } 11855 #endif 11856 #endif /* BCM_TOMAHAWK_SUPPORT */ 11857 if (BCM_FAILURE(rv)) { 11858 if (dlb_ecmp_group) { 11859 sal_free(dlb_ecmp_group); 11860 } 11861 return rv; 11862 } 11863 11864 *group_index = data.entry_index; 11865 /* Indicate that at least one ecmp path is present. */ 11866 if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) { 11867 BCM_XGS3_L3_ECMP_IN_USE(unit) = 1; 11868 } 11869 11870 /* If ID and UPDATE flag is set, then the entry is already present 11871 * in the hardware, so no need to increment 11872 */ 11873 11874 if (!((flags & _BCM_L3_SHR_UPDATE) && 11875 (flags & _BCM_L3_SHR_WITH_ID))) { 11876 BCM_XGS3_L3_ECMP_GRP_CNT(unit)++; 11877 } 11878 11879 if (ecmp_flags & BCM_L3_ECMP_PATH_NO_SORTING) { 11880 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index, 11881 BCM_L3_ECMP_PATH_NO_SORTING); 11882 } else { 11883 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index, 11884 BCM_L3_ECMP_PATH_NO_SORTING); 11885 } 11886 if (ecmp_flags & BCM_L3_ECMP_OVERLAY) { 11887 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index, 11888 BCM_L3_ECMP_OVERLAY); 11889 } else { 11890 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index, 11891 BCM_L3_ECMP_OVERLAY); 11892 } 11893 if (ecmp_flags & BCM_L3_ECMP_UNDERLAY) { 11894 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index, 11895 BCM_L3_ECMP_UNDERLAY); 11896 } else { 11897 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index, 11898 BCM_L3_ECMP_UNDERLAY); 11899 } 11900 11901 if (SOC_IS_TOMAHAWK3(unit)) { 11902 if (ecmp_flags & BCM_L3_ECMP_WEIGHTED) { 11903 BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index, 11904 BCM_L3_ECMP_WEIGHTED); 11905 } else { 11906 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index, 11907 BCM_L3_ECMP_WEIGHTED); 11908 } 11909 } 11910 if (dlb_ecmp_group) { 11911 sal_free(dlb_ecmp_group); 11912 } 11913 11914 return (BCM_E_NONE); 11915 } 11916 11917 /* 11918 * Function: 11919 * _bcm_xgs3_ecmp_group_enlarge 11920 * Purpose: 11921 * Recalculate max paths of ecmp group. 11922 * Parameters: 11923 * unit - (IN)SOC unit number. 11924 * ecmp_flags - (IN)BCM_L3_ECMP_OVERLAY,etc. 11925 * max_paths - (IN/OUT)ecmp group max group size. 11926 * width - (OUT)Number of entries required for one record. 11927 * value - (OUT)max paths parameter. 11928 * Returns: 11929 * BCM_E_XXX 11930 */ 11931 #if defined(BCM_TRX_SUPPORT) 11932 STATIC int 11933 _bcm_xgs3_ecmp_max_grp_size_calc(int unit, uint32 ecmp_flags, 11934 int *max_paths, int *width, int *value) 11935 { 11936 #ifdef BCM_TRX_SUPPORT 11937 uint32 ing_config_2; 11938 uint8 ecmp_hash_16bits; 11939 11940 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 11941 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 11942 /* Limit Max_paths */ 11943 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 11944 #ifdef BCM_TOMAHAWK_SUPPORT 11945 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 11946 !(ecmp_flags & BCM_L3_ECMP_RH_OPT)) { 11947 #ifdef BCM_TOMAHAWK3_SUPPORT 11948 if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) { 11949 if (*max_paths > 4096) { 11950 *max_paths = 4096; 11951 } 11952 } else 11953 #endif 11954 { 11955 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11956 ecmp_mode_hierarchical)) { 11957 if (*max_paths > 128) { 11958 *max_paths = 128; 11959 } 11960 } 11961 11962 if (soc_feature(unit, soc_feature_fast_ecmp)) { 11963 if (*max_paths > 128) { 11964 *max_paths = 128; 11965 } 11966 } 11967 11968 if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 11969 ecmp_mode_single) { 11970 if (*max_paths > 1024) { 11971 *max_paths = 1024; 11972 } 11973 } 11974 } 11975 } 11976 #endif /* BCM_TOMAHAWK_SUPPORT */ 11977 11978 if (SOC_IS_TRIDENT(unit)){ 11979 SOC_IF_ERROR_RETURN 11980 (READ_ING_CONFIG_2r(unit, &ing_config_2)); 11981 ecmp_hash_16bits = 11982 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 11983 ECMP_HASH_16BITSf); 11984 if ((!ecmp_hash_16bits) && (*max_paths > 256)) { 11985 *max_paths = 256; 11986 } 11987 } 11988 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11989 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11990 } else if (SOC_IS_TRIDENT(unit)) { 11991 if (*max_paths > 256) { 11992 *max_paths = 256; 11993 } 11994 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 11995 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 11996 } else if (SOC_IS_SCORPION(unit)) { 11997 if (*max_paths > 256) { 11998 *max_paths = 256; 11999 } 12000 *width = *max_paths; 12001 } else if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 12002 SOC_IS_SABER2(unit) || SOC_IS_GREYHOUND2(unit)) { 12003 if (*max_paths > 64) { 12004 *max_paths = 64; 12005 } 12006 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 12007 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 12008 } else if (SOC_IS_MONTEREY(unit)) { 12009 if (*max_paths > 256) { 12010 *max_paths = 256; 12011 } 12012 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 12013 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 12014 } else if (SOC_IS_KATANAX(unit)) { 12015 if (*max_paths > 1024) { 12016 *max_paths = 1024; 12017 } 12018 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 12019 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 12020 } else { 12021 if (*max_paths > 32) { 12022 *max_paths = 32; 12023 } 12024 *width = *max_paths; 12025 if (SOC_IS_TRIUMPH2(unit) || 12026 SOC_IS_APOLLO(unit) || 12027 SOC_IS_VALKYRIE2(unit) || 12028 SOC_IS_KATANAX(unit)) { 12029 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 12030 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 12031 } 12032 12033 } 12034 *value = *max_paths; 12035 } else { 12036 return (BCM_E_PARAM); 12037 } 12038 } else 12039 #endif /* BCM_TRX_SUPPORT */ 12040 { 12041 COMPILER_REFERENCE(max_paths); 12042 *width = _BCM_SINGLE_WIDE; 12043 *value = _BCM_SINGLE_WIDE; 12044 } 12045 return BCM_E_NONE; 12046 } 12047 #endif /* BCM_TRX_SUPPORT */ 12048 12049 /* 12050 * Function: 12051 * _bcm_xgs3_ecmp_group_enlarge 12052 * Purpose: 12053 * Enlarge the max group size of ecmp group. 12054 * Parameters: 12055 * unit - (IN)SOC unit number. 12056 * ecmp_group_id - (IN)Ecmp group index. 12057 * old_ecmp_base_idx - (IN) Old base index of L3_ECMP 12058 * old_max_paths - (IN)Old max group size. 12059 * new_max_paths - (IN)New max group size. 12060 * ecmp_flags - (IN)Ecmp flags 12061 * Returns: 12062 * BCM_E_XXX 12063 */ 12064 #ifdef BCM_TRIUMPH2_SUPPORT 12065 STATIC int 12066 _bcm_xgs3_ecmp_group_enlarge(int unit, 12067 int ecmp_group_id, int old_ecmp_base_idx, int old_max_paths, 12068 int new_max_paths, uint32 ecmp_flags) 12069 { 12070 #ifdef BCM_TRIUMPH2_SUPPORT 12071 int idx = 0, idx_min = 0, idx_max = 0, *maxused_idx; 12072 int rv = BCM_E_NONE; 12073 soc_defragment_member_op_t member_op; 12074 soc_defragment_group_op_t group_op; 12075 int new_ecmp_base_idx = 0; 12076 _bcm_l3_tbl_op_t data; 12077 int old_base_after_defrag = 0; 12078 12079 if (old_max_paths > new_max_paths) { 12080 return BCM_E_PARAM; 12081 } 12082 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 12083 if (SOC_IS_ENDURO(unit)) { 12084 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 12085 } else { 12086 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 12087 } 12088 data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 12089 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 12090 /* 12091 * we can look into the ecmp_grp index to know if this 12092 * is overlay entry or underlay entry. 12093 */ 12094 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 12095 if (ecmp_group_id < BCMI_L3_ECMP_OVERLAY_ENTRIES(unit)) { 12096 12097 data.oper_flags |= _BCM_L3_SHR_OVERLAY_OBJECT; 12098 } 12099 } 12100 #endif 12101 12102 bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, &data); 12103 /* Check if it is possible to increase max grp size in-place. */ 12104 for (idx = old_ecmp_base_idx + old_max_paths; 12105 (idx < (old_ecmp_base_idx + new_max_paths)) && (idx <= idx_max); 12106 idx++) { 12107 12108 if(BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, idx)) { 12109 break; 12110 } 12111 } 12112 12113 if (SOC_IS_ENDURO(unit)) { 12114 if (idx == old_ecmp_base_idx + new_max_paths) { 12115 BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit, 12116 ecmp_group_id, new_max_paths, ecmp_flags)); 12117 return BCM_E_NONE; 12118 } else { 12119 /* cannot enlarge group for enduro now */ 12120 return BCM_E_PARAM; 12121 } 12122 } else { 12123 if (idx == old_ecmp_base_idx + new_max_paths) { 12124 BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit, 12125 ecmp_group_id, new_max_paths, ecmp_flags)); 12126 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12127 old_ecmp_base_idx, old_max_paths); 12128 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12129 old_ecmp_base_idx, new_max_paths); 12130 return BCM_E_NONE; 12131 } 12132 } 12133 12134 data.width = new_max_paths; 12135 data.entry_index = -1; 12136 rv = _bcm_xgs3_tbl_free_idx_get(unit, &data); 12137 if (rv == BCM_E_FULL) { 12138 /* Defragment ECMP table */ 12139 #ifdef BCM_TOMAHAWK_SUPPORT 12140 /* Pass ECMP level so the defragmentation can happen in the 12141 right part of the ECMP table */ 12142 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 12143 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 12144 ecmp_mode_hierarchical)) { 12145 if (data.tbl_ptr->idx_min > 0) { 12146 /* De-fragment Level 2 or Underlay ECMP table 12147 * ecmp_flags & BCM_L3_ECMP_UNDERLAY */ 12148 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2)); 12149 } else if ((data.tbl_ptr->idx_min == 0) && 12150 (data.tbl_ptr->idx_max < soc_mem_index_max(unit, L3_ECMPm))) { 12151 /* De-fragment Level 1 or Overlay ECMP table 12152 * ecmp_flags & BCM_L3_ECMP_OVERLAY */ 12153 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1)); 12154 } else { 12155 /* 12156 * The current entry can go in anywhere in the ECMP table. 12157 * Means ecmp_group was created with flags 0, 12158 * De-fragment the entire ECMP table 12159 */ 12160 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2)); 12161 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1)); 12162 } 12163 } else 12164 #elif defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 12165 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 12166 if (data.oper_flags & _BCM_L3_SHR_OVERLAY_OBJECT) { 12167 BCM_IF_ERROR_RETURN( 12168 bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2)); 12169 } else { 12170 BCM_IF_ERROR_RETURN( 12171 bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1)); 12172 } 12173 } else 12174 #endif 12175 { 12176 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0)); 12177 } 12178 12179 BCM_IF_ERROR_RETURN( 12180 _bcm_xgs3_l3_ecmp_grp_info_get(unit, ecmp_group_id, 12181 NULL, &old_base_after_defrag)); 12182 12183 if (old_base_after_defrag != old_ecmp_base_idx) { 12184 old_ecmp_base_idx = old_base_after_defrag; 12185 } 12186 12187 /* Check if it is possible to increase max grp size in-place. */ 12188 for (idx = old_ecmp_base_idx + old_max_paths; 12189 (idx < (old_ecmp_base_idx + new_max_paths)) && (idx <= idx_max); 12190 idx++) { 12191 12192 if(BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp), idx)) { 12193 break; 12194 } 12195 } 12196 if (idx == old_ecmp_base_idx + new_max_paths) { 12197 BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit, 12198 ecmp_group_id, new_max_paths, ecmp_flags)); 12199 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12200 old_ecmp_base_idx, old_max_paths); 12201 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12202 old_ecmp_base_idx, new_max_paths); 12203 return BCM_E_NONE; 12204 } 12205 /* Attempt to get free index again */ 12206 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_free_idx_get(unit, &data)); 12207 12208 } 12209 12210 new_ecmp_base_idx = data.entry_index; 12211 member_op.member_copy = _bcm_tr2_l3_ecmp_member_copy; 12212 member_op.member_clear = _bcm_tr2_l3_ecmp_member_clear; 12213 group_op.group_base_ptr_update = _bcm_tr2_l3_ecmp_group_base_ptr_update; 12214 BCM_IF_ERROR_RETURN(soc_defragment_block_move(unit, old_ecmp_base_idx, 12215 new_ecmp_base_idx, old_max_paths, &member_op, 12216 ecmp_group_id, &group_op)); 12217 BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit, 12218 ecmp_group_id, new_max_paths, ecmp_flags)); 12219 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12220 (new_ecmp_base_idx + old_max_paths), 12221 (new_max_paths - old_max_paths)); 12222 return BCM_E_NONE; 12223 #endif/* BCM_TRIUMPH2_SUPPORT */ 12224 return BCM_E_PARAM; 12225 } 12226 #endif/* BCM_TRIUMPH2_SUPPORT */ 12227 12228 /* 12229 * Function: 12230 * _bcm_xgs3_ecmp_group_max_size_update 12231 * Purpose: 12232 * Update the max group size of ecmp group. 12233 * Just used by chips which support BCM_TRIUMPH2_SUPPORT. 12234 * Parameters: 12235 * unit - (IN)SOC unit number. 12236 * ecmp_flags - (IN)BCM_L3_ECMP_OVERLAY,etc. 12237 * ecmp_group_id - (IN)Ecmp group index. 12238 * new_max_paths - (IN)New max group size. 12239 * Returns: 12240 * BCM_E_XXX 12241 */ 12242 STATIC int 12243 _bcm_xgs3_ecmp_group_max_size_update(int unit, 12244 uint32 ecmp_flags, int ecmp_group_id, 12245 int old_max_paths, int new_max_paths) 12246 { 12247 #ifdef BCM_TRIUMPH2_SUPPORT 12248 int old_ecmp_base_idx = 0; 12249 int rv = BCM_E_NONE; 12250 int width, value; 12251 #ifdef BCM_TOMAHAWK_SUPPORT 12252 int old_grp_tbl_idx_max = 0; 12253 int old_grp_tbl_idx_min = 0; 12254 _bcm_l3_tbl_t *grp_tbl_ptr = NULL; 12255 int old_ecmp_tbl_idx_max = 0; 12256 int old_ecmp_tbl_idx_min = 0; 12257 _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL; 12258 #endif /* BCM_TOMAHAWK_SUPPORT */ 12259 12260 if (ecmp_group_id < 0 || 12261 ecmp_group_id > soc_mem_index_max(unit, L3_ECMP_COUNTm)) { 12262 return BCM_E_PARAM; 12263 } 12264 12265 if (new_max_paths == old_max_paths) { 12266 return BCM_E_NONE; 12267 } 12268 12269 if (!soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 12270 return BCM_E_PARAM; 12271 } 12272 12273 BCM_IF_ERROR_RETURN( 12274 _bcm_xgs3_l3_ecmp_grp_info_get(unit, ecmp_group_id, 12275 NULL, &old_ecmp_base_idx)); 12276 12277 if (new_max_paths < old_max_paths) { 12278 if (!SOC_IS_ENDURO(unit)) { 12279 /* setup new max_path */ 12280 BCM_IF_ERROR_RETURN( 12281 _bcm_xgs3_ecmp_max_grp_size_set(unit, ecmp_group_id, 12282 new_max_paths, ecmp_flags)); 12283 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12284 old_ecmp_base_idx, old_max_paths); 12285 } else { 12286 /* clean old ecmp member */ 12287 BCM_IF_ERROR_RETURN( 12288 bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, _BCM_L3_SHR_CLEAN)); 12289 } 12290 #ifdef BCM_TOMAHAWK3_SUPPORT 12291 /* For replace case, set the old_ecmp_base_idx in the entry */ 12292 if ((soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) && 12293 (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 12294 uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry. */ 12295 soc_mem_t mem = L3_ECMP_COUNTm; 12296 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 12297 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 12298 ecmp_mode_hierarchical) && (ecmp_group_id < 12299 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 12300 mem = ECMP_GROUP_HIERARCHICALm; 12301 } 12302 sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 12303 soc_mem_field32_set(unit, mem, 12304 hw_buf, BASE_PTRf, old_ecmp_base_idx); 12305 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, 12306 (ecmp_group_id), hw_buf); 12307 if (BCM_FAILURE(rv)) { 12308 return rv; 12309 } 12310 } 12311 #endif 12312 12313 /* setup new max_path */ 12314 BCM_IF_ERROR_RETURN( 12315 _bcm_xgs3_ecmp_max_grp_size_set(unit, ecmp_group_id, 12316 new_max_paths, ecmp_flags)); 12317 /* update ref_cnt of ecmp member in the group 12318 * For enduro: 12319 * it use ecmp_grp (not ecmp) to record ecmp members, 12320 * so update ref_cnt here. 12321 * bcm_xgs3_ecmp_group_del(_BCM_L3_SHR_CLEAN) 12322 * would not change the ref_cnt of ecmp_grp 12323 * For the others: 12324 * it use ecmp_grp to record ecmp group information (ex. base_ptr) 12325 * ecmp to record ecmp members 12326 * bcm_xgs3_ecmp_group_del(_BCM_L3_SHR_CLEAN) clean the ecmp members 12327 * and decrese the ref_cnt, so only need to increase ref_cnt here 12328 */ 12329 if (SOC_IS_ENDURO(unit)) { 12330 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), 12331 ecmp_group_id, old_max_paths); 12332 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), 12333 ecmp_group_id, new_max_paths); 12334 } else { 12335 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 12336 old_ecmp_base_idx, new_max_paths); 12337 } 12338 return BCM_E_NONE; 12339 } 12340 12341 12342 if (new_max_paths > old_max_paths) { 12343 BCM_IF_ERROR_RETURN( 12344 _bcm_xgs3_ecmp_max_grp_size_calc(unit, ecmp_flags, 12345 &new_max_paths, &width, &value)); 12346 12347 #ifdef BCM_TOMAHAWK_SUPPORT 12348 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 12349 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 12350 ecmp_mode_hierarchical)) { 12351 grp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 12352 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 12353 old_grp_tbl_idx_max = grp_tbl_ptr->idx_max; 12354 old_grp_tbl_idx_min = grp_tbl_ptr->idx_min; 12355 old_ecmp_tbl_idx_max = ecmp_tbl_ptr->idx_max; 12356 old_ecmp_tbl_idx_min = ecmp_tbl_ptr->idx_min; 12357 if (ecmp_flags & BCM_L3_ECMP_OVERLAY) { 12358 /* 12359 * For ECMP group at Level 1, ecmp group can only be added 12360 * in first half of ECMP table 12361 */ 12362 grp_tbl_ptr->idx_max = grp_tbl_ptr->idx_max/2; 12363 ecmp_tbl_ptr->idx_max = ecmp_tbl_ptr->idx_max/2; 12364 } else if (ecmp_flags & BCM_L3_ECMP_UNDERLAY) { 12365 /* 12366 * For ECMP group at Level 2, ecmp group can only be added 12367 * in second half of ECMP table 12368 */ 12369 grp_tbl_ptr->idx_min = (grp_tbl_ptr->idx_max/2) + 1; 12370 ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1; 12371 } 12372 #ifdef BCM_TOMAHAWK3_SUPPORT 12373 else { 12374 /* 12375 * For ECMP group at Level 2, ecmp group can only be added 12376 * in second half of ECMP table 12377 */ 12378 grp_tbl_ptr->idx_min = (grp_tbl_ptr->idx_max/2) + 1; 12379 ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1; 12380 } 12381 #endif 12382 } 12383 #endif /* BCM_TOMAHAWK_SUPPORT */ 12384 12385 rv = _bcm_xgs3_ecmp_group_enlarge(unit, ecmp_group_id, 12386 old_ecmp_base_idx, old_max_paths, new_max_paths, ecmp_flags); 12387 12388 #ifdef BCM_TOMAHAWK_SUPPORT 12389 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 12390 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 12391 ecmp_mode_hierarchical)) { 12392 grp_tbl_ptr->idx_max = old_grp_tbl_idx_max; 12393 grp_tbl_ptr->idx_min = old_grp_tbl_idx_min; 12394 ecmp_tbl_ptr->idx_max = old_ecmp_tbl_idx_max; 12395 ecmp_tbl_ptr->idx_min = old_ecmp_tbl_idx_min; 12396 } 12397 #endif /* BCM_TOMAHAWK_SUPPORT */ 12398 if (BCM_FAILURE(rv)) { 12399 return rv; 12400 } 12401 return BCM_E_NONE; 12402 } 12403 #endif/* BCM_TRIUMPH2_SUPPORT */ 12404 return BCM_E_PARAM; 12405 } 12406 12407 12408 /* 12409 * Functions: 12410 * _bcm_xgs3_l3_multipathCountUpdate 12411 * Description: 12412 * Helper function to update L3-DEFIP.ECMP_Count via DMA 12413 * Parameters: 12414 * unit device number 12415 * Return: 12416 * BCM_E_XXX 12417 */ 12418 12419 int 12420 _bcm_xgs3_l3_multipathCountUpdate (int unit, int set) 12421 { 12422 int idx; /* Iteration index. */ 12423 char *lpm_tbl_ptr; /* Dma table pointer.*/ 12424 uint32 *lpm_entry; /* Hw entry buffer. */ 12425 int defip_table_size; /* Defip table size. */ 12426 int ecmp_count=0; /* Next hop count in the group. */ 12427 int *ecmp_grp; /* Ecmp group from hw. */ 12428 int ecmp_group_idx; 12429 int rv=BCM_E_NONE, update_flag=0; 12430 soc_mem_t mem; /* IPv4 in IPv6 table memory. */ 12431 12432 mem = BCM_XGS3_L3_MEM(unit, defip); 12433 12434 if (!set) { 12435 return BCM_E_NONE; 12436 } 12437 12438 /* Allocate ecmp group buffer. */ 12439 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 12440 12441 /* Table DMA the LPM table to software copy */ 12442 rv = bcm_xgs3_l3_tbl_dma(unit, mem, 12443 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 12444 &lpm_tbl_ptr, &defip_table_size); 12445 if (BCM_FAILURE(rv)) { 12446 sal_free(ecmp_grp); 12447 return (rv); 12448 } 12449 12450 L3_LOCK(unit); 12451 12452 for (idx = 0; idx < defip_table_size; idx++) { 12453 /* Calculate entry ofset. */ 12454 if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 12455 lpm_entry = 12456 (uint32 *)soc_mem_table_idx_to_pointer(unit, mem, 12457 defip_entry_t *, lpm_tbl_ptr, idx); 12458 } else { 12459 lpm_entry = 12460 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 12461 defip_level1_entry_t *, lpm_tbl_ptr, idx); 12462 } 12463 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) { 12464 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f)) { 12465 ecmp_group_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f); 12466 rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_idx, ecmp_grp, &ecmp_count); 12467 if (rv != BCM_E_NOT_FOUND) { 12468 if (BCM_FAILURE(rv)) { 12469 sal_free(ecmp_grp); 12470 L3_UNLOCK(unit); 12471 return (rv); 12472 } 12473 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP_COUNT0f, ecmp_count); 12474 update_flag = 1; 12475 } 12476 } 12477 } 12478 12479 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID1f)) { 12480 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP1f)) { 12481 ecmp_group_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR1f); 12482 rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_idx, ecmp_grp, &ecmp_count); 12483 if (rv != BCM_E_NOT_FOUND) { 12484 if (BCM_FAILURE(rv)) { 12485 sal_free(ecmp_grp); 12486 L3_UNLOCK(unit); 12487 return (rv); 12488 } 12489 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP_COUNT1f, ecmp_count); 12490 update_flag = 1; 12491 } 12492 } 12493 } 12494 #ifdef BCM_TRIDENT_SUPPORT 12495 if ((SOC_IS_TD_TT(unit) || SOC_IS_TD2_TT2(unit)) && 12496 update_flag) { 12497 uint32 i, hit; 12498 defip_hit_only_entry_t hit_entry[2]; 12499 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym}; 12500 int hit_mem_cnt = 2; 12501 12502 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit)) { 12503 hit_mem[0] = L3_DEFIP_HIT_ONLYm; 12504 hit_mem_cnt = 1; 12505 } 12506 12507 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 12508 BCM_IF_ERROR_RETURN 12509 (BCM_XGS3_MEM_READ(unit, hit_mem[i], 12510 idx, &hit_entry[i])); 12511 hit |= soc_mem_field32_get(unit, hit_mem[i], 12512 &hit_entry[i], HIT0f); 12513 } 12514 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, HIT0f, hit); 12515 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 12516 hit |= soc_mem_field32_get(unit, hit_mem[i], 12517 &hit_entry[i], HIT1f); 12518 } 12519 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, HIT1f, hit); 12520 } 12521 #endif /* BCM_TRIDENT_SUPPORT */ 12522 } 12523 /* Write the modified buffer back. */ 12524 if (update_flag) { 12525 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 12526 soc_mem_index_min(unit, mem), 12527 soc_mem_index_max(unit, mem), lpm_tbl_ptr); 12528 } 12529 sal_free(ecmp_grp); 12530 soc_cm_sfree(unit, lpm_tbl_ptr); 12531 L3_UNLOCK(unit); 12532 return (rv); 12533 } 12534 12535 12536 12537 /* 12538 * Function: 12539 * bcm_xgs3_proxy_nh_add 12540 * Purpose: 12541 * Allocate NextHop table index & Write NextHop entry. 12542 * Routine trying to match new entry to an existing one, 12543 * if match found reference cound is incremented, otherwise 12544 * new index allocated & entry added to hw. 12545 * Parameters: 12546 * unit - (IN)SOC unit number. 12547 * flags - (IN)Egress object flags. 12548 * nh_info - (IN)Next hop entry info. 12549 * index - (OUT)Next hop index. 12550 * Returns: 12551 * BCM_E_XXX 12552 */ 12553 12554 int 12555 bcm_xgs3_proxy_nh_add(int unit, uint32 flags, bcm_proxy_egress_t *proxy_nh_info, int *index) 12556 { 12557 int rv = BCM_E_UNAVAIL; 12558 _bcm_l3_tbl_op_t data; /* Operation data. */ 12559 bcm_port_t port, port_out; 12560 bcm_module_t modid, modid_out; 12561 bcm_trunk_t trunk; 12562 int id; 12563 12564 /* Make sure module was initialized. */ 12565 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 12566 return (BCM_E_INIT); 12567 } 12568 12569 /* Input parameters check. */ 12570 if (NULL == proxy_nh_info) { 12571 return (BCM_E_PARAM); 12572 } 12573 12574 if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) { 12575 /* Make sure hw call is defined. */ 12576 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, proxy_nh_add)) { 12577 return (BCM_E_UNAVAIL); 12578 } 12579 12580 /* Convert API next hop entry to HW space format. */ 12581 rv = _bcm_esw_gport_resolve(unit, proxy_nh_info->gport, 12582 &modid, &port, &trunk, &id); 12583 BCM_IF_ERROR_RETURN(rv); 12584 12585 if ((proxy_nh_info->flags & BCM_L3_TGID) == 0) { 12586 BCM_IF_ERROR_RETURN 12587 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 12588 modid, port, 12589 &modid_out, &port_out)); 12590 if (!SOC_MODID_ADDRESSABLE(unit, modid_out)) { 12591 return (BCM_E_BADID); 12592 } 12593 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 12594 return (BCM_E_PORT); 12595 } 12596 SOC_GPORT_MODPORT_SET(proxy_nh_info->gport, modid_out, port_out); 12597 } 12598 } 12599 12600 /* Initialization */ 12601 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 12602 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 12603 data.width = _BCM_SINGLE_WIDE; 12604 data.oper_flags = flags; 12605 data.entry_buffer = (void *)proxy_nh_info; 12606 data.hash_func = _bcm_xgs3_nh_hash_calc; 12607 data.cmp_func = _bcm_xgs3_nh_ent_cmp; 12608 data.add_func = BCM_XGS3_L3_HWCALL(unit, proxy_nh_add); 12609 if (flags & _BCM_L3_SHR_WITH_ID) { 12610 data.entry_index = *index; 12611 } 12612 12613 /* Add next hop table entry. */ 12614 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_add(unit, &data)); 12615 *index = data.entry_index; 12616 12617 return (BCM_E_NONE); 12618 } 12619 12620 12621 /* 12622 * Function: 12623 * bcm_xgs3_proxy_nh_get 12624 * Purpose: 12625 * Parameters: 12626 * unit - (IN)SOC unit number. 12627 * nh_idx - (IN)Next hop index. 12628 * proxy_nh_info - (OUT)Buffer to fill next hop info. 12629 * Returns: 12630 * BCM_E_XXX 12631 */ 12632 int 12633 bcm_xgs3_proxy_nh_get(int unit, int nh_idx, bcm_proxy_egress_t *proxy_nh_info) 12634 { 12635 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 12636 12637 /* Make sure module was initialized. */ 12638 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 12639 return (BCM_E_INIT); 12640 } 12641 12642 /* Input parameters check. */ 12643 if (NULL == proxy_nh_info) { 12644 return (BCM_E_PARAM); 12645 } 12646 12647 /* Make sure entry is inuse. */ 12648 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_idx)) { 12649 return (BCM_E_NOT_FOUND); 12650 } 12651 12652 /* Get next hop entry from hw. */ 12653 if (BCM_XGS3_L3_HWCALL_CHECK(unit, proxy_nh_get)) { 12654 BCM_XGS3_L3_MODULE_LOCK(unit); 12655 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, proxy_nh_get) (unit, nh_idx, proxy_nh_info); 12656 BCM_XGS3_L3_MODULE_UNLOCK(unit); 12657 BCM_IF_ERROR_RETURN(rv); 12658 } 12659 return rv; 12660 } 12661 12662 #if defined (BCM_TRIUMPH_SUPPORT) 12663 /* 12664 * Function: 12665 * bcm_esw_l3_ingress_create 12666 * Purpose: 12667 * Create an Ingress Interface object. 12668 * Parameters: 12669 * unit - (IN) bcm device. 12670 * flags - (IN) BCM_L3_INGRESS_REPLACE: replace existing. 12671 * BCM_L3_INGRESS_WITH_ID: intf argument is given. 12672 * BCM_L3_INGRESS_GLOBAL_ROUTE : 12673 * BCM_L3_INGRESS_DSCP_TRUST : 12674 * ing_intf - (IN) Ingress Interface information. 12675 * intf_id - (OUT) L3 Ingress interface id pointing to Ingress object. 12676 * This is an IN argument if either BCM_L3_INGRESS_REPLACE 12677 * or BCM_L3_INGRESS_WITH_ID are given in flags. 12678 * Returns: 12679 * BCM_E_XXX 12680 */ 12681 12682 int 12683 bcm_xgs3_l3_ingress_create(int unit, bcm_l3_ingress_t *ing_intf, bcm_if_t *intf_id) 12684 { 12685 int rv = BCM_E_UNAVAIL; 12686 _bcm_l3_ingress_intf_t iif; /* Ingress interface. */ 12687 int intf_min; 12688 #ifdef BCM_TOMAHAWK_SUPPORT 12689 int ecn_map_index; 12690 int ecn_map_type; 12691 int ecn_map_num; 12692 #endif 12693 /* Make sure module was initialized. */ 12694 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 12695 return (BCM_E_INIT); 12696 } 12697 12698 /* Check L3 Ingress Interface mode. */ 12699 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 12700 return (BCM_E_DISABLED); 12701 } 12702 12703 /* Input parameters check. */ 12704 if ((NULL == ing_intf) || (NULL == intf_id)) { 12705 return (BCM_E_PARAM); 12706 } 12707 12708 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 12709 12710 L3_ING_IF_MIN(unit, intf_min); 12711 12712 /* WITH_ID and REPLACE flags check */ 12713 if (ing_intf->flags & BCM_L3_INGRESS_WITH_ID){ 12714 /* Check interface id range */ 12715 if ( (*intf_id < intf_min) || 12716 (*intf_id >= BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)) ) { 12717 return (BCM_E_PARAM); 12718 } 12719 iif.intf_id = *intf_id; 12720 iif.flags |= BCM_L3_INGRESS_WITH_ID; 12721 if (ing_intf->flags & BCM_L3_INGRESS_REPLACE) { 12722 iif.flags |= BCM_L3_INGRESS_REPLACE; 12723 } else if (0 != SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), *intf_id)) { 12724 /* Cannot overwrite if REPLACE Flag is not set */ 12725 return BCM_E_EXISTS; 12726 } 12727 } else if (ing_intf->flags & BCM_L3_INGRESS_REPLACE){ 12728 if (0 != SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), *intf_id)) { 12729 iif.intf_id = *intf_id; 12730 iif.flags |= BCM_L3_INGRESS_REPLACE; 12731 } else { 12732 return BCM_E_PARAM; 12733 } 12734 } 12735 12736 #ifdef BCM_TOMAHAWK3_SUPPORT 12737 if (soc_feature(unit, soc_feature_inband_network_telemetry)) { 12738 if (ing_intf->flags & BCM_L3_INGRESS_INT) { 12739 iif.flags |= BCM_L3_INGRESS_INT; 12740 } 12741 } 12742 #endif 12743 12744 /* Enable global route */ 12745 if (ing_intf->flags & BCM_L3_INGRESS_GLOBAL_ROUTE) { 12746 iif.flags |= BCM_L3_INGRESS_GLOBAL_ROUTE; 12747 } 12748 12749 /* Enable URPF Default Route Check */ 12750 if (ing_intf->flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) { 12751 iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 12752 } 12753 12754 if (ing_intf->flags & BCM_L3_INGRESS_DSCP_TRUST) { 12755 iif.qos_map_id = ing_intf->qos_map_id; 12756 iif.flags |= BCM_L3_INGRESS_DSCP_TRUST; 12757 } 12758 12759 if (ing_intf->flags & BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE) { 12760 iif.flags |= BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE; 12761 } 12762 12763 if (ing_intf->flags & BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU) { 12764 iif.flags |= BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU; 12765 } 12766 12767 if (ing_intf->flags & BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU) { 12768 iif.flags |= BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU; 12769 } 12770 12771 if (ing_intf->flags & BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU) { 12772 iif.flags |= BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU; 12773 } 12774 12775 if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST) { 12776 iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST; 12777 } 12778 12779 if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST) { 12780 iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST; 12781 } 12782 12783 if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST) { 12784 iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST; 12785 } 12786 12787 if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST) { 12788 iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST; 12789 } 12790 12791 if (ing_intf->flags & BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC) { 12792 iif.flags |= BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC; 12793 } 12794 12795 if (ing_intf->flags & BCM_L3_INGRESS_SRC_DST_NAT_REALM_ID) { 12796 iif.flags |= BCM_L3_INGRESS_SRC_DST_NAT_REALM_ID; 12797 } 12798 12799 if ((ing_intf->urpf_mode < bcmL3IngressUrpfDisable) || 12800 (ing_intf->urpf_mode > bcmL3IngressUrpfStrict)) { 12801 return BCM_E_PARAM; 12802 } 12803 #ifdef BCM_TOMAHAWK_SUPPORT 12804 if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) && 12805 soc_feature(unit, soc_feature_ecn_wred) && 12806 (ing_intf->flags & BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP)) { 12807 ecn_map_type = ing_intf->tunnel_term_ecn_map_id & 12808 _BCM_XGS5_ECN_MAP_TYPE_MASK; 12809 ecn_map_index = ing_intf->tunnel_term_ecn_map_id & 12810 _BCM_XGS5_ECN_MAP_NUM_MASK; 12811 ecn_map_num = 12812 soc_mem_index_count(unit, ING_TUNNEL_ECN_DECAPm) / 12813 _BCM_ECN_MAX_ENTRIES_PER_TUNNEL_TERM_MAP; 12814 if (ecn_map_type != _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM) { 12815 return BCM_E_PARAM; 12816 } 12817 if (ecn_map_index >= ecn_map_num) { 12818 return BCM_E_PARAM; 12819 } 12820 if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 12821 _bcmEcnmapTypeTunnelTerm)) { 12822 return BCM_E_PARAM; 12823 } 12824 iif.tunnel_term_ecn_map_id = ecn_map_index; 12825 iif.flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP; 12826 } 12827 #endif /* BCM_TOMAHAWK_SUPPORT */ 12828 iif.vrf = ing_intf->vrf; 12829 iif.if_class = ing_intf->intf_class; 12830 iif.ipmc_intf_id = ing_intf->ipmc_intf_id; 12831 iif.urpf_mode = ing_intf->urpf_mode; 12832 iif.nat_realm_id = ing_intf->nat_realm_id; 12833 iif.ip4_options_profile_id = ing_intf->ip4_options_profile_id; 12834 rv =_bcm_xgs3_l3_ingress_interface_add (unit, &iif); 12835 if (BCM_SUCCESS(rv)) { 12836 *intf_id = iif.intf_id; 12837 12838 #ifdef BCM_WARM_BOOT_SUPPORT 12839 SOC_CONTROL_LOCK(unit); 12840 SOC_CONTROL(unit)->scache_dirty = 1; 12841 SOC_CONTROL_UNLOCK(unit); 12842 #endif 12843 } 12844 return rv; 12845 } 12846 12847 /* 12848 * Function: 12849 * bcm_xgs3_l3_ingress_destroy 12850 * Purpose: 12851 * Destroy an Ingress Interface object. 12852 * Parameters: 12853 * unit - (IN) bcm device. 12854 * intf_id - (IN) L3 Ingress interface id pointing to Ingress object. 12855 * Returns: 12856 * BCM_E_XXX 12857 */ 12858 int 12859 bcm_xgs3_l3_ingress_destroy(int unit, bcm_if_t intf_id) 12860 { 12861 /* Make sure module was initialized. */ 12862 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 12863 return (BCM_E_INIT); 12864 } 12865 12866 /* Check L3 Ingress Interface mode. */ 12867 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 12868 return (BCM_E_DISABLED); 12869 } 12870 12871 /* Input parameters check. */ 12872 if ( (intf_id < 0) || (intf_id >= BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) { 12873 return (BCM_E_PARAM); 12874 } 12875 12876 BCM_IF_ERROR_RETURN 12877 (_bcm_xgs3_l3_ingress_interface_delete(unit, intf_id)); 12878 12879 #ifdef BCM_WARM_BOOT_SUPPORT 12880 SOC_CONTROL_LOCK(unit); 12881 SOC_CONTROL(unit)->scache_dirty = 1; 12882 SOC_CONTROL_UNLOCK(unit); 12883 #endif 12884 return BCM_E_NONE; 12885 } 12886 12887 /* 12888 * Function: 12889 * bcm_xgs3_l3_ingress_get 12890 * Purpose: 12891 * Get an Ingress Interface object. 12892 * Parameters: 12893 * unit - (IN) bcm device. 12894 * intf_id - (IN) L3 Ingress interface id pointing to Ingress object. 12895 * ing_intf - (OUT) Ingress Interface information. 12896 * Returns: 12897 * BCM_E_XXX 12898 */ 12899 int 12900 bcm_xgs3_l3_ingress_get(int unit, bcm_if_t intf_id, bcm_l3_ingress_t *ing_intf) 12901 { 12902 int rv = BCM_E_UNAVAIL; 12903 _bcm_l3_ingress_intf_t iif; /* Ingress interface. */ 12904 12905 /* Make sure module was initialized. */ 12906 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 12907 return (BCM_E_INIT); 12908 } 12909 12910 /* Check L3 Ingress Interface mode. */ 12911 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 12912 return (BCM_E_DISABLED); 12913 } 12914 12915 /* Input parameters check. */ 12916 if ( (intf_id < 0) || (intf_id > BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) { 12917 return (BCM_E_PARAM); 12918 } 12919 12920 if (!SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_id)) { 12921 return (BCM_E_NOT_FOUND); 12922 } 12923 /* Initialize ingress buffer */ 12924 (void) bcm_l3_ingress_t_init(ing_intf); 12925 iif.intf_id = intf_id; 12926 12927 rv = _bcm_xgs3_l3_ingress_interface_get(unit, &iif); 12928 if (BCM_SUCCESS(rv)) { 12929 ing_intf->vrf = iif.vrf; 12930 ing_intf->intf_class = iif.if_class; 12931 ing_intf->ipmc_intf_id = iif.ipmc_intf_id; 12932 ing_intf->urpf_mode = iif.urpf_mode; 12933 ing_intf->ip4_options_profile_id = iif.ip4_options_profile_id; 12934 ing_intf->nat_realm_id = iif.nat_realm_id; 12935 12936 if (iif.flags & BCM_L3_INGRESS_GLOBAL_ROUTE) { 12937 if (SOC_MEM_FIELD_VALID(unit, L3_IIF_PROFILEm, ALLOW_GLOBAL_ROUTEf)) { 12938 ing_intf->flags |= BCM_L3_INGRESS_GLOBAL_ROUTE; 12939 } 12940 } 12941 12942 if (iif.flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) { 12943 ing_intf->flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 12944 } 12945 12946 if (iif.flags & BCM_L3_INGRESS_DSCP_TRUST) { 12947 ing_intf->qos_map_id = iif.qos_map_id; 12948 ing_intf->flags |= BCM_L3_INGRESS_DSCP_TRUST; 12949 } 12950 12951 if (iif.flags & BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE) { 12952 ing_intf->flags |= BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE; 12953 } 12954 12955 if (iif.flags & BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU) { 12956 ing_intf->flags |= BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU; 12957 } 12958 12959 if (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU) { 12960 ing_intf->flags |= BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU; 12961 } 12962 12963 if (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU) { 12964 ing_intf->flags |= BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU; 12965 } 12966 12967 if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST) { 12968 ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST; 12969 } 12970 12971 if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST) { 12972 ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST; 12973 } 12974 12975 if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST) { 12976 ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST; 12977 } 12978 12979 if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST) { 12980 ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST; 12981 } 12982 12983 if (iif.flags & BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC) { 12984 ing_intf->flags |= BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC; 12985 } 12986 #ifdef BCM_TOMAHAWK_SUPPORT 12987 if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) && 12988 soc_feature(unit, soc_feature_ecn_wred) && 12989 (bcmi_xgs5_ecn_map_used_get(unit, ing_intf->tunnel_term_ecn_map_id, 12990 _bcmEcnmapTypeTunnelTerm) > 0)) { 12991 ing_intf->flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP; 12992 ing_intf->tunnel_term_ecn_map_id = iif.tunnel_term_ecn_map_id | 12993 _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM; 12994 } 12995 #endif 12996 } 12997 12998 return rv; 12999 } 13000 13001 /* 13002 * Function: 13003 * bcm_xgs3_l3_ingress_find 13004 * Purpose: 13005 * Find an Ingress Interface object. 13006 * Parameters: 13007 * unit - (IN) bcm device. 13008 * ing_intf - (IN) Ingress Interface information. 13009 * intf_id - (OUT) L3 Ingress interface id pointing to Ingress object. 13010 * Returns: 13011 * BCM_E_XXX 13012 */ 13013 int 13014 bcm_xgs3_l3_ingress_find(int unit, bcm_l3_ingress_t *ing_intf, 13015 bcm_if_t *intf_id) 13016 { 13017 _bcm_l3_ingress_intf_t iif; /* Ingress interface. */ 13018 int index_max; /* max index for L3_IIF */ 13019 int idx; /* Start index */ 13020 13021 /* Make sure module was initialized. */ 13022 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 13023 return (BCM_E_INIT); 13024 } 13025 13026 /* Check l3 switching mode. */ 13027 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 13028 return (BCM_E_DISABLED); 13029 } 13030 13031 /* Input parameters check. */ 13032 if ((NULL == ing_intf) || (NULL == intf_id)) { 13033 return (BCM_E_PARAM); 13034 } 13035 13036 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 13037 13038 13039 /* cannot match vrf or urpf_mode if these fields do not exist */ 13040 if (!soc_mem_field_valid(unit, L3_IIFm, VRFf) && 13041 ing_intf->vrf != 0) { 13042 return BCM_E_UNAVAIL; 13043 } 13044 if (!(soc_mem_field_valid(unit, L3_IIFm, URPF_MODEf) || 13045 (soc_feature(unit, soc_feature_l3_iif_profile) && 13046 soc_mem_field_valid(unit, L3_IIF_PROFILEm, URPF_MODEf))) && 13047 ing_intf->urpf_mode != 0) { 13048 return BCM_E_UNAVAIL; 13049 } 13050 13051 L3_ING_IF_MIN(unit, idx); 13052 13053 /* get max table index */ 13054 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ing_intf)); 13055 for (;idx <= index_max; idx++) { 13056 if (!SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx)) { 13057 continue; 13058 } 13059 13060 iif.intf_id = idx; 13061 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ingress_interface_get(unit, &iif)); 13062 13063 /* Match VRF */ 13064 if (iif.vrf != ing_intf->vrf) { 13065 continue; 13066 } 13067 13068 /* Match urpf_mode */ 13069 if (iif.urpf_mode != ing_intf->urpf_mode) { 13070 continue; 13071 } 13072 break; 13073 } 13074 13075 if (idx > index_max) { 13076 return BCM_E_NOT_FOUND; 13077 } 13078 13079 *intf_id = idx; 13080 13081 return (BCM_E_NONE); 13082 } 13083 13084 /* 13085 * Function: 13086 * _bcm_xgs3_ing_intf_traverse_cb 13087 * Purpose: 13088 * Call user callback for valid L3_IIF entries. 13089 * Parameters: 13090 * unit - (IN)SOC unit number. 13091 * pattern - (IN)Match pattern (interface id & negate). 13092 * data1 - (IN)Route info. 13093 * data2 - (IN)Next hop info. 13094 * cmp_result- (OUT)Comparison result. 13095 * Returns: 13096 * BCM_E_XXX 13097 */ 13098 STATIC int 13099 _bcm_xgs3_ing_intf_traverse_cb(int unit, void *pattern, void *data1, 13100 void *data2, int *cmp_result) 13101 { 13102 _bcm_l3_trvrs_data_t *trv_data; /* Travers data. */ 13103 bcm_l3_ingress_t *ing_intf; /* Ingress object. */ 13104 int intf_id; /* L3 IIF index. */ 13105 13106 13107 /* Cast input parameters. */ 13108 trv_data = (_bcm_l3_trvrs_data_t *) pattern; 13109 ing_intf = (bcm_l3_ingress_t *) data1; 13110 intf_id = *(int *)data2; 13111 13112 /* Call user callback. */ 13113 if (NULL != trv_data->ingress_cb) { 13114 (*trv_data->ingress_cb) (unit, intf_id, ing_intf, trv_data->cookie); 13115 } 13116 13117 return (BCM_E_NONE); 13118 } 13119 13120 13121 /* 13122 * Function: 13123 * bcm_xgs3_l3_ingress_traverse 13124 * Purpose: 13125 * Goes through ingress interface objects table and runs the user callback 13126 * function at each valid ingress objects entry passing back the 13127 * information for that object. 13128 * Parameters: 13129 * unit - (IN) bcm device. 13130 * trav_fn - (IN) Callback function. 13131 * user_data - (IN) User data to be passed to callback function. 13132 * Returns: 13133 * BCM_E_XXX 13134 */ 13135 13136 int 13137 bcm_xgs3_l3_ingress_traverse(int unit, bcm_l3_ingress_traverse_cb trav_fn, 13138 void *user_data) 13139 { 13140 _bcm_l3_trvrs_data_t trv_data; /* Travers initiator function input. */ 13141 13142 /* Make sure module was initialized. */ 13143 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 13144 return (BCM_E_INIT); 13145 } 13146 13147 /* Check l3 switching mode. */ 13148 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 13149 return (BCM_E_DISABLED); 13150 } 13151 13152 /* Input parameters check. */ 13153 if (NULL == trav_fn) { 13154 return (BCM_E_PARAM); 13155 } 13156 13157 /* Zero traverse info. */ 13158 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 13159 13160 /* Fill traverse data struct. */ 13161 trv_data.op_cb = _bcm_xgs3_ing_intf_traverse_cb; 13162 trv_data.ingress_cb = trav_fn; 13163 trv_data.cookie = user_data; 13164 13165 /* Update_match */ 13166 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_update_match)) { 13167 int rv; 13168 BCM_XGS3_L3_MODULE_LOCK(unit); 13169 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_update_match) (unit, &trv_data); 13170 BCM_XGS3_L3_MODULE_UNLOCK(unit); 13171 return rv; 13172 } 13173 13174 return (BCM_E_UNAVAIL); 13175 } 13176 13177 13178 /* 13179 * Function: 13180 * _bcm_xgs3_ing_intf_entry_parse 13181 * Purpose: 13182 * Parse the L3 Ingress Interface table entry info. 13183 * Parameters: 13184 * unit - (IN) SOC unit number. 13185 * ing_entry_ptr - (IN) Ingress Interface table entry. 13186 * bcm_l3_ingress_t - (OUT) Ingress Interface table entry info. 13187 * Returns: 13188 * BCM_E_XXX 13189 */ 13190 13191 STATIC int 13192 _bcm_xgs3_ing_intf_entry_parse(int unit, uint32 *ing_entry_ptr, 13193 bcm_l3_ingress_t *ing_intf_entry) 13194 { 13195 soc_mem_t mem; /* Table location memory. */ 13196 int hw_map_idx=0; 13197 #ifdef BCM_TRIDENT2_SUPPORT 13198 iif_entry_t entry; /* HW entry buffer. */ 13199 uint32 index; 13200 void *entries[1]; 13201 iif_profile_entry_t l3_iif_profile; 13202 #endif 13203 13204 /* Zero buffers. */ 13205 sal_memset(ing_intf_entry, 0, sizeof(bcm_l3_ingress_t)); 13206 13207 /* Get next hop table memory location. */ 13208 mem = BCM_XGS3_L3_MEM(unit, ing_intf); 13209 13210 /* Get class id value. */ 13211 if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, CLASS_IDf)) { 13212 ing_intf_entry->intf_class = soc_mem_field32_get(unit, 13213 mem, ing_entry_ptr, CLASS_IDf); 13214 } 13215 13216 /* Get vrf id value. */ 13217 if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, VRFf)) { 13218 ing_intf_entry->vrf = soc_mem_field32_get(unit, 13219 mem, ing_entry_ptr, VRFf); 13220 } 13221 13222 /* Get Flags value. */ 13223 if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, ALLOW_GLOBAL_ROUTEf)) { 13224 if (1 == soc_mem_field32_get(unit, mem, ing_entry_ptr, 13225 ALLOW_GLOBAL_ROUTEf)) { 13226 ing_intf_entry->flags |= BCM_L3_INGRESS_GLOBAL_ROUTE; 13227 } 13228 } 13229 13230 #ifdef BCM_TRIDENT2_SUPPORT 13231 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) 13232 || SOC_IS_TRIDENT3X(unit)) { 13233 /* Get l3 iif profile entry */ 13234 entries[0] = &l3_iif_profile; 13235 index = soc_mem_field32_get(unit, L3_IIFm, (uint32 *)&entry, 13236 L3_IIF_PROFILE_INDEXf); 13237 if (_bcm_l3_iif_profile_entry_get(unit, index, 1, entries) 13238 != BCM_E_NONE) { 13239 return BCM_E_FAIL; 13240 } 13241 } 13242 #endif 13243 13244 /* Get Trust QoS Map Id Value. */ 13245 if (soc_mem_field_valid(unit, L3_IIFm, TRUST_DSCP_PTRf)) { 13246 hw_map_idx = soc_mem_field32_get(unit, mem, ing_entry_ptr, 13247 TRUST_DSCP_PTRf); 13248 } 13249 #ifdef BCM_TRIDENT2_SUPPORT 13250 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) 13251 || SOC_IS_TRIDENT3X(unit)) { 13252 hw_map_idx = soc_mem_field32_get(unit, L3_IIF_PROFILEm, 13253 &l3_iif_profile, TRUST_DSCP_PTRf); 13254 } 13255 #endif 13256 if (hw_map_idx != 63) { 13257 if (SOC_IS_TRIUMPH(unit) || SOC_IS_VALKYRIE(unit)) { 13258 BCM_IF_ERROR_RETURN 13259 (_bcm_tr_qos_idx2id(unit, hw_map_idx, 0x3, 13260 &ing_intf_entry->qos_map_id)); 13261 } else { 13262 #ifdef BCM_TRIUMPH2_SUPPORT 13263 BCM_IF_ERROR_RETURN 13264 (_bcm_tr2_qos_idx2id(unit, hw_map_idx, 0x3, 13265 &ing_intf_entry->qos_map_id)); 13266 #endif /*BCM_TRIUMPH2_SUPPORT*/ 13267 } 13268 ing_intf_entry->flags |= BCM_L3_INGRESS_DSCP_TRUST; 13269 } 13270 13271 #ifdef BCM_TRIUMPH2_SUPPORT 13272 if (soc_mem_field_valid(unit, mem, IPMC_L3_IIFf)) { 13273 ing_intf_entry->ipmc_intf_id = soc_mem_field32_get(unit, mem, 13274 ing_entry_ptr, IPMC_L3_IIFf); 13275 } 13276 #endif 13277 13278 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_HURRICANE3_SUPPORT) 13279 if (soc_mem_field_valid(unit, L3_IIFm, URPF_MODEf)) { 13280 ing_intf_entry->urpf_mode = soc_mem_field32_get(unit, mem, 13281 ing_entry_ptr, URPF_MODEf); 13282 } 13283 13284 if (soc_mem_field_valid(unit, L3_IIFm, URPF_DEFAULTROUTECHECKf)) { 13285 if (1 == soc_mem_field32_get(unit, mem, ing_entry_ptr, 13286 URPF_DEFAULTROUTECHECKf)) { 13287 ing_intf_entry->flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 13288 } 13289 } 13290 #endif /* BCM_TRIDENT_SUPPORT || BCM_HURRICANE3_SUPPORT */ 13291 #ifdef BCM_TRIDENT2_SUPPORT 13292 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) 13293 || SOC_IS_TRIDENT3X(unit)) { 13294 if (SOC_MEM_FIELD_VALID( 13295 unit, L3_IIF_PROFILEm, URPF_DEFAULTROUTECHECKf)) { 13296 if (1 == soc_mem_field32_get(unit, L3_IIF_PROFILEm, 13297 &l3_iif_profile, URPF_DEFAULTROUTECHECKf)) { 13298 ing_intf_entry->flags |= 13299 BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 13300 } 13301 } 13302 } 13303 #endif 13304 #ifdef BCM_TOMAHAWK_SUPPORT 13305 if (SOC_IS_TOMAHAWKX(unit)) { 13306 if (soc_mem_field_valid(unit, L3_IIF_PROFILEm, IPMC_MISS_AS_L2MCf)) { 13307 if (0 != soc_mem_field32_get(unit, L3_IIF_PROFILEm, 13308 &l3_iif_profile, 13309 IPMC_MISS_AS_L2MCf)) { 13310 ing_intf_entry->flags |= BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC; 13311 } 13312 } 13313 } 13314 #endif 13315 13316 return BCM_E_NONE; 13317 } 13318 13319 /* 13320 * Function: 13321 * _bcm_xgs3_ing_intf_update_match 13322 * Purpose: 13323 * Update/Show/Delete all entries in L3_IIF table matching a certain rule. 13324 * Parameters: 13325 * unit - (IN)SOC unit number. 13326 * trv_data - (IN)Delete pattern + compare,act,notify routines. 13327 * Returns: 13328 * BCM_E_XXX 13329 */ 13330 STATIC int 13331 _bcm_xgs3_ing_intf_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 13332 { 13333 bcm_l3_ingress_t ing_intf_entry; /* Next hop entry info. */ 13334 uint32 *ing_entry_ptr; /* Ingress L3-IIF Table entry pointer.*/ 13335 char *ing_tbl_ptr; /* Dma table pointer. */ 13336 int cmp_result; /* Test routine result. */ 13337 soc_mem_t mem; /* Next hop memory. */ 13338 int idx,start_iif; /* Iteration index. */ 13339 int rv = BCM_E_NONE; /* Operation return status. */ 13340 13341 /* Get L3-IIF Table memory. */ 13342 mem = BCM_XGS3_L3_MEM(unit, ing_intf); 13343 13344 L3_ING_IF_MIN(unit, start_iif); 13345 13346 /* Table DMA the L3-IIF table to software copy */ 13347 BCM_IF_ERROR_RETURN 13348 (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, ing_intf), "ing_intf_tbl", 13349 &ing_tbl_ptr, NULL)); 13350 13351 for (idx = start_iif; idx < BCM_XGS3_L3_ING_IF_TBL_SIZE(unit); idx++) { 13352 /* Skip unused entries. */ 13353 if (0 == SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx)) { 13354 continue; 13355 } 13356 13357 /* Calculate entry ofset. */ 13358 ing_entry_ptr = 13359 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx); 13360 13361 (void) _bcm_xgs3_ing_intf_entry_parse(unit, ing_entry_ptr, &ing_intf_entry); 13362 13363 /* Execute operation routine if any. */ 13364 if (trv_data->op_cb) { 13365 rv = (*trv_data->op_cb)(unit, (void *)trv_data, 13366 (void *)&ing_intf_entry,(void *)&idx, &cmp_result); 13367 if (rv < 0) { 13368 #ifdef BCM_CB_ABORT_ON_ERR 13369 if (SOC_CB_ABORT_ON_ERR(unit)) { 13370 break; 13371 } 13372 #endif 13373 } 13374 } 13375 } 13376 soc_cm_sfree(unit, ing_tbl_ptr); 13377 return (rv); 13378 } 13379 13380 #endif /*BCM_TRIUMPH_SUPPORT*/ 13381 13382 /* 13383 * Function: 13384 * bcm_xgs3_l3_egress_id_parse 13385 * Purpose: 13386 * Parse Egress object, to return flag and next hop / ecmp group id. 13387 * Parameters: 13388 * unit - (IN) bcm device. 13389 * intf - (IN) Interface id pointing to egress object or 13390 * multipath egress object. 13391 * flags - (OUT) BCM_L3_MULTIPATH if interface points to multipath 13392 * egress object. 13393 * nh_ecmp_id - (OUT) Next hop /ecmp group id. 13394 * Returns: 13395 * BCM_E_DISABLED - if advanced egress switching disabled. 13396 * BCM_E_PARAM - if invalid interface id passed. 13397 * BCM_E_NONE - otherwise. 13398 */ 13399 int 13400 bcm_xgs3_l3_egress_id_parse(int unit, bcm_if_t intf, 13401 uint32 *flags, int *nh_ecmp_id) 13402 { 13403 /* Check if L3 feature is supported on the device */ 13404 if (!soc_feature(unit, soc_feature_l3)) { 13405 return (BCM_E_UNAVAIL); 13406 } 13407 13408 /* Make sure module was initialized. */ 13409 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 13410 return (BCM_E_INIT); 13411 } 13412 13413 /* Check l3 switching mode. */ 13414 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 13415 return (BCM_E_DISABLED); 13416 } 13417 13418 /* Input parameters check. */ 13419 if ((NULL == flags) || (NULL == nh_ecmp_id)) { 13420 return (BCM_E_PARAM); 13421 } 13422 13423 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 13424 *nh_ecmp_id = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 13425 /* Make sure next hop is in use. */ 13426 if (!BCM_XGS3_L3_ENT_REF_CNT 13427 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *nh_ecmp_id)) { 13428 return (BCM_E_PARAM); 13429 } 13430 *flags = 0; 13431 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 13432 *nh_ecmp_id = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 13433 /* Make sure next hop is in use. */ 13434 if (!BCM_XGS3_L3_ENT_REF_CNT 13435 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *nh_ecmp_id)) { 13436 return (BCM_E_PARAM); 13437 } 13438 *flags = 0; 13439 } else if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) { 13440 *nh_ecmp_id = intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 13441 /* Make sure ecmp grp is in use. */ 13442 #ifdef BCM_TOMAHAWK3_SUPPORT 13443 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 13444 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 13445 ecmp_mode_hierarchical) && 13446 (*nh_ecmp_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 13447 if (!BCM_XGS3_L3_ENT_REF_CNT 13448 (BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), *nh_ecmp_id)) { 13449 return (BCM_E_PARAM); 13450 } 13451 13452 } else 13453 #endif 13454 if (!BCM_XGS3_L3_ENT_REF_CNT 13455 (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), *nh_ecmp_id)) { 13456 return (BCM_E_PARAM); 13457 } 13458 *flags = BCM_L3_MULTIPATH; 13459 } else { 13460 return (BCM_E_PARAM); 13461 } 13462 13463 return (BCM_E_NONE); 13464 } 13465 13466 /* 13467 * Function: 13468 * _bcm_xgs3_l3_egress_to_nh_info 13469 * Purpose: 13470 * Map API egress object data to hw used next hop format. 13471 * Parameters: 13472 * unit - (IN) bcm device. 13473 * egr - (IN) Egress object properties to match. 13474 * nh_info - (IN/OUT) L3 interface id pointing to egress object 13475 * Returns: 13476 * BCM_E_XXX. 13477 */ 13478 STATIC int 13479 _bcm_xgs3_l3_egress_to_nh_info(int unit, bcm_l3_egress_t *egr, 13480 bcm_l3_egress_t *nh_info) 13481 { 13482 #ifdef BCM_FIREBOLT_SUPPORT 13483 _bcm_l3_intf_cfg_t l3_intf; /* Outgoing interface info. */ 13484 int interface_map_mode=0; 13485 int rv; 13486 #endif /* BCM_FIREBOLT_SUPPORT */ 13487 13488 #ifdef BCM_TRIUMPH_SUPPORT 13489 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 13490 /* Check L3 Ingress Interface Map mode. */ 13491 BCM_IF_ERROR_RETURN (bcm_xgs3_l3_ingress_intf_map_get(unit, &interface_map_mode)); 13492 } 13493 #endif /* BCM_TRIUMPH_SUPPORT */ 13494 13495 13496 /* Copy user info to local structure to preserve user structure. */ 13497 *nh_info = *egr; 13498 13499 /* If trap to cpu required overwrite mac/module/intf/port. */ 13500 if (nh_info->flags & BCM_L3_L2TOCPU) { 13501 /* Set module id to a local module. */ 13502 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &nh_info->module)); 13503 13504 /* Set port to be a cpu port. */ 13505 nh_info->port = CMIC_PORT(unit); 13506 13507 /* Set interface to be cpu interface. */ 13508 nh_info->intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit); 13509 } 13510 #ifdef BCM_FIREBOLT_SUPPORT 13511 /* Firebolt devices need interface info to fill vid & tunnel next hop. */ 13512 else if (SOC_IS_FBX(unit)) { 13513 /* Read interface information. */ 13514 /* Verify interface index range. */ 13515 if ((nh_info->intf != BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) && 13516 (nh_info->intf != BCM_IF_INVALID)) { 13517 if (nh_info->intf >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 13518 return (BCM_E_PARAM); 13519 } 13520 sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 13521 BCM_XGS3_L3_INTF_IDX_SET(l3_intf, nh_info->intf); 13522 BCM_XGS3_L3_MODULE_LOCK(unit); 13523 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf); 13524 BCM_XGS3_L3_MODULE_UNLOCK(unit); 13525 if (rv >= 0) { 13526 if (interface_map_mode) { 13527 nh_info->vlan = egr->vlan; 13528 } else { 13529 /* Set vid to next hop entry. */ 13530 nh_info->vlan = l3_intf.l3i_vid; 13531 if (!BCM_VLAN_VALID(nh_info->vlan)) { 13532 return (BCM_E_CONFIG); 13533 } 13534 } 13535 } 13536 }else { 13537 /* Set as Internally configured interface */ 13538 nh_info->intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit); 13539 nh_info->vlan = 0; 13540 } 13541 } 13542 #endif /* BCM_FIREBOLT_SUPPORT */ 13543 13544 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_GREYHOUND_SUPPORT) 13545 if (nh_info->flags & BCM_L3_IPMC) { 13546 if (!soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop) && 13547 !soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) { 13548 return BCM_E_UNAVAIL; 13549 } 13550 } 13551 #endif /* BCM_TRIUMPH3_SUPPORT */ 13552 13553 if ((nh_info->flags2 & BCM_L3_FLAGS2_UNDERLAY) && (nh_info->flags & BCM_L3_IPMC)) { 13554 if (BCM_GPORT_IS_VXLAN_PORT(egr->port)) { 13555 nh_info->port = 0; 13556 } 13557 } 13558 13559 return (BCM_E_NONE); 13560 } 13561 13562 #ifdef BCM_TRIDENT_SUPPORT 13563 /* 13564 * Function: 13565 * _bcm_xgs3_trunk_replace_check 13566 * Purpose: 13567 * Store old trunk-id in replace operation to reset the next hop store 13568 * Parameters: 13569 * unit - (IN) bcm device. 13570 * flag - (IN) L3 egress flags 13571 * egr_nh_old - (IN) Pointer to L3 Egress object. 13572 * trunk_id_in_use - (OUT) used-trunk-id in replace operation 13573 * Returns: 13574 * BCM_E_XXX. 13575 */ 13576 STATIC int 13577 _bcm_xgs3_trunk_replace_check(int unit, uint32 flags, 13578 bcm_l3_egress_t* egr_nh_old, 13579 bcm_trunk_t *trunk_id_in_use) 13580 { 13581 13582 if (( soc_feature(unit, soc_feature_trill) && (flags & BCM_L3_TRILL_ONLY)) || 13583 ( soc_feature(unit, soc_feature_l2gre) && (flags & BCM_L3_L2GRE_ONLY)) || 13584 ( soc_feature(unit, soc_feature_vxlan) && (flags & BCM_L3_VXLAN_ONLY)) ) { 13585 13586 if (egr_nh_old == NULL) { 13587 return BCM_E_INTERNAL; 13588 } 13589 /* Check if we are replacing a trunk destination */ 13590 if (BCM_L3_TGID & egr_nh_old->flags) { 13591 *trunk_id_in_use = egr_nh_old->trunk; 13592 } 13593 } 13594 return BCM_E_NONE; 13595 } 13596 13597 /* 13598 * Function: 13599 * _bcm_xgs3_trunk_update_check 13600 * Purpose: 13601 * Update used-trunk-id member-ports in replace operation to update the next hop store 13602 * Parameters: 13603 * unit - (IN) bcm device. 13604 * nh_info - (IN) L3 Egress_object 13605 * tid_in_use - (IN) used-trunk-id in replace operation 13606 * index - (IN) Next hop index. 13607 * Returns: 13608 * BCM_E_XXX. 13609 */ 13610 STATIC int 13611 _bcm_xgs3_trunk_update_check(int unit, bcm_l3_egress_t *nh_info, bcm_trunk_t tid_in_use, int index) 13612 { 13613 13614 /* For a replace operation where Trunk id is replaced, 13615 * de-link the old trunk id from the next hop store. 13616 */ 13617 if (tid_in_use != -1) { 13618 /* if the destination is trunk then replacing tid 13619 * should be different from replaced tid 13620 */ 13621 if (BCM_L3_TGID & nh_info->flags) { 13622 if (tid_in_use != nh_info->port) { 13623 BCM_IF_ERROR_RETURN(_bcm_xgs3_trunk_nh_store_unmap(unit, tid_in_use, index)); 13624 } 13625 } else { 13626 BCM_IF_ERROR_RETURN(_bcm_xgs3_trunk_nh_store_unmap(unit, tid_in_use, index)); 13627 } 13628 } 13629 return BCM_E_NONE; 13630 } 13631 13632 /* 13633 * Function: 13634 * _bcm_xgs3_l3_egress_nhi_mapping_store 13635 * Purpose: 13636 * Store old trunk/module-id/port-id in replace operation 13637 * to reset the nhi mapping store 13638 * Parameters: 13639 * unit - (IN) bcm device 13640 * intf - (IN) L3 interface id pointing to Egress object 13641 * tgid - (OUT) used-trunk-id 13642 * modid - (OUT) used-mod-id 13643 * portid - (OUT) used-port-id 13644 * Returns: 13645 * BCM_E_XXX. 13646 */ 13647 STATIC int 13648 _bcm_xgs3_l3_egress_nhi_mapping_store(int unit, uint32 flags, 13649 bcm_if_t intf, bcm_trunk_t *tgid, 13650 bcm_module_t *modid, bcm_port_t *portid) 13651 { 13652 bcm_l3_egress_t egr_nh_old; 13653 int rv = BCM_E_NONE; 13654 13655 rv = bcm_xgs3_l3_egress_get(unit, intf, &egr_nh_old); 13656 if (BCM_SUCCESS(rv)) { 13657 /* Only for Unicast Next-hops */ 13658 if (!(egr_nh_old.flags & BCM_L3_IPMC) && 13659 ((egr_nh_old.flags & BCM_L3_VXLAN_ONLY)|| 13660 (egr_nh_old.flags & BCM_L3_TRILL_ONLY) || 13661 (egr_nh_old.flags & BCM_L3_L2GRE_ONLY))) { 13662 *modid = egr_nh_old.module; 13663 *portid = egr_nh_old.port; 13664 13665 if (egr_nh_old.flags & BCM_L3_TGID) { 13666 *tgid = egr_nh_old.trunk; 13667 } 13668 } 13669 } 13670 13671 return BCM_E_NONE; 13672 } 13673 13674 /* 13675 * Function: 13676 * _bcm_xgs3_l3_egress_nhi_mapping_reset 13677 * Purpose: 13678 * Reset NHI mappping store entry 13679 * Parameters: 13680 * unit - (IN) bcm device. 13681 * nh_index - (IN) nexthop index 13682 * old_tgid - (IN) trunk id 13683 * old_modid - (IN) module id 13684 * old_portid - (IN) port id 13685 * flags - (IN) flag information 13686 * Returns: 13687 * BCM_E_XXX 13688 */ 13689 STATIC int 13690 _bcm_xgs3_l3_egress_nhi_mapping_reset(int unit, int nh_index, 13691 bcm_trunk_t old_tgid, 13692 bcm_module_t old_modid, 13693 bcm_port_t old_portid, 13694 uint32 flags) 13695 { 13696 ing_l3_next_hop_entry_t ing_nh; 13697 int rv = BCM_E_NONE; 13698 int is_local = 0; 13699 bcm_port_t portid = 0; 13700 bcm_trunk_t tgid = 0; 13701 int num_ports = 0; 13702 int idx = -1; 13703 bcm_port_t local_ports[SOC_MAX_NUM_PORTS]; 13704 int modid = 0; 13705 int gport = 0; 13706 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 13707 bcm_trunk_member_t *tmp_member_gports_array = NULL; 13708 #endif 13709 13710 if (!(flags & BCM_L3_REPLACE)) { 13711 /* Ingore if not replace action */ 13712 return BCM_E_NONE; 13713 } 13714 13715 BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm, 13716 MEM_BLOCK_ANY, nh_index, &ing_nh)); 13717 if (soc_feature(unit, soc_feature_generic_dest)) { 13718 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID, dest = 0; 13719 dest = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh, 13720 DESTINATIONf, &dest_type); 13721 portid = (dest & SOC_MEM_FIF_DGPP_TGID_MASK); 13722 if (dest_type == SOC_MEM_FIF_DEST_LAG) { 13723 tgid = (dest & SOC_MEM_FIF_DGPP_TGID_MASK); 13724 } else if (dest_type == SOC_MEM_FIF_DEST_DGPP) { 13725 modid = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >> 13726 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS; 13727 } 13728 } else { 13729 #ifdef BCM_TOMAHAWK3_SUPPORT 13730 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 13731 modid = 0; 13732 } else 13733 #endif 13734 { 13735 modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf); 13736 } 13737 } 13738 if (old_tgid != -1) { 13739 if (!soc_feature(unit, soc_feature_generic_dest)) { 13740 if (soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf)) { 13741 tgid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 13742 &ing_nh, TGIDf); 13743 } 13744 } 13745 13746 if (old_tgid != tgid) { 13747 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 13748 rv = bcm_esw_trunk_get(unit, old_tgid, NULL, 0, NULL, &num_ports); 13749 if (BCM_FAILURE(rv)) { 13750 return BCM_E_PORT; 13751 } 13752 if (num_ports == 0) { 13753 return BCM_E_NONE; 13754 } 13755 13756 if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 13757 tmp_member_gports_array = sal_alloc( 13758 sizeof(bcm_trunk_member_t) * num_ports, "tmp_member_gports_arry"); 13759 if (tmp_member_gports_array == NULL) { 13760 return BCM_E_MEMORY; 13761 } 13762 sal_memset(tmp_member_gports_array, 0, 13763 sizeof(bcm_trunk_member_t) * num_ports); 13764 rv = bcm_esw_trunk_get(unit, old_tgid, NULL, 13765 num_ports, tmp_member_gports_array, &num_ports); 13766 if (BCM_FAILURE(rv)) { 13767 goto clean_up; 13768 } 13769 } else 13770 #endif 13771 { 13772 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, old_tgid, 13773 SOC_MAX_NUM_PORTS, local_ports, &num_ports)); 13774 } 13775 } 13776 } else if (old_portid != -1) { 13777 BCM_IF_ERROR_RETURN 13778 (_bcm_esw_modid_is_local(unit, old_modid, &is_local)); 13779 if (!is_local) { 13780 if (!soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 13781 /* Ignore EGR_PORT_TO_NHI_MAPPINGs */ 13782 return BCM_E_NONE; 13783 } 13784 } 13785 13786 if (!soc_feature(unit, soc_feature_generic_dest)) { 13787 portid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 13788 &ing_nh, PORT_NUMf); 13789 } 13790 if ((old_portid != portid) || (old_modid != modid)) { 13791 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 13792 if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 13793 /* Alloc one trunk member size memory */ 13794 tmp_member_gports_array = sal_alloc( 13795 sizeof(bcm_trunk_member_t), "tmp_member_gports_arry"); 13796 if (tmp_member_gports_array == NULL) { 13797 return BCM_E_MEMORY; 13798 } 13799 sal_memset(tmp_member_gports_array, 0, 13800 sizeof(bcm_trunk_member_t)); 13801 BCM_GPORT_MODPORT_SET(gport, old_modid, old_portid); 13802 tmp_member_gports_array[num_ports++].gport = gport; 13803 } else 13804 #endif 13805 { 13806 local_ports[num_ports++] = old_portid; 13807 } 13808 } 13809 } 13810 13811 for (idx = 0; idx < num_ports; idx++) { 13812 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 13813 if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 13814 gport = tmp_member_gports_array[idx].gport; 13815 } else 13816 #endif 13817 { 13818 BCM_GPORT_MODPORT_SET(gport, old_modid, local_ports[idx]); 13819 } 13820 13821 rv = _bcm_trx_gport_to_nhi_set(unit, gport, 0); 13822 if (BCM_FAILURE(rv)) { 13823 goto clean_up; 13824 } 13825 } 13826 13827 clean_up: 13828 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 13829 if (NULL != tmp_member_gports_array) { 13830 sal_free(tmp_member_gports_array); 13831 } 13832 #endif 13833 13834 return rv; 13835 } 13836 #endif /* BCM_TRIDENT_SUPPORT */ 13837 13838 /* 13839 * Function: 13840 * bcm_xgs3_l3_egress_create 13841 * Purpose: 13842 * Create an Egress forwarding object. 13843 * Parameters: 13844 * unit - (IN) bcm device. 13845 * flags - (IN) BCM_L3_REPLACE: replace existing. 13846 * BCM_L3_WITH_ID: intf argument is given. 13847 * egr - (IN) Egress forwarding destination. 13848 * intf - (OUT) L3 interface id pointing to Egress object. 13849 * This is an IN argument if either BCM_L3_REPLACE 13850 * or BCM_L3_WITH_ID are given in flags. 13851 * Returns: 13852 * BCM_E_XXX 13853 */ 13854 int 13855 bcm_xgs3_l3_egress_create(int unit, uint32 flags, bcm_l3_egress_t *egr, 13856 bcm_if_t *intf) 13857 { 13858 int err_code = BCM_E_NONE; /* Used for cleanup. */ 13859 int index = -1; /* Next hop index. */ 13860 bcm_l3_egress_t nh_info; /* Next hop entry. */ 13861 uint32 shr_flags; /* Table shared flags. */ 13862 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) 13863 uint32 entry_type=0; /* Next Hop Entry_type */ 13864 #endif /* BCM_TRIUMPH_SUPPORT && BCM_MPLS_SUPPORT */ 13865 #if defined(BCM_TRIUMPH2_SUPPORT) 13866 uint32 protection_flags=0; 13867 uint32 old_l3_payload = 0xffffffff; 13868 #endif /* BCM_TRIUMPH2_SUPPORT */ 13869 #if defined(BCM_TRIDENT_SUPPORT) 13870 int rv; 13871 bcm_trunk_t tid_in_use = -1; 13872 bcm_trunk_t tgid = -1; 13873 bcm_module_t modid = -1; 13874 bcm_port_t portid = -1; 13875 bcm_l3_egress_t egr_nh_old, *p_egr_nh_old = NULL; 13876 #endif /* BCM_TRIDENT_SUPPORT */ 13877 int egress_obj_update = 0; 13878 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT) 13879 int overlay_nh = FALSE; 13880 #endif 13881 int entry_flag = 0; 13882 13883 /* Make sure module was initialized. */ 13884 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 13885 return (BCM_E_INIT); 13886 } 13887 13888 /* Check l3 switching mode. */ 13889 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 13890 return (BCM_E_DISABLED); 13891 } 13892 13893 /* Input parameters check. */ 13894 if ((NULL == egr) || (NULL == intf)) { 13895 return (BCM_E_PARAM); 13896 } 13897 13898 /* Flags check */ 13899 if ((!soc_feature(unit, soc_feature_trill)) && 13900 (egr->flags & BCM_L3_TRILL_ONLY)) { 13901 return (BCM_E_PARAM); 13902 } 13903 13904 if (!(soc_feature(unit, soc_feature_vxlan) || 13905 soc_feature(unit, soc_feature_vxlan_lite)) && 13906 (egr->flags & BCM_L3_VXLAN_ONLY)) { 13907 return (BCM_E_PARAM); 13908 } 13909 13910 if ((!soc_feature(unit, soc_feature_l2gre)) && 13911 (egr->flags & BCM_L3_L2GRE_ONLY)) { 13912 return (BCM_E_PARAM); 13913 } 13914 13915 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 13916 if ((!soc_feature(unit, soc_feature_flex_flow)) && 13917 (egr->flags2 & BCM_L3_FLOW_ONLY)) { 13918 return (BCM_E_PARAM); 13919 } 13920 13921 if ((!soc_feature(unit, soc_feature_flex_flow)) && 13922 (egr->flags2 & BCM_L3_MPLS_GRE_LABEL)) { 13923 return (BCM_E_PARAM); 13924 } 13925 #endif 13926 13927 #if defined(BCM_TRIDENT3_SUPPORT) 13928 if (soc_feature(unit, soc_feature_flex_flow) && 13929 (egr->flow_handle != 0) && 13930 ((egr->flags2 & BCM_L3_FLAGS2_FIELD_ONLY) || 13931 (egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP) || 13932 (egr->flags & BCM_L3_ROUTE_LABEL))) { 13933 return (BCM_E_PARAM); 13934 } 13935 13936 if (soc_feature(unit, soc_feature_large_scale_nat)) { 13937 if (egr->replication_id < 0 || 13938 egr->replication_id > 0xffff) { 13939 return (BCM_E_PARAM); 13940 } 13941 } 13942 #endif 13943 13944 if ((!soc_feature(unit, soc_feature_nh_for_ifp_actions)) && 13945 (egr->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) { 13946 return (BCM_E_UNAVAIL); 13947 } 13948 13949 if ((!soc_feature(unit, soc_feature_fcoe)) && 13950 (egr->flags2 & BCM_L3_FLAGS2_FCOE_ONLY)) { 13951 return (BCM_E_UNAVAIL); 13952 } 13953 13954 if ((!soc_feature(unit, soc_feature_nh_ifp_action_src_dst_mac_swap)) && 13955 (egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP)) { 13956 return (BCM_E_UNAVAIL); 13957 } 13958 13959 if ((!soc_feature(unit, soc_feature_th_nh_no_overlap_ecmp)) && 13960 (egr->flags2 & BCM_L3_FLAGS2_NO_ECMP_OVERLAP)) { 13961 return (BCM_E_UNAVAIL); 13962 } 13963 13964 #if defined(BCM_TOMAHAWK_SUPPORT) 13965 if ((egr->flags2 & BCM_L3_FLAGS2_NO_ECMP_OVERLAP) && 13966 (flags & BCM_L3_WITH_ID)) { 13967 return (BCM_E_PARAM); 13968 } 13969 #endif /* BCM_TOMAHAWK_SUPPORT */ 13970 13971 13972 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 13973 /* For IFP_ACTIONS view only */ 13974 if ((!(egr->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) && 13975 (egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP)) { 13976 return (BCM_E_PARAM); 13977 } 13978 13979 /* BCM_L3_FLAGS2_SRC_DST_MAC_SWAP must not be used together 13980 with BCM_L3_KEEP_SRCMAC or BCM_L3_KEEP_DSTMAC */ 13981 if ((egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP) && 13982 ((egr->flags & BCM_L3_KEEP_SRCMAC) || 13983 (egr->flags & BCM_L3_KEEP_DSTMAC))) { 13984 return (BCM_E_PARAM); 13985 } 13986 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 13987 13988 if ((!soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php)) && 13989 (egr->flags2 & BCM_L3_FLAGS2_MPLS_PHP)) { 13990 return (BCM_E_PARAM); 13991 } 13992 13993 /* Verify egress object range if BCM_L3_WITH_ID flag is set. */ 13994 if (flags & BCM_L3_WITH_ID) { 13995 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, *intf) && 13996 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, *intf)) { 13997 return (BCM_E_PARAM); 13998 } 13999 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, *intf)) { 14000 index = *intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 14001 } else { 14002 index = *intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 14003 } 14004 14005 #ifdef BCM_TOMAHAWK3_SUPPORT 14006 /* When Tomahawk3 Failover with fixed egress nh offset is enable, 14007 egr->failover_id is used internally to distinguish between user 14008 created primary intf (should be zero) and prot_intf created from 14009 bcm_th3_failover_egress_set (should be _FAILOVER_FIXED_NH_OFFSET_ON) */ 14010 if (FAILOVER_INFO(unit)->prot_offset > 0) { 14011 if (!_BCM_FAILOVER_ID_HAS_FIXED_NH_OFFSET(egr->failover_id) && 14012 (index >= FAILOVER_INFO(unit)->prot_offset)) { 14013 return BCM_E_PARAM; /* primary nh index invalid */ 14014 } 14015 /* Clear the bit after above check */ 14016 egr->failover_id &= ~_FAILOVER_FIXED_NH_OFFSET_ON; 14017 } 14018 #endif 14019 14020 } 14021 14022 bcm_l3_egress_t_init(&nh_info); 14023 /* Convert api egress object to hw next hop entry format. */ 14024 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_egress_to_nh_info(unit, egr, &nh_info)); 14025 14026 /* Convert api flags to shared table management flags. */ 14027 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_flags_to_shr(flags, &shr_flags)); 14028 14029 /* Store api flags within egr object flags */ 14030 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_flags_to_egr_obj(flags, &nh_info)); 14031 14032 /* Disable matching entry lookup. */ 14033 shr_flags |= _BCM_L3_SHR_MATCH_DISABLE; 14034 14035 if (!(egr->flags2 & BCM_L3_FLAGS2_UNDERLAY)) { 14036 #ifdef BCM_RIOT_SUPPORT 14037 if (BCMI_RIOT_IS_ENABLED(unit) 14038 && (_bcm_vp_is_vfi_type(unit, nh_info.port) || 14039 _bcm_vp_lag_member_is_vfi_type(unit, nh_info.port))) { 14040 14041 overlay_nh = TRUE; 14042 shr_flags |= _BCM_L3_SHR_OVERLAY_OBJECT; 14043 } 14044 #endif 14045 } 14046 14047 #if defined(BCM_TRIDENT_SUPPORT) 14048 /* Retrieve used-trunk-id in replace operation to reset the next hop store */ 14049 if (BCM_L3_REPLACE & flags) { 14050 rv = bcm_xgs3_l3_egress_get(unit, *intf, &egr_nh_old); 14051 if (BCM_SUCCESS(rv)) { 14052 p_egr_nh_old = &egr_nh_old; 14053 _bcm_xgs3_trunk_replace_check(unit, egr->flags, 14054 p_egr_nh_old, &tid_in_use); 14055 egress_obj_update = 1; 14056 } 14057 } 14058 14059 if ((soc_feature(unit, soc_feature_vxlan) || 14060 soc_feature(unit, soc_feature_flex_flow) || 14061 soc_feature(unit, soc_feature_trill) || 14062 soc_feature(unit, soc_feature_l2gre)) && (!overlay_nh)) { 14063 if (flags & BCM_L3_REPLACE) { 14064 /* Retrieve old trunk/module-id/port-id in replace operation 14065 * to reset the nhi mapping store 14066 */ 14067 BCM_IF_ERROR_RETURN( 14068 _bcm_xgs3_l3_egress_nhi_mapping_store(unit, egr->flags, 14069 *intf, &tgid, &modid, &portid)); 14070 } 14071 } 14072 #endif /* BCM_TRIDENT_SUPPORT */ 14073 14074 #if defined(BCM_TOMAHAWK_SUPPORT) 14075 if (soc_feature(unit, soc_feature_th_nh_no_overlap_ecmp) && 14076 (BCM_L3_FLAGS2_NO_ECMP_OVERLAP & egr->flags2)) { 14077 shr_flags |= _BCM_L3_SHR_NO_ECMP_OVERLAP; 14078 } 14079 14080 #endif /* BCM_TOMAHAWK_SUPPORT */ 14081 14082 #if defined(BCM_TRIDENT3_SUPPORT) 14083 if (soc_feature(unit, soc_feature_flex_flow) && 14084 nh_info.flow_handle != 0) { 14085 14086 uint32 entry_width; 14087 14088 BCM_IF_ERROR_RETURN( 14089 _bcm_l3_get_flex_entry_width(unit, &nh_info, &entry_width)); 14090 14091 if (entry_width == _BCM_DOUBLE_WIDE) { 14092 entry_flag = _BCM_L3_SHR_WIDE_FLEX_ENTRY; 14093 } 14094 } 14095 if (soc_feature(unit, soc_feature_large_scale_nat) && 14096 flags & BCM_L3_REPLACE && 14097 flags & BCM_L3_WITH_ID) { 14098 /* Release MAC_DA_PROFILE if used */ 14099 BCM_IF_ERROR_RETURN( 14100 bcm_td3_ipmc_egr_nh_mac_da_profile_entry_delete(unit, index)); 14101 } 14102 #endif /* BCM_TRIDENT3_SUPPORT */ 14103 14104 /* Create next hop entry. */ 14105 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_add(unit, shr_flags, &nh_info, &index)); 14106 14107 /* Return Egress object id 100K + nh_index for regular L3 egress objects */ 14108 /* Return BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + nh_index for L3 egress objects on VP */ 14109 #ifdef BCM_TRIUMPH2_SUPPORT 14110 if (((soc_feature(unit, soc_feature_wlan) || 14111 soc_feature(unit, soc_feature_virtual_port_routing)) && 14112 (egr->encap_id > 0 && egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))) || 14113 overlay_nh) { 14114 14115 *intf = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + index; 14116 } else 14117 #endif 14118 { 14119 *intf = BCM_XGS3_EGRESS_IDX_MIN(unit) + index; 14120 } 14121 14122 #if defined(BCM_TRIDENT_SUPPORT) 14123 if (soc_feature(unit, soc_feature_vxlan) || 14124 soc_feature(unit, soc_feature_flex_flow) || 14125 soc_feature(unit, soc_feature_trill) || 14126 soc_feature(unit, soc_feature_l2gre)) { 14127 /* Reset nhi mapping store */ 14128 L3_IF_ERROR_CLEANUP( 14129 _bcm_xgs3_l3_egress_nhi_mapping_reset( 14130 unit, index, tgid, modid, portid, flags)); 14131 } 14132 14133 if ( soc_feature(unit, soc_feature_trill) && 14134 (egr->flags & BCM_L3_TRILL_ONLY) && (!overlay_nh)){ 14135 /* Update used-trunk-id member-ports in replace operation to update the next hop store */ 14136 L3_IF_ERROR_CLEANUP 14137 (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index)); 14138 /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops */ 14139 if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) { 14140 L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index)); 14141 } 14142 /* Configure TRILL NextHop */ 14143 L3_IF_ERROR_CLEANUP_ELSE_RETURN(bcm_td_trill_egress_set(unit, index, flags)); 14144 } 14145 #endif /* BCM_TRIDENT_SUPPORT */ 14146 14147 #if defined(BCM_TRIUMPH3_SUPPORT) 14148 if (soc_feature(unit, soc_feature_l2gre) && 14149 (egr->flags & BCM_L3_L2GRE_ONLY) && (!overlay_nh)){ 14150 /* Update used-trunk-id member-ports in replace operation to update the next hop store */ 14151 L3_IF_ERROR_CLEANUP 14152 (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index)); 14153 /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops */ 14154 if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) { 14155 L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index)); 14156 } 14157 /* Configure L2GRE NextHop */ 14158 L3_IF_ERROR_CLEANUP_ELSE_RETURN(bcm_tr3_l2gre_egress_set(unit, index, flags)); 14159 } 14160 #endif /* BCM_TRIUMPH3_SUPPORT */ 14161 14162 #if defined(BCM_TRIDENT2_SUPPORT) 14163 if ( soc_feature(unit, soc_feature_vxlan) && 14164 (egr->flags & BCM_L3_VXLAN_ONLY) && (!overlay_nh)){ 14165 int vp = 0; 14166 int drop = 0; 14167 _bcm_vp_info_t vp_info; 14168 14169 if (BCM_GPORT_IS_VXLAN_PORT(egr->port)) { 14170 vp = BCM_GPORT_VXLAN_PORT_ID_GET(egr->port); 14171 L3_IF_ERROR_CLEANUP(_bcm_vp_info_get(unit, vp, &vp_info)); 14172 if (vp_info.vp_type != _bcmVpTypeVxlan) { 14173 L3_IF_ERROR_CLEANUP(BCM_E_PARAM); 14174 } 14175 } 14176 14177 if (egr->multicast_flags & BCM_L3_MULTICAST_L3_DROP) { 14178 drop = 1; 14179 } 14180 14181 /* Update used-trunk-id member-ports in replace operation to update the next hop store */ 14182 L3_IF_ERROR_CLEANUP 14183 (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index)); 14184 /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops */ 14185 if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) { 14186 L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index)); 14187 } 14188 /* Configure VXLAN NextHop */ 14189 L3_IF_ERROR_CLEANUP_ELSE_RETURN(bcm_td2_vxlan_next_hop_set(unit, index, flags, vp, drop)); 14190 } 14191 #endif /* BCM_TRIDENT2_SUPPORT */ 14192 14193 #if defined(BCM_GREYHOUND2_SUPPORT) 14194 if (soc_feature(unit, soc_feature_vxlan_lite) && 14195 (egr->flags & BCM_L3_VXLAN_ONLY)) { 14196 if (flags & BCM_L3_REPLACE) { 14197 BCM_IF_ERROR_RETURN(bcmi_gh2_vxlan_egress_entry_mac_replace( 14198 unit, index, egr)); 14199 } 14200 if (!overlay_nh) { 14201 L3_IF_ERROR_CLEANUP_ELSE_RETURN(err_code); 14202 } 14203 } 14204 #endif /* BCM_GREYHOUND2_SUPPORT */ 14205 14206 #if defined(BCM_TRIDENT3_SUPPORT) 14207 if ((soc_feature(unit, soc_feature_flex_flow)) && 14208 (egr->flow_handle != 0) && 14209 (egr->flags2 & BCM_L3_MPLS_GRE_LABEL)) { 14210 14211 BCM_IF_ERROR_RETURN(_bcm_td3_mpls_gre_label_add(unit, egr, index, flags)); 14212 } 14213 14214 if (soc_feature(unit, soc_feature_flex_flow) && 14215 (egr->flags2 & BCM_L3_FLOW_ONLY) && (!overlay_nh)){ 14216 int vp = 0; 14217 int drop = 0; 14218 _bcm_vp_info_t vp_info; 14219 14220 if ((egr->encap_id > 0) && (egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))) { 14221 vp = egr->encap_id; 14222 } 14223 14224 if (BCM_GPORT_IS_FLOW_PORT(egr->port)) { 14225 vp = BCM_GPORT_FLOW_PORT_ID_GET(egr->port); 14226 } 14227 14228 if (vp) { 14229 L3_IF_ERROR_CLEANUP(_bcm_vp_info_get(unit, vp, &vp_info)); 14230 if (vp_info.vp_type != _bcmVpTypeFlow) { 14231 L3_IF_ERROR_CLEANUP(BCM_E_PARAM); 14232 } 14233 } 14234 14235 if (egr->multicast_flags & BCM_L3_MULTICAST_L3_DROP) { 14236 drop = 1; 14237 } 14238 14239 /* Update used-trunk-id member-ports in replace operation to update the next hop store */ 14240 L3_IF_ERROR_CLEANUP 14241 (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index)); 14242 /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops */ 14243 if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) { 14244 L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index)); 14245 } 14246 /* Configure FLOW NextHop */ 14247 L3_IF_ERROR_CLEANUP_ELSE_RETURN(_bcm_td3_flow_next_hop_set(unit, index, flags, vp, drop)); 14248 } 14249 #endif /* BCM_TRIDENT3_SUPPORT */ 14250 14251 #ifdef BCM_TRIDENT_SUPPORT 14252 if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 14253 (nh_info.flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) { 14254 egr_l3_next_hop_entry_t egr_nh; 14255 uint32 tag_buffer = 0; 14256 uint8 tag_action = 0; 14257 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 14258 MEM_BLOCK_ALL, index, &egr_nh)); 14259 #ifdef BCM_TOMAHAWK3_SUPPORT 14260 if (SOC_IS_TOMAHAWK3(unit)) { 14261 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14262 nh_entry_type_field[unit], 2); 14263 } else 14264 #endif 14265 { 14266 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14267 nh_entry_type_field[unit], 6); 14268 } 14269 if (SOC_IS_TD2_TT2(unit)) { 14270 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14271 IFP_ACTIONS__L3_UC_SA_DISABLEf, 14272 ((nh_info.flags & BCM_L3_KEEP_SRCMAC)!=0)); 14273 if (!SOC_IS_TOMAHAWK3(unit)) { 14274 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14275 L3__L3_UC_SA_DISABLEf, 0); 14276 } 14277 } 14278 14279 if (egr->vntag_action == bcmVnTagActionChange) { 14280 tag_action = 1; 14281 tag_buffer = (((uint32)egr->vntag.direction & 0x1) << 31) | 14282 (((uint32)egr->vntag.pointer & 0x1) << 30) | 14283 (((uint32)egr->vntag.dst_vif & 0x3fff) << 16)| 14284 (((uint32)egr->vntag.loop & 0x1) << 15) | 14285 ((uint32)egr->vntag.src_vif & 0xfff); 14286 } else if (egr->etag_action == bcmETagActionChange) { 14287 tag_action = 2; 14288 tag_buffer = (((uint32)egr->etag.pcp & 0x7) << 29) | 14289 (((uint32)egr->etag.de & 0x1) << 28) | 14290 (((uint32)egr->etag.src_vid & 0xfff) << 16) | 14291 ((uint32)egr->etag.vid & 0x3fff); 14292 } else if (egr->vntag_action == bcmVnTagActionDelete) { 14293 tag_action = 3; 14294 tag_buffer = 0; 14295 } else if (egr->etag_action == bcmETagActionDelete) { 14296 tag_action = 3; 14297 tag_buffer = ~0; 14298 } 14299 14300 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, 14301 IFP_ACTIONS__VNTAGf)) { 14302 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14303 IFP_ACTIONS__VNTAGf, tag_buffer); 14304 } 14305 14306 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, 14307 IFP_ACTIONS__VNTAG_ACTIONf)) { 14308 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14309 IFP_ACTIONS__VNTAG_ACTIONf, tag_action); 14310 } 14311 14312 BCM_IF_ERROR_RETURN 14313 (soc_mem_write(unit, EGR_L3_NEXT_HOPm, 14314 MEM_BLOCK_ALL, index, &egr_nh)); 14315 } 14316 #endif 14317 14318 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 14319 if (soc_feature(unit, soc_feature_nh_ifp_action_src_dst_mac_swap) && 14320 (nh_info.flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP)) { 14321 egr_l3_next_hop_entry_t egr_nh; 14322 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 14323 MEM_BLOCK_ALL, index, &egr_nh)); 14324 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14325 IFP_ACTIONS__SWAP_MAC_DA_SAf, 1); 14326 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14327 IFP_ACTIONS__L3_UC_SA_DISABLEf, 1); 14328 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14329 IFP_ACTIONS__L3_UC_DA_DISABLEf, 1); 14330 BCM_IF_ERROR_RETURN 14331 (soc_mem_write(unit, EGR_L3_NEXT_HOPm, 14332 MEM_BLOCK_ALL, index, &egr_nh)); 14333 } 14334 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 14335 14336 #if defined(BCM_TRIUMPH2_SUPPORT) 14337 if (soc_feature(unit, soc_feature_failover)) { 14338 if (BCM_SUCCESS(_bcm_esw_failover_egr_check (unit, egr))) { 14339 if (_BCM_MULTICAST_IS_SET(egr->failover_mc_group)) { 14340 protection_flags |= _BCM_FAILOVER_1_PLUS_PROTECTION; 14341 } 14342 L3_IF_ERROR_CLEANUP( 14343 _bcm_esw_failover_prot_nhi_create(unit, protection_flags, index, 14344 (uint32) (egr->failover_if_id - BCM_XGS3_EGRESS_IDX_MIN(unit)), 14345 egr->failover_mc_group, egr->failover_id)); 14346 } else if (flags & BCM_L3_REPLACE) { 14347 /* Clean up prot_nhi if egress object is replaced by new one which 14348 * has no failover information. 14349 */ 14350 if ((0 == egr->failover_id) && (0 == egr->failover_if_id)) { 14351 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_KATANA2(unit)) { 14352 if (0 == egr->failover_mc_group) { 14353 err_code = 14354 _bcm_esw_failover_prot_nhi_cleanup(unit, index); 14355 } 14356 } else { 14357 err_code = 14358 _bcm_esw_failover_prot_nhi_cleanup(unit, index); 14359 } 14360 if ((err_code != BCM_E_NOT_FOUND) && 14361 (err_code != BCM_E_NONE)) { 14362 goto cleanup; 14363 } 14364 } 14365 } 14366 } 14367 #endif /* BCM_TRIUMPH2_SUPPORT */ 14368 14369 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) 14370 if ((SOC_IS_TR_VL(unit)) && (soc_feature(unit, soc_feature_mpls))) { 14371 /* 14372 * BCM_L3_ROUTE_LABEL is an egress object flag. There was a 14373 * bug in the code wherein bcm_l3_egress_create was looking 14374 * for BCM_L3_ROUTE_LABEL in "flags" and get/destroy functions 14375 * were looking in "egr->flags". This was causing MPLS actions 14376 * to be modified during replace. 14377 * Changing this check to egr->flags might affect customers who 14378 * are passing BCM_L3_ROUTE_LABEL in "flags". 14379 * Therefore, modifying code to check for BCM_L3_ROUTE_LABEL 14380 * in flags as well as egr->flags. 14381 */ 14382 if ((flags & BCM_L3_ROUTE_LABEL) || 14383 (egr->flags & BCM_L3_ROUTE_LABEL)) { 14384 if (egr->mpls_label != BCM_MPLS_LABEL_INVALID) { 14385 /* Case of PUSH Inner-Label */ 14386 L3_IF_ERROR_CLEANUP( 14387 bcm_tr_mpls_get_entry_type(unit, index, &entry_type)); 14388 if (entry_type == 0) { 14389 L3_IF_ERROR_CLEANUP( 14390 bcm_tr_mpls_egress_entry_modify(unit, index, 0, 1)); 14391 } 14392 #if defined(BCM_TOMAHAWK3_SUPPORT) 14393 if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) { 14394 L3_IF_ERROR_CLEANUP( 14395 bcm_th3_mpls_l3_label_add(unit, egr, index, flags)); 14396 } else 14397 #endif 14398 { 14399 L3_IF_ERROR_CLEANUP( 14400 bcm_tr_mpls_l3_label_add (unit, egr, index, flags)); 14401 } 14402 } 14403 #if defined(BCM_TRIUMPH2_SUPPORT) 14404 if (soc_feature(unit, soc_feature_mpls_failover)) { 14405 if ((protection_flags & _BCM_FAILOVER_1_PLUS_PROTECTION) && 14406 soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) { 14407 egr_ipmc_entry_t egr_ipmc_entry; 14408 int l3mc_index = _BCM_MULTICAST_ID_GET(egr->failover_mc_group); 14409 L3_IF_ERROR_CLEANUP(soc_mem_read(unit, EGR_IPMCm, 14410 MEM_BLOCK_ANY, l3mc_index, 14411 &egr_ipmc_entry)); 14412 old_l3_payload = soc_mem_field32_get(unit, EGR_IPMCm, &egr_ipmc_entry, 14413 L3_PAYLOADf); 14414 soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 14415 L3_PAYLOADf,1); 14416 L3_IF_ERROR_CLEANUP(soc_mem_write(unit, EGR_IPMCm, 14417 MEM_BLOCK_ALL, 14418 l3mc_index, 14419 &egr_ipmc_entry)); 14420 } 14421 } 14422 #endif 14423 } else if (!((flags & BCM_L3_ROUTE_LABEL) || 14424 (egr->flags & BCM_L3_ROUTE_LABEL))) { 14425 if ((egr->mpls_label != BCM_MPLS_LABEL_INVALID) || 14426 _BCM_MPLS_EGRESS_LABEL_PRESERVE(unit, egr->mpls_flags)) { 14427 /* Case of SWAP-OUT Label */ 14428 L3_IF_ERROR_CLEANUP( 14429 bcm_tr_mpls_get_entry_type(unit, index, &entry_type)); 14430 if (entry_type == 0) { 14431 L3_IF_ERROR_CLEANUP( 14432 bcm_tr_mpls_egress_entry_modify(unit, index, 0, 1)); 14433 } 14434 #if defined(BCM_TOMAHAWK3_SUPPORT) 14435 if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) { 14436 L3_IF_ERROR_CLEANUP( 14437 bcm_th3_mpls_swap_nh_info_add (unit, egr, index, flags)); 14438 } else 14439 #endif 14440 { 14441 14442 L3_IF_ERROR_CLEANUP( 14443 bcm_tr_mpls_swap_nh_info_add (unit, egr, index, flags)); 14444 } 14445 } else if (egr->mpls_label == BCM_MPLS_LABEL_INVALID ) { 14446 /* Case of Egress into MPLS Tunnel */ 14447 L3_IF_ERROR_CLEANUP( 14448 bcm_tr_mpls_swap_nh_info_delete(unit, index)); 14449 if (BCM_SUCCESS(bcm_tr_mpls_tunnel_intf_valid (unit, index))) { 14450 L3_IF_ERROR_CLEANUP( 14451 bcm_tr_mpls_get_entry_type(unit, index, &entry_type)); 14452 if (entry_type == 0) { 14453 L3_IF_ERROR_CLEANUP( 14454 bcm_tr_mpls_egress_entry_modify(unit, index, 14455 0, 1)); 14456 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT) 14457 if (soc_feature(unit, soc_feature_mpls_nh_ttl_control)) { 14458 if (egr->flags & BCM_L3_KEEP_TTL) { 14459 egr_l3_next_hop_entry_t egr_nh; 14460 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 14461 MEM_BLOCK_ALL, index, &egr_nh)); 14462 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14463 MPLS__DISABLE_TTL_DECREMENTf, 1); 14464 BCM_IF_ERROR_RETURN 14465 (soc_mem_write(unit, EGR_L3_NEXT_HOPm, 14466 MEM_BLOCK_ALL, index, &egr_nh)); 14467 } 14468 } 14469 #endif 14470 #if defined(INCLUDE_XFLOW_MACSEC) 14471 if (soc_feature(unit, soc_feature_xflow_macsec) && 14472 ((egr->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) || 14473 (egr->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) { 14474 egr_l3_next_hop_entry_t egr_nh; 14475 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 14476 MEM_BLOCK_ALL, index, &egr_nh)); 14477 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 14478 &egr_nh, MPLS__MACSEC_ENCRYPTf, 0); 14479 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 14480 &egr_nh, MPLS__MACSEC_DECRYPTf, 0); 14481 if (egr->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) { 14482 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 14483 &egr_nh, MPLS__MACSEC_ENCRYPTf, 0x1); 14484 } else { 14485 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 14486 &egr_nh, MPLS__MACSEC_DECRYPTf, 0x1); 14487 } 14488 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 14489 &egr_nh, MPLS__HG_MC_DST_MODIDf, egr->module); 14490 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 14491 &egr_nh, MPLS__HG_MC_DST_PORT_NUMf, egr->port); 14492 BCM_IF_ERROR_RETURN 14493 (soc_mem_write(unit, EGR_L3_NEXT_HOPm, 14494 MEM_BLOCK_ALL, index, &egr_nh)); 14495 } 14496 #endif 14497 } 14498 } else { 14499 L3_IF_ERROR_CLEANUP( 14500 bcm_tr_mpls_get_entry_type(unit, index, &entry_type)); 14501 if (entry_type == 1) { 14502 L3_IF_ERROR_CLEANUP( 14503 bcm_tr_mpls_egress_entry_modify(unit, index, 0, entry_type)); 14504 } 14505 } 14506 #if defined(BCM_TRIUMPH2_SUPPORT) 14507 if (soc_feature(unit, soc_feature_mpls_failover)) { 14508 if (soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) { 14509 egr_ipmc_entry_t egr_ipmc_entry; 14510 int l3mc_index = _BCM_MULTICAST_ID_GET(egr->failover_mc_group); 14511 L3_IF_ERROR_CLEANUP(soc_mem_read(unit, EGR_IPMCm, 14512 MEM_BLOCK_ANY, l3mc_index, 14513 &egr_ipmc_entry)); 14514 old_l3_payload = soc_mem_field32_get(unit, EGR_IPMCm, &egr_ipmc_entry, 14515 L3_PAYLOADf); 14516 soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 14517 L3_PAYLOADf,0); 14518 L3_IF_ERROR_CLEANUP(soc_mem_write(unit, EGR_IPMCm, 14519 MEM_BLOCK_ALL, 14520 l3mc_index, 14521 &egr_ipmc_entry)); 14522 } 14523 } 14524 #endif 14525 } 14526 } 14527 if (flags & BCM_L3_REPLACE) { 14528 bcm_tr_mpls_egress_entry_mac_replace(unit, index, egr); 14529 if (!soc_feature(unit, soc_feature_th3_style_simple_mpls)) { 14530 /* Update the VP NextHops -- For L2 MPLS and L3 SWAP */ 14531 L3_IF_ERROR_CLEANUP(bcm_tr_mpls_update_vp_nh (unit, *intf)); 14532 } 14533 } 14534 } 14535 #endif /* BCM_TRX_SUPPORT && BCM_MPLS_SUPPORT */ 14536 14537 #ifdef BCM_TRIDENT2_SUPPORT 14538 if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) && 14539 (nh_info.flags2 & BCM_L3_FLAGS2_MPLS_PHP)) { 14540 L3_IF_ERROR_CLEANUP( 14541 bcm_tr_mpls_get_entry_type(unit, index, &entry_type)); 14542 if (entry_type == 0) { 14543 L3_IF_ERROR_CLEANUP( 14544 bcm_tr_mpls_egress_entry_modify(unit, index, 0, 1)); 14545 } 14546 } 14547 #endif /* BCM_TRIDENT2_SUPPORT */ 14548 14549 #ifdef BCM_TRIDENT2_SUPPORT 14550 if (soc_feature(unit, soc_feature_fcoe) && 14551 (nh_info.flags2 & BCM_L3_FLAGS2_FCOE_ONLY)) { 14552 egr_l3_next_hop_entry_t egr_nh; 14553 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 14554 MEM_BLOCK_ALL, index, &egr_nh)); 14555 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 14556 nh_entry_type_field[unit], 8); 14557 BCM_IF_ERROR_RETURN 14558 (soc_mem_write(unit, EGR_L3_NEXT_HOPm, 14559 MEM_BLOCK_ALL, index, &egr_nh)); 14560 } 14561 #endif 14562 14563 #ifdef BCM_TRIUMPH3_SUPPORT 14564 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 14565 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 14566 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 14567 if (!BCM_GPORT_IS_SET(egr->port)) { 14568 L3_IF_ERROR_CLEANUP 14569 (bcm_th2_l3_egress_dlb_attr_set(unit, index, 14570 egr, p_egr_nh_old)); 14571 } 14572 } else 14573 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 14574 { 14575 L3_IF_ERROR_CLEANUP 14576 (bcm_tr3_l3_egress_dlb_attr_set(unit, index, egr)); 14577 } 14578 } else 14579 #endif /* BCM_TRIUMPH3_SUPPORT */ 14580 { 14581 if ((egr->dynamic_scaling_factor != 14582 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) || 14583 (egr->dynamic_load_weight != 14584 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID) || 14585 (egr->dynamic_queue_size_weight != 14586 BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID)) { 14587 err_code = BCM_E_UNAVAIL; 14588 goto cleanup; 14589 } 14590 } 14591 14592 return (BCM_E_NONE); 14593 cleanup: 14594 if (!egress_obj_update) { 14595 (void) bcm_xgs3_nh_del(unit, entry_flag, index); 14596 } 14597 #if defined(BCM_TRIUMPH2_SUPPORT) 14598 if (soc_feature(unit, soc_feature_mpls_failover)) { 14599 if ((old_l3_payload != 0xffffffff) && 14600 soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) { 14601 egr_ipmc_entry_t egr_ipmc_entry; 14602 int l3mc_index = _BCM_MULTICAST_ID_GET(egr->failover_mc_group); 14603 (void) soc_mem_read(unit, EGR_IPMCm, MEM_BLOCK_ANY, l3mc_index, 14604 &egr_ipmc_entry); 14605 soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 14606 L3_PAYLOADf,old_l3_payload); 14607 (void) soc_mem_write(unit, EGR_IPMCm, MEM_BLOCK_ALL, l3mc_index, 14608 &egr_ipmc_entry); 14609 } 14610 } 14611 #endif 14612 return err_code; 14613 } 14614 14615 /* 14616 * Function: 14617 * bcm_xgs3_l3_egress_destroy 14618 * Purpose: 14619 * Destroy an Egress forwarding object. 14620 * Parameters: 14621 * unit - (IN) bcm device. 14622 * intf - (IN) L3 interface id pointing to Egress object. 14623 * Returns: 14624 * BCM_E_XXX 14625 */ 14626 int 14627 bcm_xgs3_l3_egress_destroy(int unit, bcm_if_t intf) 14628 { 14629 bcm_l3_egress_t egr; /* Next hop info. */ 14630 int nh_idx; /* Next hop index. */ 14631 int rv; /* Operation return status. */ 14632 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) 14633 uint32 entry_type=0; /* Next Hop Entry_type */ 14634 #endif /* BCM_TRIUMPH_SUPPORT && BCM_MPLS_SUPPORT */ 14635 uint32 entry_flag=0; 14636 14637 /* Make sure module was initialized. */ 14638 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 14639 return (BCM_E_INIT); 14640 } 14641 14642 /* Check l3 switching mode. */ 14643 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 14644 return (BCM_E_DISABLED); 14645 } 14646 14647 /* Input parameters check. */ 14648 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 14649 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 14650 return (BCM_E_PARAM); 14651 } 14652 14653 /* Calculate next hop index. */ 14654 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 14655 nh_idx = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 14656 } else { 14657 nh_idx = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 14658 } 14659 14660 /* If entry is used by hosts/routes or ecmp objects - reject deletion */ 14661 if(1 < BCM_XGS3_L3_ENT_REF_CNT 14662 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_idx)) { 14663 return (BCM_E_BUSY); 14664 } 14665 14666 rv = bcm_xgs3_l3_egress_get(unit, intf, &egr); 14667 BCM_IF_ERROR_RETURN(rv); 14668 14669 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) 14670 if ((SOC_IS_TR_VL(unit)) && (soc_feature(unit, soc_feature_mpls))) { 14671 /* coverity[uninit_use] */ 14672 BCM_IF_ERROR_RETURN(bcm_tr_mpls_get_entry_type(unit, nh_idx, &entry_type)); 14673 if (entry_type == 1) { 14674 if (egr.flags & BCM_L3_ROUTE_LABEL) { 14675 if (egr.mpls_label != BCM_MPLS_LABEL_INVALID) { 14676 rv = bcm_tr_mpls_l3_label_delete (unit, nh_idx); 14677 BCM_IF_ERROR_RETURN(rv); 14678 } 14679 } else if (!(egr.flags & BCM_L3_ROUTE_LABEL)) { 14680 if (egr.mpls_label != BCM_MPLS_LABEL_INVALID) { 14681 rv = bcm_tr_mpls_swap_nh_info_delete (unit, nh_idx); 14682 BCM_IF_ERROR_RETURN(rv); 14683 rv = bcm_tr_mpls_egress_entry_modify(unit, nh_idx, 0, 0); 14684 BCM_IF_ERROR_RETURN(rv); 14685 } else if (egr.mpls_label == BCM_MPLS_LABEL_INVALID) { 14686 rv = bcm_tr_mpls_egress_entry_modify(unit, nh_idx, 0, 0); 14687 BCM_IF_ERROR_RETURN(rv); 14688 } 14689 } 14690 } 14691 } 14692 #endif /* BCM_TRIUMPH_SUPPORT && BCM_MPLS_SUPPORT */ 14693 14694 #if defined(BCM_TRIDENT3_SUPPORT) 14695 if ((soc_feature(unit, soc_feature_flex_flow)) && 14696 (egr.flow_handle != 0) && 14697 (egr.mpls_label != BCM_MPLS_LABEL_INVALID)) { 14698 14699 soc_mem_t view_id; 14700 14701 BCM_IF_ERROR_RETURN( 14702 soc_flow_db_ffo_to_mem_view_id_get(unit, 14703 egr.flow_handle, 14704 egr.flow_option_handle, 14705 SOC_FLOW_DB_FUNC_EGRESS_OBJ_ID, 14706 (uint32 *)&view_id)); 14707 14708 rv = _bcm_td3_mpls_gre_label_delete(unit, nh_idx, view_id); 14709 14710 BCM_IF_ERROR_RETURN(rv); 14711 } 14712 #endif 14713 14714 #if defined(BCM_TRIUMPH2_SUPPORT) 14715 if (soc_feature(unit, soc_feature_failover)) { 14716 if (BCM_SUCCESS(_bcm_esw_failover_egr_check(unit, &egr))) { 14717 rv = _bcm_esw_failover_prot_nhi_cleanup(unit, nh_idx); 14718 if ( (rv != BCM_E_NOT_FOUND) && (rv != BCM_E_NONE) ) { 14719 return rv; 14720 } 14721 } 14722 } 14723 #endif /* BCM_TRIUMPH2_SUPPORT */ 14724 14725 #ifdef BCM_TRIDENT2_SUPPORT 14726 if (soc_feature(unit, soc_feature_vxlan)) { 14727 if(egr.flags & BCM_L3_VXLAN_ONLY) { 14728 /* Reset VXLAN Egress NextHop */ 14729 BCM_IF_ERROR_RETURN( 14730 bcm_td2_vxlan_egress_reset(unit, nh_idx)); 14731 /* Reset Trunk to NextHop Index Store entry */ 14732 if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) { 14733 BCM_IF_ERROR_RETURN( 14734 _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx)); 14735 } 14736 } 14737 } 14738 #endif /* BCM_TRIDENT2_SUPPORT */ 14739 14740 #ifdef BCM_TRIDENT3_SUPPORT 14741 if (soc_feature(unit, soc_feature_flex_flow)) { 14742 uint32 entry_width; 14743 14744 if(egr.flags2 & BCM_L3_FLOW_ONLY) { 14745 /* Reset FLOW Egress NextHop */ 14746 BCM_IF_ERROR_RETURN( 14747 _bcm_td3_flow_egress_reset(unit, nh_idx)); 14748 /* Reset Trunk to NextHop Index Store entry */ 14749 if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) { 14750 BCM_IF_ERROR_RETURN( 14751 _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx)); 14752 } 14753 } 14754 14755 if (egr.flow_handle != 0) { 14756 BCM_IF_ERROR_RETURN( 14757 _bcm_l3_get_flex_entry_width(unit, &egr, &entry_width)); 14758 14759 if (entry_width == _BCM_DOUBLE_WIDE) { 14760 entry_flag = _BCM_L3_SHR_WIDE_FLEX_ENTRY; 14761 } 14762 } 14763 } 14764 #endif /* BCM_TRIDENT3_SUPPORT */ 14765 14766 #ifdef BCM_TRIUMPH3_SUPPORT 14767 if (soc_feature(unit, soc_feature_l2gre)) { 14768 /* Reset L2GRE Egress NextHop */ 14769 if(egr.flags & BCM_L3_L2GRE_ONLY) { 14770 BCM_IF_ERROR_RETURN( 14771 bcm_tr3_l2gre_egress_reset(unit, nh_idx)); 14772 /* Reset Trunk to NextHop Index Store entry */ 14773 if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) { 14774 BCM_IF_ERROR_RETURN( 14775 _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx)); 14776 } 14777 } 14778 } 14779 #endif /* BCM_TRIUMPH3_SUPPORT */ 14780 14781 14782 #ifdef BCM_TRIDENT_SUPPORT 14783 if (soc_feature(unit, soc_feature_trill)) { 14784 /* Reset TRILL Egress NextHop */ 14785 if(egr.flags & BCM_L3_TRILL_ONLY) { 14786 BCM_IF_ERROR_RETURN( 14787 bcm_td_trill_egress_reset(unit, nh_idx)); 14788 /* Reset Trunk to NextHop Index Store entry */ 14789 if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) { 14790 BCM_IF_ERROR_RETURN( 14791 _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx)); 14792 } 14793 } 14794 } 14795 #endif /* BCM_TRIDENT_SUPPORT */ 14796 14797 14798 #ifdef BCM_TRIUMPH3_SUPPORT 14799 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 14800 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 14801 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 14802 if (!BCM_GPORT_IS_SET(egr.port)) { 14803 BCM_IF_ERROR_RETURN 14804 (bcm_th2_l3_egress_dlb_attr_destroy(unit, nh_idx, &egr)); 14805 } 14806 } else 14807 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 14808 { 14809 BCM_IF_ERROR_RETURN 14810 (bcm_tr3_l3_egress_dlb_attr_destroy(unit, nh_idx)); 14811 } 14812 } 14813 #endif /* BCM_TRIUMPH3_SUPPORT */ 14814 14815 #ifdef BCM_KATANA_SUPPORT 14816 if (soc_feature(unit, soc_feature_extended_queueing) && 14817 (egr.flags & BCM_L3_QUEUE_MAP)) { 14818 14819 BCM_IF_ERROR_RETURN( 14820 bcmi_kt_extended_queue_config_destroy(unit, nh_idx)); 14821 } 14822 #endif /*BCM_KATANA_SUPPORT*/ 14823 #if defined(BCM_TRIUMPH2_SUPPORT) 14824 if (soc_feature(unit, soc_feature_mpls_failover)) { 14825 if ((egr.flags & BCM_L3_ROUTE_LABEL) && 14826 (egr.mpls_label != BCM_MPLS_LABEL_INVALID) && 14827 _BCM_MULTICAST_IS_SET(egr.failover_mc_group) && 14828 soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) { 14829 egr_ipmc_entry_t egr_ipmc_entry; 14830 int l3mc_index = _BCM_MULTICAST_ID_GET(egr.failover_mc_group); 14831 rv = soc_mem_read(unit, EGR_IPMCm, MEM_BLOCK_ANY, l3mc_index, 14832 &egr_ipmc_entry); 14833 BCM_IF_ERROR_RETURN(rv); 14834 soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 14835 L3_PAYLOADf,0); 14836 rv = soc_mem_write(unit, EGR_IPMCm, MEM_BLOCK_ALL, l3mc_index, 14837 &egr_ipmc_entry); 14838 BCM_IF_ERROR_RETURN(rv); 14839 } 14840 } 14841 #endif 14842 /* Delete next hop entry. */ 14843 rv = bcm_xgs3_nh_del(unit, entry_flag, nh_idx); 14844 return (rv); 14845 } 14846 14847 /* 14848 * Function: 14849 * bcm_xgs3_l3_egress_get 14850 * Purpose: 14851 * Get an Egress forwarding object. 14852 * Parameters: 14853 * unit - (IN) bcm device. 14854 * intf - (IN) L3 interface id pointing to Egress object. 14855 * egr - (OUT) Egress forwarding destination. 14856 * Returns: 14857 * BCM_E_XXX 14858 */ 14859 int 14860 bcm_xgs3_l3_egress_get(int unit, bcm_if_t intf, bcm_l3_egress_t *egr) 14861 { 14862 int offset; 14863 14864 /* Make sure module was initialized. */ 14865 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 14866 return (BCM_E_INIT); 14867 } 14868 14869 /* Check l3 switching mode. */ 14870 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 14871 return (BCM_E_DISABLED); 14872 } 14873 14874 /* Input parameters check. */ 14875 if ((NULL == egr) || (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) && 14876 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf))) { 14877 return (BCM_E_PARAM); 14878 } 14879 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 14880 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 14881 } else { 14882 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 14883 } 14884 /* Fill next hop entry info. */ 14885 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, (intf - offset), egr)); 14886 14887 #ifdef BCM_TRIUMPH3_SUPPORT 14888 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 14889 /* Get dynamic_scaling_factor and dynamic_load_weight */ 14890 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 14891 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 14892 if (!BCM_GPORT_IS_SET(egr->port)) { 14893 BCM_IF_ERROR_RETURN 14894 (bcm_th2_l3_egress_dlb_attr_get(unit, (intf - offset), egr)); 14895 } 14896 } else 14897 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 14898 { 14899 BCM_IF_ERROR_RETURN 14900 (bcm_tr3_l3_egress_dlb_attr_get(unit, (intf - offset), egr)); 14901 } 14902 } else 14903 #endif /* BCM_TRIUMPH3_SUPPORT */ 14904 { 14905 egr->dynamic_scaling_factor = BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID; 14906 egr->dynamic_load_weight = BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID; 14907 egr->dynamic_queue_size_weight = BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID; 14908 } 14909 14910 return BCM_E_NONE; 14911 } 14912 14913 /* 14914 * Function: 14915 * bcm_xgs3_l3_egress_find 14916 * Purpose: 14917 * Find an egress forwarding object. 14918 * Parameters: 14919 * unit - (IN) bcm device. 14920 * egr - (IN) Egress object properties to match. 14921 * intf - (OUT) L3 interface id pointing to egress object 14922 * if found. 14923 * Returns: 14924 * BCM_E_XXX 14925 */ 14926 int 14927 bcm_xgs3_l3_egress_find(int unit, bcm_l3_egress_t *egr, 14928 bcm_if_t *intf) 14929 { 14930 _bcm_l3_tbl_op_t data; /* Operation data. */ 14931 bcm_l3_egress_t nh_info; /* Next hop structure. */ 14932 int nh_idx; 14933 int riot_vp_egress_obj = 0; 14934 #ifdef BCM_RIOT_SUPPORT 14935 _bcm_l3_bookkeeping_t *l3_bk; 14936 #endif 14937 14938 14939 14940 /* Make sure module was initialized. */ 14941 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 14942 return (BCM_E_INIT); 14943 } 14944 14945 /* Check l3 switching mode. */ 14946 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 14947 return (BCM_E_DISABLED); 14948 } 14949 14950 /* Input parameters check. */ 14951 if ((NULL == egr) || (NULL == intf)) { 14952 return (BCM_E_PARAM); 14953 } 14954 14955 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 14956 if (!soc_feature(unit, soc_feature_flex_flow) && 14957 (egr->flags2 & BCM_L3_MPLS_GRE_LABEL)) { 14958 return (BCM_E_PARAM); 14959 } 14960 #endif 14961 14962 /* Convert api egress object to hw next hop entry format. */ 14963 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_egress_to_nh_info(unit, egr, &nh_info)); 14964 14965 /* Convert API next hop entry to HW space format. */ 14966 BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_info)); 14967 14968 14969 /* Initialization */ 14970 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 14971 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 14972 data.width = _BCM_SINGLE_WIDE; 14973 data.entry_buffer = (void *)&nh_info; 14974 data.hash_func = _bcm_xgs3_nh_hash_calc; 14975 data.cmp_func = _bcm_xgs3_nh_ent_cmp; 14976 14977 /* Find next hop entry. */ 14978 BCM_IF_ERROR_RETURN (_bcm_xgs3_tbl_match(unit, &data)); 14979 nh_idx = data.entry_index; 14980 14981 14982 #ifdef BCM_RIOT_SUPPORT 14983 l3_bk = &_bcm_l3_bk_info[unit]; 14984 14985 if (BCMI_RIOT_IS_ENABLED(unit)) { 14986 if (l3_bk->l3_intf_overlay_alloc_mode > 0) { 14987 if (nh_idx > l3_bk->l3_nh_overlay_entries) { 14988 riot_vp_egress_obj = 1; 14989 } 14990 } else { 14991 if (nh_idx <= l3_bk->l3_nh_overlay_entries) { 14992 riot_vp_egress_obj = 1; 14993 } 14994 } 14995 } 14996 #endif 14997 14998 /* Return Egress object id offset + nh_index */ 14999 /* Offset depends on whether it is a regular next hop residing on 15000 * a physical port, or a next hop residing on a VP. 15001 */ 15002 if ((nh_info.encap_id > 0 && 15003 nh_info.encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) || 15004 riot_vp_egress_obj) { 15005 /* encap_id contains a vp value */ 15006 *intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15007 } else { 15008 *intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit); 15009 } 15010 15011 return (BCM_E_NONE); 15012 } 15013 15014 /* 15015 * Function: 15016 * _bcm_xgs3_nh_traverse_cb 15017 * Purpose: 15018 * Call user callback for valid next hop entries. 15019 * Parameters: 15020 * unit - (IN)SOC unit number. 15021 * pattern - (IN)Match pattern (interface id & negate). 15022 * data1 - (IN)Route info. 15023 * data2 - (IN)Next hop info. 15024 * cmp_result- (OUT)Comparison result. 15025 * Returns: 15026 * BCM_E_XXX 15027 */ 15028 STATIC int 15029 _bcm_xgs3_nh_traverse_cb(int unit, void *pattern, void *data1, 15030 void *data2, int *cmp_result) 15031 { 15032 _bcm_l3_trvrs_data_t *trv_data; /* Travers data. */ 15033 bcm_l3_egress_t *egr; /* Egress object. */ 15034 int nh_idx; /* Next hop index. */ 15035 int rv = BCM_E_NONE; 15036 15037 /* Cast input parameters. */ 15038 trv_data = (_bcm_l3_trvrs_data_t *) pattern; 15039 egr = (bcm_l3_egress_t *) data1; 15040 nh_idx = *(int *)data2; 15041 15042 #ifdef BCM_TRX_SUPPORT 15043 if (egr->encap_id > 0 && egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) { 15044 /* encap_id contains a virtual port value */ 15045 int vp; 15046 15047 vp = egr->encap_id; 15048 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 15049 BCM_GPORT_NIV_PORT_ID_SET(egr->port, vp); 15050 nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15051 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) { 15052 BCM_GPORT_EXTENDER_PORT_ID_SET(egr->port, vp); 15053 nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15054 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) { 15055 BCM_GPORT_VLAN_PORT_ID_SET(egr->port, vp); 15056 nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15057 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) { 15058 BCM_GPORT_WLAN_PORT_ID_SET(egr->port, vp); 15059 nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15060 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) { 15061 BCM_GPORT_MPLS_PORT_ID_SET(egr->port, vp); 15062 nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15063 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) { 15064 BCM_GPORT_VXLAN_PORT_ID_SET(egr->encap_id, vp); 15065 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15066 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) { 15067 BCM_GPORT_FLOW_PORT_ID_SET(egr->encap_id, vp); 15068 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15069 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) { 15070 BCM_GPORT_L2GRE_PORT_ID_SET(egr->encap_id, vp); 15071 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15072 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeTrill)) { 15073 BCM_GPORT_TRILL_PORT_ID_SET(egr->encap_id, vp); 15074 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15075 } else { 15076 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15077 } 15078 if (egr->encap_id == vp) { 15079 egr->module = 0; 15080 egr->trunk = 0; 15081 egr->flags &= ~BCM_L3_TGID; 15082 egr->encap_id = 0; 15083 } 15084 } else if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, egr->encap_id)) { 15085 /* encap_id contains a L2 egress object ID */ 15086 egr->port = 0; 15087 egr->module = 0; 15088 egr->trunk = 0; 15089 egr->flags &= ~BCM_L3_TGID; 15090 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15091 } else 15092 #endif /* BCM_TRX_SUPPORT */ 15093 { 15094 #ifdef BCM_RIOT_SUPPORT 15095 if (BCMI_RIOT_IS_ENABLED(unit) && 15096 (_bcm_vp_is_vfi_type(unit, egr->port))) { 15097 nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15098 } else 15099 #endif 15100 { 15101 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 15102 } 15103 } 15104 15105 /* Call user callback. */ 15106 if (NULL != trv_data->egress_cb) { 15107 rv = (*trv_data->egress_cb) (unit, nh_idx, egr, trv_data->cookie); 15108 #ifdef BCM_CB_ABORT_ON_ERR 15109 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 15110 return (rv); 15111 } 15112 #endif 15113 } 15114 15115 return (rv); 15116 } 15117 15118 /* 15119 * Function: 15120 * _bcm_xgs3_ecmp_group_nh_delete 15121 * Purpose: 15122 * Service routine used to decrement ecmp group member next hop 15123 * reference counter. 15124 * Parameters: 15125 * unit - (IN)SOC unit number. 15126 * ecmp_group - (IN)Ecmp group member array. 15127 * ecmp_count - (IN)Number of entries in ecmp group erray. 15128 * Returns: 15129 * BCM_E_XXX 15130 */ 15131 STATIC INLINE int 15132 _bcm_xgs3_ecmp_group_nh_delete(int unit, int *ecmp_group, int ecmp_count) 15133 { 15134 int idx; /* Iteration index. */ 15135 15136 /* Decrease reference count for all group member nexthops. */ 15137 for (idx = 0; idx < ecmp_count; idx++) { 15138 /* If ECMP member is another ECMP group, skip NH delete */ 15139 if (soc_feature(unit, soc_feature_hierarchical_ecmp) || 15140 soc_feature(unit, soc_feature_multi_level_ecmp)) { 15141 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 15142 ecmp_group[idx])) { 15143 continue; 15144 } 15145 } 15146 15147 bcm_xgs3_nh_del(unit, 0, ecmp_group[idx]); 15148 } 15149 return (BCM_E_NONE); 15150 } 15151 15152 15153 /* 15154 * Function: 15155 * _bcm_xgs3_ecmp_group_remove 15156 * Purpose: 15157 * Service routine used to decrement ecmp group member next hop 15158 * reference counter & destroy ecmp group. 15159 * Parameters: 15160 * unit - (IN)SOC unit number. 15161 * ecmp_idx - (IN)Ecmp group start index. 15162 * remove_nh - (IN)Remove group's member next hops. 15163 * Returns: 15164 * BCM_E_XXX 15165 */ 15166 STATIC int 15167 _bcm_xgs3_ecmp_group_remove(int unit, int ecmp_idx, int remove_nh) 15168 { 15169 int ecmp_count = 0; /* Next hop count in the group. */ 15170 int *ecmp_grp; /* Ecmp group from hw. */ 15171 int rv=BCM_E_NONE; /* Operation return status. */ 15172 15173 if (remove_nh) { 15174 /* Allocate ecmp group buffer. */ 15175 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 15176 15177 /* Read ecmp group members from the hw. */ 15178 rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_idx, 15179 ecmp_grp, &ecmp_count); 15180 if (BCM_FAILURE(rv)) { 15181 sal_free(ecmp_grp); 15182 return (rv); 15183 } 15184 15185 /* Decrease reference count for all group member nexthops. */ 15186 rv = _bcm_xgs3_ecmp_group_nh_delete(unit, ecmp_grp, ecmp_count); 15187 if (BCM_FAILURE(rv)) { 15188 sal_free(ecmp_grp); 15189 return (rv); 15190 } 15191 sal_free (ecmp_grp); 15192 } 15193 15194 /* Decrement reference count of existing group */ 15195 return bcm_xgs3_ecmp_group_del(unit, ecmp_idx, 0); 15196 } 15197 15198 /* 15199 * Function: 15200 * bcm_xgs3_l3_egress_traverse 15201 * Purpose: 15202 * Goes through egress objects table and runs the user callback 15203 * function at each valid egress objects entry passing back the 15204 * information for that object. 15205 * Parameters: 15206 * unit - (IN) bcm device. 15207 * trav_fn - (IN) Callback function. 15208 * user_data - (IN) User data to be passed to callback function. 15209 * Returns: 15210 * BCM_E_XXX 15211 */ 15212 int 15213 bcm_xgs3_l3_egress_traverse(int unit, bcm_l3_egress_traverse_cb trav_fn, 15214 void *user_data) 15215 { 15216 _bcm_l3_trvrs_data_t trv_data; /* Travers initiator function input. */ 15217 15218 /* Make sure module was initialized. */ 15219 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 15220 return (BCM_E_INIT); 15221 } 15222 15223 /* Check l3 switching mode. */ 15224 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 15225 return (BCM_E_DISABLED); 15226 } 15227 15228 /* Input parameters check. */ 15229 if (NULL == trav_fn) { 15230 return (BCM_E_PARAM); 15231 } 15232 15233 /* Zero traverse info. */ 15234 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 15235 15236 /* Fill traverse data struct. */ 15237 trv_data.op_cb = _bcm_xgs3_nh_traverse_cb; 15238 trv_data.egress_cb = trav_fn; 15239 trv_data.cookie = user_data; 15240 15241 /* Delete routes matching the pattern from hw. */ 15242 if (BCM_XGS3_L3_HWCALL_CHECK(unit, nh_update_match)) { 15243 int rv; 15244 BCM_XGS3_L3_MODULE_LOCK(unit); 15245 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_update_match) (unit, &trv_data); 15246 BCM_XGS3_L3_MODULE_UNLOCK(unit); 15247 return rv; 15248 } 15249 return (BCM_E_UNAVAIL); 15250 } 15251 15252 /* 15253 * Function: 15254 * _bcm_xgs3_l3_egress_intf_validate 15255 * Purpose: 15256 * Validate L3 egress objects array for multipath egress object 15257 * create / destroy / lookup 15258 * Parameters: 15259 * unit - (IN) bcm device. 15260 * intf_count - (IN) Number of elements in intf_array. 15261 * intf_array - (IN) Array of Egress forwarding objects. 15262 * ecmp_group_flags - (IN) ECMP group flags. 15263 * Returns: 15264 * BCM_E_XXX 15265 */ 15266 STATIC int 15267 _bcm_xgs3_l3_egress_intf_validate(int unit, int intf_count, 15268 bcm_if_t *intf_array, 15269 uint32 ecmp_group_flags) 15270 { 15271 _bcm_l3_tbl_t *tbl_ptr; /* Unit next hop table pointer. */ 15272 int idx; /* Iteration index. */ 15273 int nh_id; /* Next hop id. */ 15274 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT 15275 int ecmp_group_idx; /* ECMP group index */ 15276 #endif 15277 15278 /* Input parameters check */ 15279 if (intf_count > 0 && NULL == intf_array) { 15280 return (BCM_E_PARAM); 15281 } 15282 15283 /* Get next hop table pointer. */ 15284 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 15285 15286 /* Initialize ecmp group next hop indexes. */ 15287 for (idx = 0; idx < intf_count; idx ++) { 15288 15289 #ifdef BCM_TOMAHAWK_SUPPORT 15290 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 15291 if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15292 ecmp_mode_hierarchical) { 15293 /* 15294 * If ECMP group is at level 1, group index is a valid member 15295 * when the load balancing mode is not Resilient Hashing 15296 */ 15297 if ((ecmp_group_flags & BCM_L3_ECMP_OVERLAY) && 15298 !(ecmp_group_flags & BCM_L3_ECMP_RH_OPT) && 15299 (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx]))) { 15300 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, 15301 (intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 15302 BCM_L3_ECMP_UNDERLAY)) { 15303 continue; 15304 } else { 15305 return (BCM_E_PARAM); 15306 } 15307 } 15308 } 15309 } 15310 #endif /* BCM_TOMAHAWK_SUPPORT */ 15311 15312 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT 15313 if (soc_feature(unit, soc_feature_multi_level_ecmp)) { 15314 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 15315 /* 15316 * Overlay ECMP groups may have ecmp groups as valid members 15317 */ 15318 if ((ecmp_group_flags & BCM_L3_ECMP_OVERLAY) && 15319 (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 15320 intf_array[idx]))) { 15321 /* Make sure ecmp group member is inuse. */ 15322 ecmp_group_idx = intf_array[idx] - 15323 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 15324 15325 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 15326 ecmp_grp), ecmp_group_idx)) { 15327 return (BCM_E_PARAM); 15328 } 15329 /* Make sure ecmp group member is underlay. */ 15330 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, 15331 (intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 15332 BCM_L3_ECMP_OVERLAY)) { 15333 return (BCM_E_PARAM); 15334 } 15335 continue; 15336 } 15337 } 15338 } 15339 #endif /* BCM_MULTI_LEVEL_ECMP_SUPPORT */ 15340 15341 /* Egress object range sanity. */ 15342 if ((!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx]) && 15343 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[idx]))) { 15344 #ifdef BCM_TOMAHAWK3_SUPPORT 15345 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15346 if (!((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 15347 (ecmp_group_flags & BCM_L3_ECMP_OVERLAY)) || 15348 !(BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15349 ecmp_mode_hierarchical)) { 15350 return (BCM_E_PARAM); 15351 } 15352 } else 15353 #endif 15354 { 15355 return (BCM_E_PARAM); 15356 } 15357 } 15358 15359 /* Calculate next hop index. */ 15360 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15361 nh_id = intf_array[idx] - BCM_XGS3_EGRESS_IDX_MIN(unit); 15362 } 15363 #ifdef BCM_TOMAHAWK3_SUPPORT 15364 else if ((BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) && 15365 (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 15366 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15367 ecmp_mode_hierarchical)) { 15368 nh_id = intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 15369 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 15370 } 15371 #endif 15372 else { 15373 nh_id = intf_array[idx] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15374 } 15375 15376 /* Validate that next hop is valid and in use */ 15377 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, nh_id)) { 15378 return (BCM_E_PARAM); 15379 } 15380 } 15381 return (BCM_E_NONE); 15382 } 15383 15384 15385 /* 15386 * Function: 15387 * _bcm_xgs3_l3_egress_intf_ref_count_update 15388 * Purpose: 15389 * Update L3 egress object reference counts. 15390 * Parameters: 15391 * unit - (IN) bcm device. 15392 * intf_count - (IN) Number of elements in intf_array. 15393 * intf_array - (IN) Array of Egress forwarding objects. 15394 * inc_dec - (IN) +/-1 Increment/Decrement. 15395 * Returns: 15396 * BCM_E_XXX 15397 */ 15398 int 15399 _bcm_xgs3_l3_egress_intf_ref_count_update(int unit, int intf_count, 15400 bcm_if_t *intf_array, int inc_dec) 15401 { 15402 _bcm_l3_tbl_t *tbl_ptr; /* Unit next hop table pointer. */ 15403 int idx; /* Iteration index. */ 15404 int nh_id; /* Next hop id. */ 15405 15406 /* Get next hop table pointer. */ 15407 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 15408 15409 /* Initialize ecmp group next hop indexes. */ 15410 for (idx = 0; idx < intf_count; idx ++) { 15411 /* Skip over members that are not NH indices */ 15412 if (soc_feature(unit, soc_feature_hierarchical_ecmp) || 15413 soc_feature(unit, soc_feature_multi_level_ecmp)) { 15414 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 15415 intf_array[idx])) { 15416 continue; 15417 } 15418 } 15419 /* Calculate next hop index. */ 15420 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15421 nh_id = intf_array[idx] - BCM_XGS3_EGRESS_IDX_MIN(unit); 15422 } else { 15423 nh_id = intf_array[idx] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15424 } 15425 15426 /* Increment next hops reference counter. */ 15427 if (1 == inc_dec) { 15428 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE); 15429 } else { 15430 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE); 15431 } 15432 } 15433 return (BCM_E_NONE); 15434 } 15435 15436 STATIC INLINE int 15437 _bcm_esw_l3_ecmp_grand_max_paths(int unit, uint32 ecmp_group_flags) { 15438 int _max_paths = 0; 15439 15440 #ifdef BCM_TOMAHAWK_SUPPORT 15441 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 15442 (ecmp_group_flags & BCM_L3_ECMP_RH_OPT)) { 15443 _max_paths = BCM_XGS3_L3_ECMP_RH_MAX_PATHS(unit); 15444 } else 15445 #endif /* BCM_TOMAHAWK_SUPPORT */ 15446 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 15447 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized) && 15448 (ecmp_group_flags & BCM_L3_ECMP_DLB_OPT)) { 15449 _max_paths = 64; 15450 } else if (soc_feature(unit, soc_feature_dgm) && 15451 (ecmp_group_flags & BCM_L3_ECMP_DGM_OPT)) { 15452 _max_paths = 128; 15453 } else 15454 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 15455 { 15456 _max_paths = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 15457 #ifdef BCM_TOMAHAWK3_SUPPORT 15458 if ((soc_feature(unit, soc_feature_l3_ecmp_weighted)) && 15459 !(ecmp_group_flags & BCM_L3_ECMP_WEIGHTED)) { 15460 if (_max_paths > BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS) { 15461 _max_paths = BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS; 15462 } 15463 } 15464 #endif 15465 } 15466 15467 return _max_paths; 15468 } 15469 15470 15471 /* 15472 * Function: 15473 * _bcm_xgs3_l3_egress_multipath_to_ecmp_grp 15474 * Purpose: 15475 * Map an Egress Multipath forwarding object to hw ecmp group. 15476 * Parameters: 15477 * unit - (IN) bcm device. 15478 * intf_count - (IN) Number of elements in intf_array. 15479 * intf_array - (IN) Array of Egress forwarding objects. 15480 * ref_cnt_inc - (IN) Increment next hops reference counters. 15481 * ecmp_group_flags - (IN) ECMP group flags. 15482 * ecmp_group - (OUT)Array of next hop indexes. 15483 * Returns: 15484 * BCM_E_XXX 15485 */ 15486 STATIC int 15487 _bcm_xgs3_l3_egress_multipath_to_ecmp_grp(int unit, int intf_count, 15488 bcm_if_t *intf_array, 15489 int ref_cnt_inc, int *ecmp_group, 15490 uint32 ecmp_group_flags) 15491 { 15492 int idx; /* Iteration index. */ 15493 #ifdef BCM_TOMAHAWK3_SUPPORT 15494 int ecmp_intfs = 0; 15495 #endif 15496 15497 /* Enforce maximum ecmp path's */ 15498 if (intf_count > _bcm_esw_l3_ecmp_grand_max_paths(unit, ecmp_group_flags)) { 15499 return (BCM_E_RESOURCE); 15500 } 15501 15502 15503 /* Validate egress object interfaces array. */ 15504 BCM_IF_ERROR_RETURN 15505 (_bcm_xgs3_l3_egress_intf_validate(unit, intf_count, intf_array, 15506 ecmp_group_flags)); 15507 15508 /* Increment each individual next hop reference count. */ 15509 if (ref_cnt_inc) { 15510 BCM_IF_ERROR_RETURN 15511 (_bcm_xgs3_l3_egress_intf_ref_count_update(unit, intf_count, 15512 intf_array, 1)); 15513 } 15514 15515 /* Initialize ecmp group next hop indexes. */ 15516 for (idx = 0; idx < intf_count; idx ++) { 15517 /* Calculate next hop index. */ 15518 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15519 ecmp_group[idx] = intf_array[idx] - BCM_XGS3_EGRESS_IDX_MIN(unit); 15520 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[idx])){ 15521 ecmp_group[idx] = intf_array[idx] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15522 } 15523 #ifdef BCM_TOMAHAWK3_SUPPORT 15524 else if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15525 ecmp_group[idx] = intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 15526 } 15527 #endif 15528 #ifdef BCM_TOMAHAWK_SUPPORT 15529 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 15530 if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15531 ecmp_mode_hierarchical) { 15532 /* 15533 * If ECMP group is at level 1, group index is a valid member 15534 * intf_array[idx] has the absolute multipath index */ 15535 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15536 ecmp_group[idx] = intf_array[idx]; 15537 #ifdef BCM_TOMAHAWK3_SUPPORT 15538 ecmp_intfs++; 15539 #endif 15540 } 15541 15542 } 15543 } 15544 #endif /* BCM_TOMAHAWK_SUPPORT */ 15545 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT 15546 if (soc_feature(unit, soc_feature_multi_level_ecmp)) { 15547 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 15548 /* 15549 * If ECMP group is at level 1, group index is a valid member 15550 * intf_array[idx] has the absolute multipath index */ 15551 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) { 15552 ecmp_group[idx] = intf_array[idx]; 15553 } 15554 } 15555 } 15556 #endif /* BCM_MULTI_LEVEL_ECMP_SUPPORT */ 15557 15558 15559 15560 } 15561 #ifdef BCM_TOMAHAWK3_SUPPORT 15562 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) { 15563 if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15564 ecmp_mode_hierarchical) { 15565 if ((ecmp_group_flags & BCM_L3_ECMP_OVERLAY) && 15566 (ecmp_intfs != intf_count)) { 15567 if (ref_cnt_inc) { 15568 BCM_IF_ERROR_RETURN 15569 (_bcm_xgs3_l3_egress_intf_ref_count_update(unit, intf_count, 15570 intf_array, -1)); 15571 } 15572 return (BCM_E_PARAM); 15573 } 15574 } 15575 } 15576 #endif 15577 return (BCM_E_NONE); 15578 } 15579 15580 /* 15581 * Function: 15582 * _bcm_xgs3_l3_egress_multipath_read 15583 * Purpose: 15584 * Read an Egress Multipath forwarding object from hw. 15585 * Parameters: 15586 * unit - (IN) bcm device. 15587 * grp_idx - (IN) Ecmp group index. 15588 * intf_size - (IN) Maximum forwarding entries to read. 15589 * intf_array - (OUT) Array of Egress forwarding objects. 15590 * intf_count - (OUT) Number of entries of intf_count actually filled in. 15591 * Returns: 15592 * BCM_E_XXX 15593 */ 15594 STATIC int 15595 _bcm_xgs3_l3_egress_multipath_read(int unit, int grp_idx, int intf_size, 15596 bcm_if_t *intf_array, int *intf_count) 15597 { 15598 int *ecmp_grp; /* Ecmp group from hw. */ 15599 int idx; /* Iteration index. */ 15600 int rv; /* Operation return status. */ 15601 #ifdef BCM_TRIDENT2_SUPPORT 15602 char *egr_nh_tbl_ptr; /* Dma egress nh table pointer. */ 15603 uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pointer. */ 15604 #endif 15605 15606 /*Use BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID for chips like firebolt3 that 15607 * does not have ECMP_GROUP*/ 15608 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 15609 if (!BCMI_XGS3_L3_MPATH_GROUP_IDX_VALID(unit, 15610 (grp_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) { 15611 return (BCM_E_PARAM); 15612 } 15613 } else { 15614 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 15615 (grp_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) { 15616 return (BCM_E_PARAM); 15617 } 15618 } 15619 15620 /* Allocate ecmp group buffer. */ 15621 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 15622 15623 /* Read ecmp group from hw. */ 15624 rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, 15625 ecmp_grp, intf_count); 15626 if (BCM_FAILURE(rv)) { 15627 sal_free(ecmp_grp); 15628 return (rv); 15629 } 15630 15631 if (intf_size == 0) { 15632 sal_free(ecmp_grp); 15633 return (BCM_E_NONE); 15634 } 15635 15636 if (NULL == intf_array) { 15637 sal_free(ecmp_grp); 15638 return (BCM_E_PARAM); 15639 } 15640 15641 /* Adjust number of read entries . */ 15642 if (*intf_count > intf_size) { 15643 *intf_count = intf_size; 15644 } 15645 15646 #ifdef BCM_TRIDENT2_SUPPORT 15647 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 15648 if (*intf_count > L3_ECMP_MEM_DMA_THRESHOLD) { 15649 rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm, 15650 sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl", 15651 &egr_nh_tbl_ptr, NULL); 15652 if (SOC_FAILURE(rv)) { 15653 sal_free(ecmp_grp); 15654 return rv; 15655 } 15656 } 15657 } 15658 #endif 15659 /* Fill ecmp group info. */ 15660 for (idx = 0; idx < *intf_count; idx++) { 15661 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 15662 /* If this is already a multipath interface, skip adding base index */ 15663 if (soc_feature(unit, soc_feature_hierarchical_ecmp) || 15664 soc_feature(unit, soc_feature_multi_level_ecmp)) { 15665 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_grp[idx])) { 15666 intf_array[idx] = ecmp_grp[idx]; 15667 continue; 15668 } 15669 } 15670 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_MULTI_LEVEL_ECMP_SUPPORT */ 15671 #if defined(BCM_TOMAHAWK3_SUPPORT) 15672 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 15673 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15674 ecmp_mode_hierarchical) && 15675 (grp_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 15676 intf_array[idx] = 15677 ecmp_grp[idx] + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 15678 } else 15679 #endif 15680 { 15681 intf_array[idx] = ecmp_grp[idx] + BCM_XGS3_EGRESS_IDX_MIN(unit); 15682 } 15683 15684 #ifdef BCM_TRIDENT2_SUPPORT 15685 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 15686 egr_l3_next_hop_entry_t egr_nh; 15687 if (*intf_count > L3_ECMP_MEM_DMA_THRESHOLD) { 15688 egr_entry_ptr = 15689 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm, 15690 uint32 *, egr_nh_tbl_ptr, 15691 ecmp_grp[idx]); 15692 } else { 15693 rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 15694 ecmp_grp[idx], &egr_nh); 15695 if (SOC_FAILURE(rv)) { 15696 sal_free(ecmp_grp); 15697 return rv; 15698 } 15699 egr_entry_ptr = (uint32 *) &egr_nh; 15700 } 15701 15702 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, nh_entry_type_field[unit])) { 15703 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 15704 egr_entry_ptr, nh_entry_type_field[unit]) != 0) { 15705 continue; 15706 } 15707 15708 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 15709 egr_entry_ptr, L3__DVPf) == 0) { 15710 continue; 15711 } 15712 15713 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__DVP_VALIDf)) { 15714 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 15715 egr_entry_ptr, L3__DVP_VALIDf)) { 15716 intf_array[idx] = ecmp_grp[idx] + 15717 BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15718 } 15719 } else { 15720 intf_array[idx] = ecmp_grp[idx] + 15721 BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15722 } 15723 } 15724 } 15725 #endif /* BCM_TRIDENT2_SUPPORT */ 15726 } 15727 15728 #ifdef BCM_TRIDENT2_SUPPORT 15729 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 15730 if (*intf_count > L3_ECMP_MEM_DMA_THRESHOLD) { 15731 soc_cm_sfree(unit, egr_nh_tbl_ptr); 15732 } 15733 } 15734 #endif 15735 15736 #ifdef BCM_RIOT_SUPPORT 15737 if ((BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) || 15738 BCMI_RIOT_IS_ENABLED(unit)) && 15739 (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest) || 15740 soc_feature(unit, soc_feature_generic_dest))) { 15741 15742 for (idx = 0; idx < *intf_count; idx++) { 15743 ing_l3_next_hop_entry_t ing_nh_entry; 15744 uint32 nh_dest = 0; 15745 bcm_l3_egress_t nh; 15746 15747 bcm_l3_egress_t_init(&nh); 15748 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT 15749 /* Skip over members that are not NH indices */ 15750 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_grp[idx]) && 15751 soc_feature(unit, soc_feature_multi_level_ecmp)) { 15752 continue; 15753 } 15754 #endif /* BCM_MULTI_LEVEL_ECMP_SUPPORT */ 15755 15756 rv = soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 15757 ecmp_grp[idx], &ing_nh_entry); 15758 15759 if (SOC_FAILURE(rv)) { 15760 sal_free(ecmp_grp); 15761 return rv; 15762 } 15763 15764 nh_dest = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry, 15765 DESTINATIONf); 15766 #ifdef BCM_TRIDENT3_SUPPORT 15767 if (soc_feature(unit, soc_feature_generic_dest)) { 15768 bcmi_td3_get_port_from_destination(unit, nh_dest, &nh); 15769 } else 15770 #endif /* BCM_TRIDENT3_SUPPORT */ 15771 { 15772 bcmi_get_port_from_destination(unit, nh_dest, &nh); 15773 } 15774 if (_bcm_vp_is_vfi_type(unit, nh.port)) { 15775 intf_array[idx] = ecmp_grp[idx] + 15776 BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15777 } 15778 } 15779 } 15780 #endif 15781 sal_free(ecmp_grp); 15782 return (BCM_E_NONE); 15783 } 15784 15785 /* 15786 * Function: 15787 * bcmi_xgs3_l3_egress_ref_count_update 15788 * Purpose: 15789 * Update L3 egress object reference counts. 15790 * Parameters: 15791 * unit - (IN) bcm device. 15792 * intf_count - (IN) Number of elements in intf_array. 15793 * intf_array - (IN) Array of Egress forwarding objects. 15794 * incr - (IN) +/-1 Increment/Decrement. 15795 * Returns: 15796 * BCM_E_XXX 15797 */ 15798 int 15799 bcmi_xgs3_l3_egress_ref_count_update(int unit, 15800 bcm_if_t intf, 15801 uint32 flags, 15802 int nh_ecmp_id, 15803 int incr) 15804 { 15805 _bcm_l3_tbl_t *tbl_ptr; /* Unit next hop table pointer. */ 15806 int nh_id; /* Next hop Id.*/ 15807 15808 if (flags & BCM_L3_MULTIPATH) { 15809 /* Get next hop table pointer. */ 15810 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 15811 #if defined(BCM_TOMAHAWK3_SUPPORT) 15812 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 15813 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15814 ecmp_mode_hierarchical) && 15815 (nh_ecmp_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 15816 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 15817 } 15818 #endif 15819 nh_id = nh_ecmp_id; 15820 } else { 15821 /* Get next hop table pointer. */ 15822 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 15823 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 15824 nh_id = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 15825 } else { 15826 nh_id = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 15827 } 15828 } 15829 15830 if (incr) { 15831 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE); 15832 } else { 15833 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE); 15834 } 15835 15836 return BCM_E_NONE; 15837 } 15838 15839 /* 15840 * Function: 15841 * bcm_xgs3_l3_egress_multipath_max_create 15842 * Purpose: 15843 * Create an Egress Multipath forwarding object. 15844 * Parameters: 15845 * unit - (IN) bcm device. 15846 * flags - (IN) BCM_L3_REPLACE: replace existing. 15847 * BCM_L3_WITH_ID: intf argument is given. 15848 * ecmp_flags - (IN) BCM_L3_ECMP_PATH_NO_SORTING: not resort members 15849 * intf_count - (IN) Number of elements in intf_array. 15850 * intf_array - (IN) Array of Egress forwarding objects. 15851 * mpintf - (OUT) L3 interface id pointing to Egress multipath object. 15852 * This is an IN argument if either BCM_L3_REPLACE 15853 * or BCM_L3_WITH_ID are given in flags. 15854 * dlb_member_bitmap - (IN) ECMP DLB members. 15855 * Returns: 15856 * BCM_E_XXX 15857 */ 15858 int 15859 bcm_xgs3_l3_egress_multipath_max_create(int unit, uint32 flags, uint32 ecmp_flags, 15860 int max_paths, int intf_count, 15861 bcm_if_t *intf_array, bcm_if_t *mpintf, 15862 int primary_count, 15863 SHR_BITDCL *dlb_member_bitmap) 15864 { 15865 int *ecmp_group = NULL; /* Next hop indexes array. */ 15866 int *old_ecmp_group = NULL; /* Original nh indexes array. */ 15867 int old_group_size; /* Original ecmp group size. */ 15868 int ecmp_group_idx = -1; /* Ecmp group index. */ 15869 uint32 new_ecmp_flags = 0; /* ECMP group flags */ 15870 uint32 shr_flags; /* Table management flags. */ 15871 int rv = 0; /* Operation return status. */ 15872 int max_grp_paths = 0; /* Configured Max ECMP Group paths */ 15873 int _max_paths; 15874 _bcm_l3_tbl_t *tbl_ptr; /* Unit ecmp table pointer. */ 15875 15876 /* Make sure unit supports multipath egress mode. */ 15877 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 15878 15879 /* Input parameters check. */ 15880 if (NULL == mpintf) { 15881 return (BCM_E_PARAM); 15882 } 15883 15884 /* Make sure device supports ecmp forwarding. */ 15885 if (0 == BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) { 15886 return (BCM_E_UNAVAIL); 15887 } 15888 15889 _max_paths = _bcm_esw_l3_ecmp_grand_max_paths(unit, ecmp_flags); 15890 15891 if (max_paths == 0) { 15892 max_paths = _max_paths; 15893 } else if (max_paths < 2 || 15894 max_paths > _max_paths){ 15895 return BCM_E_PARAM; 15896 } 15897 15898 if (intf_count > max_paths) { 15899 return (BCM_E_RESOURCE); 15900 } 15901 15902 if (primary_count > intf_count) { 15903 return BCM_E_INTERNAL; 15904 } 15905 15906 if (primary_count < intf_count) { 15907 if (soc_feature(unit, soc_feature_dgm) && 15908 (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) { 15909 /* Either primary or alternate cannot exceed half grand max paths */ 15910 if (primary_count > (_max_paths >> 1) || 15911 (intf_count - primary_count) > (_max_paths >> 1)) { 15912 return (BCM_E_RESOURCE); 15913 } 15914 15915 /* Alternate count is not allowed to be equal to max paths */ 15916 if ((intf_count - primary_count) == max_paths) { 15917 return (BCM_E_PARAM); 15918 } 15919 } else { 15920 return BCM_E_INTERNAL; 15921 } 15922 } 15923 15924 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 15925 15926 #if defined(BCM_TOMAHAWK3_SUPPORT) 15927 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 15928 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 15929 ecmp_mode_hierarchical) && 15930 (ecmp_flags & BCM_L3_ECMP_OVERLAY)) { 15931 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 15932 } 15933 #endif 15934 old_group_size = 0; 15935 new_ecmp_flags = ecmp_flags; 15936 /* Allocate ecmp group buffer. */ 15937 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group)); 15938 15939 15940 /* Verify egress object range if BCM_L3_WITH_ID flag is set. */ 15941 if (flags & BCM_L3_WITH_ID) { 15942 15943 /* Get ecmp group index. */ 15944 ecmp_group_idx = *mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 15945 15946 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 15947 if (!BCMI_XGS3_L3_MPATH_GROUP_IDX_VALID(unit, *mpintf)) { 15948 sal_free(ecmp_group); 15949 return (BCM_E_PARAM); 15950 } 15951 } else { 15952 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, *mpintf)) { 15953 sal_free(ecmp_group); 15954 return (BCM_E_PARAM); 15955 } 15956 } 15957 15958 if (flags & BCM_L3_REPLACE) { 15959 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, 15960 ecmp_group_idx)) { 15961 sal_free(ecmp_group); 15962 return BCM_E_NOT_FOUND; 15963 } 15964 15965 rv = _bcm_xgs3_l3_ecmp_group_alloc(unit, &old_ecmp_group); 15966 if (BCM_FAILURE(rv)) { 15967 sal_free (ecmp_group); 15968 return rv; 15969 } 15970 15971 /* for rh, it's dynamic_size */ 15972 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, 15973 &max_grp_paths); 15974 if (rv < 0) { 15975 sal_free(ecmp_group); 15976 sal_free(old_ecmp_group); 15977 return rv; 15978 } 15979 15980 /* Since the last entry of the L3_ECMP table is reserved for 15981 * storing the group size, the last group size will be 1 less. 15982 * This check ensures that user configures only those number of 15983 * members. 15984 */ 15985 if (intf_count > max_paths) { 15986 sal_free(ecmp_group); 15987 sal_free(old_ecmp_group); 15988 return BCM_E_PARAM; 15989 } 15990 15991 rv = _bcm_xgs3_l3_egress_multipath_read(unit, ecmp_group_idx, 15992 max_grp_paths, old_ecmp_group, 15993 &old_group_size); 15994 15995 if (BCM_FAILURE(rv)) { 15996 sal_free(ecmp_group); 15997 sal_free(old_ecmp_group); 15998 return (rv); 15999 } 16000 16001 if (max_grp_paths != max_paths) { 16002 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 16003 #if defined(BCM_TRIDENT3_SUPPORT) 16004 if (soc_esw_ecmp_protected_enabled(unit)) { 16005 /* Do nothing. */ 16006 } else 16007 #endif /* BCM_TRIDENT3_SUPPORT */ 16008 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 16009 { 16010 rv = _bcm_xgs3_ecmp_group_max_size_update(unit, ecmp_flags, 16011 ecmp_group_idx, max_grp_paths, max_paths); 16012 } 16013 if (rv < 0) { 16014 sal_free(ecmp_group); 16015 sal_free(old_ecmp_group); 16016 return rv; 16017 } 16018 } 16019 } 16020 16021 /*Both add and delete operation should with BCM_L3_WITH_ID set */ 16022 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx, 16023 BCM_L3_ECMP_PATH_NO_SORTING)) { 16024 new_ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING; 16025 } 16026 } 16027 /* Convert api flags to shared table management flags. */ 16028 rv = _bcm_xgs3_l3_flags_to_shr(flags, &shr_flags); 16029 if (BCM_FAILURE(rv)) { 16030 sal_free(ecmp_group); 16031 if (old_ecmp_group != NULL) { 16032 sal_free(old_ecmp_group); 16033 } 16034 return (rv); 16035 } 16036 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) \ 16037 || defined(BCM_TOMAHAWK3_SUPPORT) 16038 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) 16039 #if defined(BCM_TOMAHAWK3_SUPPORT) 16040 || (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 16041 ecmp_mode_hierarchical) 16042 #endif 16043 ) { 16044 16045 if (ecmp_flags & BCM_L3_ECMP_OVERLAY) { 16046 shr_flags |= _BCM_L3_SHR_OVERLAY_OBJECT; 16047 } 16048 } 16049 #endif 16050 16051 /* Disable matching entry lookup. */ 16052 shr_flags |= _BCM_L3_SHR_MATCH_DISABLE; 16053 16054 /* Convert egress multipath object to ecmp group. */ 16055 rv = _bcm_xgs3_l3_egress_multipath_to_ecmp_grp(unit, intf_count, intf_array, 16056 TRUE, ecmp_group, new_ecmp_flags); 16057 16058 if (BCM_FAILURE(rv)) { 16059 sal_free(ecmp_group); 16060 if (old_ecmp_group != NULL) { 16061 sal_free(old_ecmp_group); 16062 } 16063 return (rv ); 16064 } 16065 16066 /* Create ecmp group. */ 16067 rv = _bcm_xgs3_ecmp_group_add(unit, shr_flags, new_ecmp_flags, intf_count, 16068 max_paths, ecmp_group, &ecmp_group_idx, 16069 primary_count, dlb_member_bitmap); 16070 16071 if (BCM_FAILURE(rv)) { 16072 /* Decrement nh reference count - if ecmp group creation failed. */ 16073 _bcm_xgs3_ecmp_group_nh_delete(unit, ecmp_group, intf_count); 16074 sal_free(ecmp_group); 16075 if (old_ecmp_group != NULL) { 16076 sal_free(old_ecmp_group); 16077 } 16078 return (rv); 16079 } else if (old_group_size) { 16080 /* Decrement nh reference count - for old ecmp group members. */ 16081 rv = _bcm_xgs3_l3_egress_intf_ref_count_update(unit, old_group_size, 16082 old_ecmp_group, -1); 16083 if (BCM_FAILURE(rv)) { 16084 sal_free(ecmp_group); 16085 if (old_ecmp_group != NULL) { 16086 sal_free(old_ecmp_group); 16087 } 16088 return (rv); 16089 } 16090 } 16091 16092 sal_free(ecmp_group); 16093 if (old_ecmp_group != NULL) { 16094 sal_free(old_ecmp_group); 16095 } 16096 16097 /* Return Egress object id 100K + nh_index */ 16098 *mpintf = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit) + ecmp_group_idx; 16099 return (BCM_E_NONE); 16100 } 16101 16102 /* 16103 * Function: 16104 * bcm_xgs3_l3_egress_multipath_create 16105 * Purpose: 16106 * Create an Egress Multipath forwarding object. 16107 * Parameters: 16108 * unit - (IN) bcm device. 16109 * flags - (IN) BCM_L3_REPLACE: replace existing. 16110 * BCM_L3_WITH_ID: intf argument is given. 16111 * ecmp_flags - (IN) BCM_L3_ECMP_PATH_NO_SORTING: not resort members 16112 * intf_count - (IN) Number of elements in intf_array. 16113 * intf_array - (IN) Array of Egress forwarding objects. 16114 * mpintf - (OUT) L3 interface id pointing to Egress multipath object. 16115 * This is an IN argument if either BCM_L3_REPLACE 16116 * or BCM_L3_WITH_ID are given in flags. 16117 * ecmp_member_bitmap - (IN) ECMP DLB members. 16118 * Returns: 16119 * BCM_E_XXX 16120 */ 16121 int 16122 bcm_xgs3_l3_egress_multipath_create(int unit, uint32 flags, uint32 ecmp_flags, 16123 int intf_count, bcm_if_t *intf_array, 16124 bcm_if_t *mpintf, int primary_count, 16125 SHR_BITDCL *dlb_member_bitmap) 16126 { 16127 return bcm_xgs3_l3_egress_multipath_max_create(unit, flags, ecmp_flags, 0, 16128 intf_count, intf_array, mpintf, 16129 primary_count, dlb_member_bitmap); 16130 } 16131 16132 /* 16133 * Function: 16134 * bcm_xgs3_l3_egress_multipath_get 16135 * Purpose: 16136 * Get an Egress Multipath forwarding object. 16137 * Parameters: 16138 * unit - (IN) bcm device. 16139 * mpintf - (IN) L3 interface id pointing to Egress multipath object. 16140 * intf_size - (IN) Size of allocated entries in intf_array. 16141 * intf_array - (OUT) Array of Egress forwarding objects. 16142 * intf_count - (OUT) Number of entries of intf_count actually filled in. 16143 * This will be a value less than or equal to the value. 16144 * passed in as intf_size unless intf_size is 0. If 16145 * intf_size is 0 then intf_array is ignored and 16146 * intf_count is filled in with the number of entries 16147 * that would have been filled into intf_array if 16148 * intf_size was arbitrarily large. 16149 * Returns: 16150 * BCM_E_XXX 16151 */ 16152 int 16153 bcm_xgs3_l3_egress_multipath_get(int unit, bcm_if_t mpintf, int intf_size, 16154 bcm_if_t *intf_array, int *intf_count) 16155 { 16156 int grp_idx; /* Ecmp group index. */ 16157 16158 #ifdef BCM_TRIDENT2_SUPPORT 16159 int max_vp_lags = 0; 16160 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 16161 _bcm_l3_tbl_t *tbl_ptr; /* Unit ecmp table pointer. */ 16162 #endif 16163 #endif /* BCM_TRIDENT2_SUPPORT */ 16164 16165 16166 /* Make sure unit supports multipath egress mode. */ 16167 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 16168 16169 /* Input parameters sanity check. */ 16170 if ((NULL == intf_count) || ((NULL == intf_array) && (0 != intf_size))) { 16171 return (BCM_E_PARAM); 16172 } 16173 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) { 16174 return (BCM_E_PARAM); 16175 } 16176 16177 /* Get ecmp group index. */ 16178 grp_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 16179 16180 #ifdef BCM_TRIDENT2_SUPPORT 16181 16182 /* In Trident2, reserved indices for VP-LAG should not be got. */ 16183 if (soc_feature(unit, soc_feature_vp_lag)) { 16184 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 16185 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 16186 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 16187 /* 16188 * TD2P has split indexes for overlay and underlay. 16189 * vp lags are in second range for underlay domain. 16190 * therefore skip indexes which are reserved for vp lag. 16191 */ 16192 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 16193 if ((tbl_ptr->split_idx > 0)) { 16194 if ((grp_idx >= tbl_ptr->split_idx) && 16195 (grp_idx < tbl_ptr->split_idx + max_vp_lags)) { 16196 return (BCM_E_PARAM); 16197 } 16198 } else 16199 #endif 16200 { 16201 if (grp_idx < max_vp_lags) { 16202 return (BCM_E_PARAM); 16203 } 16204 } 16205 } 16206 #endif /* BCM_TRIDENT2_SUPPORT */ 16207 16208 /* Read ecmp group from hardware. */ 16209 return _bcm_xgs3_l3_egress_multipath_read(unit, grp_idx, intf_size, 16210 intf_array, intf_count); 16211 } 16212 16213 /* 16214 * Function: 16215 * bcm_xgs3_l3_egress_ecmp_max_paths_get 16216 * Purpose: 16217 * Get maximum number of next hop entries in ecmp group 16218 * Parameters: 16219 * unit - (IN) SOC unit number. 16220 * mpintf - (IN) L3 interface ID pointing to Egress multipath object. 16221 * max_paths - (OUT) Ecmp group max paths. 16222 * raw_max_paths - (OUT) Ecmp group raw max paths. 16223 * Returns: 16224 */ 16225 int 16226 bcm_xgs3_l3_egress_ecmp_max_paths_get(int unit, bcm_if_t mpintf, 16227 int *max_paths, int *raw_max_paths) 16228 { 16229 int ecmp_group_idx; 16230 int raw_max = 0; 16231 16232 ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 16233 16234 #ifdef BCM_TOMAHAWK_SUPPORT 16235 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 16236 bcm_opt_ecmp_group_is_rh(unit, ecmp_group_idx)) { 16237 if (max_paths) { 16238 BCM_IF_ERROR_RETURN( 16239 bcm_opt_ecmp_rh_multipath_get(unit, ecmp_group_idx, 16240 0, NULL, NULL, max_paths)); 16241 } 16242 if (raw_max_paths) { 16243 BCM_IF_ERROR_RETURN( 16244 _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, 16245 raw_max_paths)); 16246 } 16247 16248 return BCM_E_NONE; 16249 } 16250 #endif /* BCM_TOMAHAWK_SUPPORT */ 16251 16252 BCM_IF_ERROR_RETURN( 16253 _bcm_xgs3_ecmp_max_grp_size_get(unit, 16254 ecmp_group_idx, &raw_max)); 16255 if (max_paths) { 16256 *max_paths = raw_max; 16257 } 16258 16259 if (raw_max_paths) { 16260 *raw_max_paths = raw_max; 16261 } 16262 16263 return BCM_E_NONE; 16264 } 16265 16266 /* 16267 * Function: 16268 * bcm_xgs3_l3_egress_multipath_destroy 16269 * Purpose: 16270 * Destroy an Egress Multipath forwarding object. 16271 * Parameters: 16272 * unit - (IN) bcm device. 16273 * mpintf - (IN) L3 interface id pointing to Egress multipath object. 16274 * Returns: 16275 * BCM_E_XXX 16276 */ 16277 int 16278 bcm_xgs3_l3_egress_multipath_destroy(int unit, bcm_if_t mpintf) 16279 { 16280 int ecmp_group_id; /* Ecmp group id. */ 16281 _bcm_l3_tbl_t *tbl_ptr; /* Unit ecmp table pointer. */ 16282 #if defined(BCM_TRIDENT2_SUPPORT) 16283 int max_vp_lags = 0; 16284 #endif /* BCM_TRIDENT2_SUPPORT */ 16285 16286 /* Make sure unit supports multipath egress mode. */ 16287 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 16288 16289 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 16290 16291 /* Calculate ecmp group id. */ 16292 ecmp_group_id = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 16293 #if defined(BCM_TOMAHAWK3_SUPPORT) 16294 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 16295 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 16296 ecmp_mode_hierarchical) && 16297 (ecmp_group_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 16298 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 16299 } 16300 #endif 16301 16302 #if defined(BCM_TRIDENT2_SUPPORT) 16303 if (soc_feature(unit, soc_feature_vp_lag)) { 16304 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 16305 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 16306 } 16307 #if defined(BCM_RIOT_SUPPORT) || defined (BCM_MULTI_LEVEL_ECMP_SUPPORT) 16308 if (tbl_ptr->split_idx > 0) { 16309 if ((ecmp_group_id >= tbl_ptr->split_idx) && 16310 (ecmp_group_id < (tbl_ptr->split_idx + max_vp_lags))) { 16311 return BCM_E_PARAM; 16312 } 16313 } else 16314 #endif /* BCM_RIOT_SUPPORT || BCM_MULTI_LEVEL_ECMP_SUPPORT */ 16315 { 16316 if (ecmp_group_id < max_vp_lags) { 16317 return BCM_E_PARAM; 16318 } 16319 } 16320 16321 #endif /* BCM_TRIDENT2_SUPPORT */ 16322 16323 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 16324 if (!BCMI_XGS3_L3_MPATH_GROUP_IDX_VALID(unit, mpintf)) { 16325 return (BCM_E_PARAM); 16326 } 16327 } else { 16328 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) { 16329 return (BCM_E_PARAM); 16330 } 16331 } 16332 16333 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_id)) { 16334 return BCM_E_NOT_FOUND; 16335 } 16336 16337 /* If entry is used by routes - reject deletion */ 16338 if(1 < BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_id)) { 16339 return (BCM_E_BUSY); 16340 } 16341 16342 /* Delete ecmp group. */ 16343 BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_group_remove(unit, 16344 ecmp_group_id, TRUE)); 16345 16346 /* Reset ecmp group flags. */ 16347 l3_module_data[unit]->l3_ecmp_info.ecmp_flags[ecmp_group_id] = 0; 16348 16349 return (BCM_E_NONE); 16350 } 16351 16352 /* 16353 * Function: 16354 * bcm_xgs3_l3_egress_multipath_add 16355 * Purpose: 16356 * Add an Egress forwarding object to an Egress Multipath 16357 * forwarding object. 16358 * Parameters: 16359 * unit - (IN) bcm device. 16360 * mpintf - (IN) L3 interface id pointing to Egress multipath object. 16361 * intf - (IN) L3 interface id pointing to Egress forwarding object. 16362 * Returns: 16363 * BCM_E_XXX 16364 */ 16365 int 16366 bcm_xgs3_l3_egress_multipath_add(int unit, bcm_if_t mpintf, bcm_if_t intf) 16367 { 16368 int ecmp_grp_sz; /* Ecmp group size. */ 16369 int *ecmp_grp; /* Ecmp group from hw. */ 16370 int rv; /* Operation return status.*/ 16371 int ecmp_group_idx; /* Ecmp group index. */ 16372 int max_grp_paths = 0; /* Configured Max ECMP Group paths */ 16373 16374 #if defined(BCM_HURRICANE_SUPPORT) 16375 if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) { 16376 return (BCM_E_UNAVAIL); 16377 } 16378 #endif 16379 if (soc_feature(unit, soc_feature_l3_no_ecmp)) { 16380 return (BCM_E_UNAVAIL); 16381 } 16382 16383 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) { 16384 return (BCM_E_PARAM); 16385 } 16386 /* Validate added interface. */ 16387 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 16388 return (BCM_E_PARAM); 16389 } 16390 16391 /* Allocate ecmp group buffer. */ 16392 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 16393 ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 16394 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_grp_paths); 16395 if (rv < 0) { 16396 sal_free (ecmp_grp); 16397 return rv; 16398 } 16399 16400 /* Get multipath egress object from hw. */ 16401 rv = bcm_xgs3_l3_egress_multipath_get (unit, mpintf, 16402 max_grp_paths, 16403 ecmp_grp, &ecmp_grp_sz); 16404 if (BCM_FAILURE(rv)) { 16405 sal_free(ecmp_grp); 16406 return (rv); 16407 } 16408 16409 16410 /* Check if there is room in ecmp grp buffer */ 16411 if (ecmp_grp_sz == BCM_XGS3_L3_ECMP_MAX(unit)) { 16412 sal_free(ecmp_grp); 16413 return (BCM_E_FULL); 16414 } 16415 16416 ecmp_grp[ecmp_grp_sz] = intf; 16417 16418 /* Update multipath egress object. */ 16419 rv = bcm_xgs3_l3_egress_multipath_create(unit, 16420 BCM_L3_REPLACE | BCM_L3_WITH_ID, 16421 0, 16422 ecmp_grp_sz + 1, ecmp_grp, 16423 &mpintf, ecmp_grp_sz + 1, NULL); 16424 sal_free(ecmp_grp); 16425 return (rv); 16426 } 16427 16428 /* 16429 * Function: 16430 * bcm_xgs3_l3_egress_multipath_delete 16431 * Purpose: 16432 * Delete an Egress forwarding object to an Egress Multipath 16433 * forwarding object. 16434 * Parameters: 16435 * unit - (IN) bcm device. 16436 * mpintf - (IN) L3 interface id pointing to Egress multipath object 16437 * intf - (IN) L3 interface id pointing to Egress forwarding object 16438 * Returns: 16439 * BCM_E_XXX 16440 */ 16441 int 16442 bcm_xgs3_l3_egress_multipath_delete(int unit, bcm_if_t mpintf, bcm_if_t intf) 16443 { 16444 int ecmp_grp_sz; /* Ecmp group size. */ 16445 int *ecmp_grp; /* Ecmp group from hw. */ 16446 int idx; /* Iteration index. */ 16447 int rv; /* Operation return status.*/ 16448 int ecmp_group_idx; /* Ecmp group index. */ 16449 int max_grp_paths = 0; /* Configured Max ECMP Group paths */ 16450 16451 #if defined(BCM_HURRICANE_SUPPORT) 16452 if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) { 16453 return (BCM_E_UNAVAIL); 16454 } 16455 16456 #endif 16457 if (soc_feature(unit, soc_feature_l3_no_ecmp)) { 16458 return (BCM_E_UNAVAIL); 16459 } 16460 16461 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) { 16462 return (BCM_E_PARAM); 16463 } 16464 /* Validate deleted interface. */ 16465 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 16466 return (BCM_E_PARAM); 16467 } 16468 16469 /* Allocate ecmp group buffer. */ 16470 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 16471 ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 16472 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_grp_paths); 16473 if (rv < 0) { 16474 sal_free(ecmp_grp); 16475 return rv; 16476 } 16477 16478 /* Get multipath egress object from hw. */ 16479 rv = bcm_xgs3_l3_egress_multipath_get(unit, mpintf, 16480 max_grp_paths, 16481 ecmp_grp, &ecmp_grp_sz); 16482 if (BCM_FAILURE(rv)) { 16483 sal_free(ecmp_grp); 16484 return (rv); 16485 } 16486 16487 /* Remove interface from egress object. */ 16488 for (idx = 0; idx < ecmp_grp_sz; idx++) { 16489 if (ecmp_grp[idx] == intf) { 16490 ecmp_grp[idx] = 0; 16491 break; 16492 } 16493 } 16494 16495 /* Check if deleted interface was found. */ 16496 if (idx == ecmp_grp_sz) { 16497 sal_free(ecmp_grp); 16498 return (BCM_E_NOT_FOUND); 16499 } 16500 16501 /* Copy last object interface to the deleted one spot. */ 16502 if (idx != (--ecmp_grp_sz)) { 16503 ecmp_grp[idx] = ecmp_grp[ecmp_grp_sz]; 16504 } 16505 16506 /* Update multipath egress object. */ 16507 rv = bcm_xgs3_l3_egress_multipath_max_create(unit, 16508 BCM_L3_REPLACE | BCM_L3_WITH_ID, 16509 0, 16510 max_grp_paths, ecmp_grp_sz, ecmp_grp, 16511 &mpintf, 16512 ecmp_grp_sz, NULL); 16513 sal_free(ecmp_grp); 16514 return (rv); 16515 } 16516 16517 /* 16518 * Function: 16519 * bcm_xgs3_l3_egress_multipath_find 16520 * Purpose: 16521 * Find an egress multipath forwarding object. 16522 * Parameters: 16523 * unit - (IN) bcm device. 16524 * intf_count - (IN) Number of elements in intf_array. 16525 * intf_array - (IN) Array of egress forwarding objects. 16526 * intf - (OUT) L3 interface id pointing to egress multipath object 16527 * if found. 16528 * Returns: 16529 * BCM_E_XXX 16530 */ 16531 int 16532 bcm_xgs3_l3_egress_multipath_find(int unit, int intf_count, bcm_if_t 16533 *intf_array, bcm_if_t *mpintf) 16534 { 16535 _bcm_l3_tbl_op_t data; /* Operation data. */ 16536 int *ecmp_group; /* Next hop indexes array. */ 16537 int rv; /* Operation return status. */ 16538 uint32 ecmp_group_flags = 0; 16539 _bcm_l3_ecmp_group_buffer_t ecmp_buf; 16540 16541 /* Make sure unit supports multipath egress mode. */ 16542 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 16543 16544 /* Input parameters check. */ 16545 if (NULL == mpintf) { 16546 return (BCM_E_PARAM); 16547 } 16548 16549 /* Allocate ecmp group buffer. */ 16550 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group)); 16551 16552 if (soc_feature(unit, soc_feature_hierarchical_ecmp) || 16553 soc_feature(unit, soc_feature_multi_level_ecmp)) { 16554 /* 16555 * Set ECMP Level to 1 to permit group members to be ecmp group id 16556 * or next hop ids 16557 */ 16558 #ifdef BCM_TOMAHAWK3_SUPPORT 16559 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) { 16560 if (intf_count && 16561 (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[0]))) { 16562 ecmp_group_flags = BCM_L3_ECMP_OVERLAY; 16563 } 16564 } else 16565 #endif 16566 { 16567 ecmp_group_flags = BCM_L3_ECMP_OVERLAY; 16568 } 16569 } 16570 16571 #ifdef BCM_TOMAHAWK3_SUPPORT 16572 if ((intf_count > BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS) && 16573 (soc_feature(unit, soc_feature_l3_ecmp_weighted))) { 16574 ecmp_group_flags |= BCM_L3_ECMP_WEIGHTED; 16575 } 16576 #endif 16577 16578 /* Convert egress multipath object to ecmp group. */ 16579 rv = _bcm_xgs3_l3_egress_multipath_to_ecmp_grp(unit, intf_count, intf_array, 16580 FALSE, ecmp_group, ecmp_group_flags); 16581 if (BCM_FAILURE(rv)) { 16582 sal_free(ecmp_group); 16583 return (rv); 16584 } 16585 16586 /* 16587 * Next hop indexes must be sorted in the group 16588 * in order to produce identical hash every time. 16589 */ 16590 _shr_sort(ecmp_group, intf_count, sizeof(int), _bcm_xgs3_cmp_int); 16591 16592 /* Initialization */ 16593 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 16594 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 16595 data.width = _BCM_SINGLE_WIDE; 16596 ecmp_buf.group_buffer = ecmp_group; 16597 /* Called by application without DLB filler */ 16598 ecmp_buf.dlb_group_buffer = NULL; 16599 data.entry_buffer = (void *)&ecmp_buf; 16600 data.hash_func = _bcm_xgs3_ecmp_grp_hash_calc; 16601 data.cmp_func = _bcm_xgs3_ecmp_grp_cmp; 16602 #ifdef BCM_TOMAHAWK3_SUPPORT 16603 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 16604 (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[0]))) { 16605 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 16606 } 16607 #endif 16608 /* Find next hop entry. */ 16609 rv = _bcm_xgs3_tbl_match(unit, &data); 16610 sal_free(ecmp_group); 16611 #ifdef BCM_TOMAHAWK_SUPPORT 16612 /* If this is a RH group on Tomahawk, find member array from _th_info */ 16613 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 16614 rv == BCM_E_NOT_FOUND) { 16615 return bcm_opt_l3_egress_rh_ecmp_find(unit, intf_count, 16616 intf_array, 16617 mpintf); 16618 } 16619 #endif 16620 if (BCM_FAILURE(rv)) { 16621 return (rv); 16622 } 16623 16624 /* Return Egress object id 100K + nh_index */ 16625 *mpintf = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit) + data.entry_index; 16626 return (BCM_E_NONE); 16627 } 16628 /* 16629 * Function: 16630 * bcm_xgs3_l3_egress_multipath_traverse 16631 * Purpose: 16632 * Goes through multipath egress objects table and runs the user callback 16633 * function at each multipath egress objects entry passing back the 16634 * information for that multipath object. 16635 * Parameters: 16636 * unit - (IN) bcm device. 16637 * trav_fn - (IN) Callback function. 16638 * user_data - (IN) User data to be passed to callback function. 16639 * Returns: 16640 * BCM_E_XXX 16641 */ 16642 int 16643 bcm_xgs3_l3_egress_multipath_traverse(int unit, 16644 bcm_l3_egress_multipath_traverse_cb trav_fn, 16645 void *user_data) 16646 { 16647 bcm_if_t *intf_array; /* Ecmp group from hw. */ 16648 _bcm_l3_tbl_t *tbl_ptr; /* Unit ecmp table pointer. */ 16649 int intf_count; /* Egress interfaces count. */ 16650 int idx; /* Iteration index. */ 16651 int rv; /* Operation return status. */ 16652 int max_grp_paths = 0; /* Configured Max ECMP Group paths */ 16653 #ifdef BCM_TRIDENT2_SUPPORT 16654 int max_vp_lags = 0; 16655 #endif 16656 16657 /* Make sure unit supports multipath egress mode. */ 16658 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 16659 16660 /* Input parameters check. */ 16661 if (NULL == trav_fn) { 16662 return (BCM_E_PARAM); 16663 } 16664 16665 /* Check if unit supports ecmp. */ 16666 if (!BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) { 16667 return (BCM_E_NONE); 16668 } 16669 16670 /* Allocate ecmp group buffer. */ 16671 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &intf_array)); 16672 16673 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 16674 idx = tbl_ptr->idx_min; 16675 16676 #ifdef BCM_TRIDENT2_SUPPORT 16677 /* In Trident2, reserved indices for VP-LAG should not be reported */ 16678 if (soc_feature(unit, soc_feature_vp_lag)) { 16679 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 16680 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 16681 } 16682 #endif /* BCM_TRIDENT2_SUPPORT */ 16683 16684 for (idx = 0; idx <= tbl_ptr->idx_maxused; idx++) { 16685 16686 #ifdef BCM_TRIDENT2_SUPPORT 16687 /* In Trident2, VP LAGs share the same table as ECMP group table. 16688 * The first N entries are reserved for VP LAGs, where N is the 16689 * value of the config property max_vp_lags. 16690 */ 16691 if (soc_feature(unit, soc_feature_vp_lag)) { 16692 16693 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 16694 /* 16695 * TD2P has split indexes for overlay and underlay. 16696 * vp lags are in second range for underlay domain. 16697 * therefore skip indexes which are reserved for vp lag. 16698 */ 16699 if ((tbl_ptr->split_idx > 0)) { 16700 16701 if ((idx >= tbl_ptr->split_idx) && 16702 (idx <= tbl_ptr->split_idx + max_vp_lags - 1)) { 16703 16704 idx = tbl_ptr->split_idx + max_vp_lags - 1; 16705 continue; 16706 } 16707 } else 16708 #endif 16709 { 16710 if (idx < max_vp_lags) { 16711 idx = max_vp_lags - 1; 16712 continue; 16713 } 16714 } 16715 } 16716 #endif /* BCM_TRIDENT2_SUPPORT */ 16717 16718 /* If group is not in use continue to the next one. */ 16719 if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) { 16720 continue; 16721 } 16722 16723 /* 16724 * COVERITY 16725 * 16726 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 16727 * rv from (*trav_fn) is being used - so it's a false alarm that 16728 * the value is being overwritten before use 16729 */ 16730 16731 /* coverity[value_overwrite : FALSE] */ 16732 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths); 16733 if (rv < 0) { 16734 sal_free(intf_array); 16735 return rv; 16736 } 16737 16738 /* Read group nexthops. */ 16739 #ifdef BCM_TOMAHAWK_SUPPORT 16740 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 16741 bcm_opt_ecmp_group_is_rh(unit, idx)) { 16742 rv = bcm_opt_ecmp_rh_multipath_get(unit, idx, 16743 BCM_XGS3_L3_ECMP_MAX(unit), 16744 intf_array, 16745 &intf_count, 16746 NULL); 16747 } else 16748 #endif 16749 { 16750 rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx, 16751 max_grp_paths, 16752 intf_array, &intf_count); 16753 } 16754 if (BCM_FAILURE(rv)) { 16755 sal_free(intf_array); 16756 return (rv); 16757 } 16758 16759 /* 16760 * COVERITY 16761 * 16762 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 16763 * rv from (*trav_fn) is being used below - so it's a false alarm 16764 * that the returned value is being overwritten before use. 16765 */ 16766 16767 /* coverity[returned_value : FALSE] */ 16768 rv = (*trav_fn)(unit, (idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 16769 intf_count, intf_array, user_data); 16770 #if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT) 16771 if (SOC_IS_SCORPION(unit) || SOC_IS_TRIUMPH(unit)) { 16772 /* Group index matches base index in ECMP table */ 16773 idx += (max_grp_paths - 1); 16774 } else 16775 #endif /* BCM_SCORPION_SUPPORT || BCM_TRIUMPH_SUPPORT */ 16776 16777 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 16778 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 16779 /* Each group takes two entries */ 16780 idx++; 16781 } 16782 #ifdef BCM_CB_ABORT_ON_ERR 16783 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 16784 sal_free(intf_array); 16785 return (rv); 16786 } 16787 #endif 16788 } 16789 #ifdef BCM_TOMAHAWK3_SUPPORT 16790 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 16791 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 16792 ecmp_mode_hierarchical)) { 16793 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 16794 idx = tbl_ptr->idx_min; 16795 16796 for (idx = 0; idx <= tbl_ptr->idx_maxused; idx++) { 16797 16798 /* If group is not in use continue to the next one. */ 16799 if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) { 16800 continue; 16801 } 16802 16803 /* 16804 * COVERITY 16805 * 16806 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 16807 * rv from (*trav_fn) is being used - so it's a false alarm that 16808 * the value is being overwritten before use 16809 */ 16810 16811 /* coverity[value_overwrite : FALSE] */ 16812 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths); 16813 if (rv < 0) { 16814 sal_free(intf_array); 16815 return rv; 16816 } 16817 16818 /* Read group nexthops. */ 16819 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 16820 bcm_opt_ecmp_group_is_rh(unit, idx)) { 16821 rv = bcm_opt_ecmp_rh_multipath_get(unit, idx, 16822 BCM_XGS3_L3_ECMP_MAX(unit), 16823 intf_array, 16824 &intf_count, 16825 NULL); 16826 } else 16827 { 16828 rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx, 16829 max_grp_paths, 16830 intf_array, &intf_count); 16831 } 16832 if (BCM_FAILURE(rv)) { 16833 sal_free(intf_array); 16834 return (rv); 16835 } 16836 16837 /* 16838 * COVERITY 16839 * 16840 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 16841 * rv from (*trav_fn) is being used below - so it's a false alarm 16842 * that the returned value is being overwritten before use. 16843 */ 16844 16845 /* coverity[returned_value : FALSE] */ 16846 rv = (*trav_fn)(unit, (idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 16847 intf_count, intf_array, user_data); 16848 16849 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 16850 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 16851 /* Each group takes two entries */ 16852 idx++; 16853 } 16854 #ifdef BCM_CB_ABORT_ON_ERR 16855 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 16856 sal_free(intf_array); 16857 return (rv); 16858 } 16859 #endif 16860 } 16861 } 16862 #endif 16863 sal_free(intf_array); 16864 return (BCM_E_NONE); 16865 } 16866 16867 /* 16868 * Function: 16869 * bcm_xgs3_l3_egress_ecmp_traverse 16870 * Purpose: 16871 * Goes through ECMP egress objects table and runs the user callback 16872 * function at each ECMP egress object entry passing back the 16873 * information for that ECMP object. 16874 * Parameters: 16875 * unit - (IN) bcm device. 16876 * trav_fn - (IN) Callback function. 16877 * user_data - (IN) User data to be passed to callback function. 16878 * Returns: 16879 * BCM_E_XXX 16880 */ 16881 int 16882 bcm_xgs3_l3_egress_ecmp_traverse(int unit, 16883 bcm_l3_egress_ecmp_traverse_cb trav_fn, 16884 void *user_data) 16885 { 16886 bcm_if_t *intf_array; /* Ecmp group from hw. */ 16887 _bcm_l3_tbl_t *tbl_ptr; /* Unit ecmp table pointer. */ 16888 int intf_count; /* Egress interfaces count. */ 16889 int idx; /* Iteration index. */ 16890 int rv; /* Operation return status. */ 16891 int max_grp_paths = 0; /* Configured Max ECMP Group paths */ 16892 bcm_l3_egress_ecmp_t ecmp; 16893 16894 /* Make sure unit supports multipath egress mode. */ 16895 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 16896 16897 /* Input parameters check. */ 16898 if (NULL == trav_fn) { 16899 return (BCM_E_PARAM); 16900 } 16901 16902 /* Check if unit supports ecmp. */ 16903 if (!BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) { 16904 return (BCM_E_NONE); 16905 } 16906 16907 /* Allocate ecmp group buffer. */ 16908 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &intf_array)); 16909 16910 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 16911 idx = tbl_ptr->idx_min; 16912 16913 /* TD3 supports unequal partition ecmp feature. If all the ecmp groups 16914 * are assigned to either OL or UL the table index should be from 0-4095 */ 16915 if (SOC_IS_TRIDENT3X(unit) && (tbl_ptr->idx_maxused == 16916 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit))) { 16917 tbl_ptr->idx_maxused = tbl_ptr->idx_maxused - 1; 16918 } 16919 16920 for (idx =0; idx <= tbl_ptr->idx_maxused; idx++) { 16921 16922 #ifdef BCM_TRIDENT2_SUPPORT 16923 /* In Trident2, reserved indices for VP-LAG should not be reported */ 16924 if (soc_feature(unit, soc_feature_vp_lag)) { 16925 int max_vp_lags = 0; 16926 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 16927 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 16928 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 16929 /* 16930 * TD2P has split indexes for overlay and underlay. 16931 * vp lags are in second range for underlay domain. 16932 * therefore skip indexes which are reserved for vp lag. 16933 */ 16934 if ((tbl_ptr->split_idx > 0)) { 16935 16936 if ((idx >= tbl_ptr->split_idx) && 16937 (idx <= tbl_ptr->split_idx + max_vp_lags - 1)) { 16938 16939 idx = tbl_ptr->split_idx + max_vp_lags - 1; 16940 continue; 16941 } 16942 } else 16943 #endif 16944 { 16945 if (idx < max_vp_lags) { 16946 idx = max_vp_lags - 1; 16947 continue; 16948 } 16949 16950 } 16951 } 16952 #endif /* BCM_TRIDENT2_SUPPORT */ 16953 16954 /* If group is not in use continue to the next one. */ 16955 if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) { 16956 continue; 16957 } 16958 16959 /* 16960 * COVERITY 16961 * 16962 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 16963 * rv from (*trav_fn) is being used - so it's a false alarm that 16964 * the value is being overwritten before use 16965 */ 16966 16967 /* coverity[value_overwrite : FALSE] */ 16968 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths); 16969 if (rv < 0) { 16970 sal_free(intf_array); 16971 return rv; 16972 } 16973 16974 /* Read group nexthops. */ 16975 rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx, 16976 max_grp_paths, 16977 intf_array, &intf_count); 16978 if (BCM_FAILURE(rv)) { 16979 sal_free(intf_array); 16980 return (rv); 16981 } 16982 /* TBD Skip over 256 reserved ECMP group entries */ 16983 16984 bcm_l3_egress_ecmp_t_init(&ecmp); 16985 ecmp.ecmp_intf = idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 16986 ecmp.max_paths = max_grp_paths; 16987 16988 #ifdef BCM_TRIUMPH3_SUPPORT 16989 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 16990 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 16991 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 16992 rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, &ecmp); 16993 16994 if (BCM_FAILURE(rv)) { 16995 sal_free(intf_array); 16996 return (rv); 16997 } 16998 16999 if (BCM_TH2_ECMP_IS_DLB(unit, ecmp.dynamic_mode)) { 17000 int i = 0, j = 0; 17001 SHR_BITDCL *group_bitmap_ptr = NULL; 17002 17003 /* Exclude filler members from expanded DLB group */ 17004 group_bitmap_ptr = 17005 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, idx); 17006 for (i = 0; i < intf_count; i++) { 17007 if (SHR_BITGET(group_bitmap_ptr, i)) { 17008 if (i > j) { 17009 intf_array[j++] = intf_array[i]; 17010 } else { 17011 j++; 17012 } 17013 } 17014 } 17015 intf_count = j; 17016 } 17017 } else 17018 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 17019 { 17020 rv = bcm_tr3_l3_egress_ecmp_dlb_get(unit, &ecmp); 17021 if (BCM_FAILURE(rv)) { 17022 sal_free(intf_array); 17023 return (rv); 17024 } 17025 } 17026 17027 } 17028 #endif /* BCM_TRIUMPH3_SUPPORT */ 17029 17030 #ifdef BCM_TRIDENT2_SUPPORT 17031 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) && 17032 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 17033 rv = bcm_td2_l3_egress_ecmp_rh_get(unit, &ecmp); 17034 if (BCM_FAILURE(rv)) { 17035 sal_free(intf_array); 17036 return (rv); 17037 } 17038 } 17039 #endif /* BCM_TRIDENT2_SUPPORT */ 17040 17041 #ifdef BCM_TOMAHAWK_SUPPORT 17042 /* Get ECMP Level flags */ 17043 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 17044 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, 17045 (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 17046 BCM_L3_ECMP_OVERLAY)) { 17047 ecmp.ecmp_group_flags |= BCM_L3_ECMP_OVERLAY; 17048 } 17049 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, 17050 (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 17051 BCM_L3_ECMP_UNDERLAY)) { 17052 ecmp.ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY; 17053 } 17054 } 17055 17056 /* Get ECMP group's existing interface array */ 17057 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 17058 rv = bcm_opt_l3_egress_ecmp_lb_get(unit, &ecmp); 17059 if (BCM_FAILURE(rv)) { 17060 sal_free(intf_array); 17061 return (rv); 17062 } 17063 17064 if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 17065 rv = bcm_opt_ecmp_rh_multipath_get(unit, 17066 (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 17067 BCM_XGS3_L3_ECMP_MAX(unit), 17068 intf_array, 17069 &intf_count, 17070 &ecmp.max_paths); 17071 if (BCM_FAILURE(rv)) { 17072 sal_free(intf_array); 17073 return (rv); 17074 } 17075 } 17076 } 17077 #endif /* BCM_TOMAHAWK_SUPPORT */ 17078 /* 17079 * COVERITY 17080 * 17081 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 17082 * rv from (*trav_fn) is being used below - so it's a false alarm 17083 * that the returned value is being overwritten before use. 17084 */ 17085 17086 /* coverity[returned_value : FALSE] */ 17087 rv = (*trav_fn)(unit, &ecmp, intf_count, intf_array, user_data); 17088 #if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT) 17089 if (SOC_IS_SCORPION(unit) || SOC_IS_TRIUMPH(unit) || SOC_IS_ENDURO(unit)) { 17090 /* Group index matches base index in ECMP table */ 17091 idx += (max_grp_paths - 1); 17092 } else 17093 #endif /* BCM_SCORPION_SUPPORT || BCM_TRIUMPH_SUPPORT */ 17094 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 17095 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 17096 /* Each group takes two entries */ 17097 idx++; 17098 } 17099 #ifdef BCM_CB_ABORT_ON_ERR 17100 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 17101 sal_free(intf_array); 17102 return (rv); 17103 } 17104 #endif 17105 } 17106 #ifdef BCM_TOMAHAWK3_SUPPORT 17107 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 17108 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 17109 ecmp_mode_hierarchical)) { 17110 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 17111 for (idx =0; idx <= tbl_ptr->idx_maxused; idx++) { 17112 17113 /* If group is not in use continue to the next one. */ 17114 if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) { 17115 continue; 17116 } 17117 17118 /* 17119 * COVERITY 17120 * 17121 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 17122 * rv from (*trav_fn) is being used - so it's a false alarm that 17123 * the value is being overwritten before use 17124 */ 17125 17126 /* coverity[value_overwrite : FALSE] */ 17127 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths); 17128 if (rv < 0) { 17129 sal_free(intf_array); 17130 return rv; 17131 } 17132 17133 /* Read group nexthops. */ 17134 rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx, 17135 max_grp_paths, 17136 intf_array, &intf_count); 17137 if (BCM_FAILURE(rv)) { 17138 sal_free(intf_array); 17139 return (rv); 17140 } 17141 /* TBD Skip over 256 reserved ECMP group entries */ 17142 17143 bcm_l3_egress_ecmp_t_init(&ecmp); 17144 ecmp.ecmp_intf = idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17145 ecmp.max_paths = max_grp_paths; 17146 17147 /* Get ECMP Level flags */ 17148 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 17149 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, 17150 (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 17151 BCM_L3_ECMP_OVERLAY)) { 17152 ecmp.ecmp_group_flags |= BCM_L3_ECMP_OVERLAY; 17153 } 17154 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, 17155 (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 17156 BCM_L3_ECMP_UNDERLAY)) { 17157 ecmp.ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY; 17158 } 17159 } 17160 17161 /* Get ECMP group's existing interface array */ 17162 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 17163 rv = bcm_opt_l3_egress_ecmp_lb_get(unit, &ecmp); 17164 if (BCM_FAILURE(rv)) { 17165 sal_free(intf_array); 17166 return (rv); 17167 } 17168 17169 if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 17170 rv = bcm_opt_ecmp_rh_multipath_get(unit, 17171 (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)), 17172 BCM_XGS3_L3_ECMP_MAX(unit), 17173 intf_array, 17174 &intf_count, 17175 &ecmp.max_paths); 17176 if (BCM_FAILURE(rv)) { 17177 sal_free(intf_array); 17178 return (rv); 17179 } 17180 } 17181 } 17182 /* 17183 * COVERITY 17184 * 17185 * In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of 17186 * rv from (*trav_fn) is being used below - so it's a false alarm 17187 * that the returned value is being overwritten before use. 17188 */ 17189 17190 /* coverity[returned_value : FALSE] */ 17191 rv = (*trav_fn)(unit, &ecmp, intf_count, intf_array, user_data); 17192 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 17193 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 17194 /* Each group takes two entries */ 17195 idx++; 17196 } 17197 #ifdef BCM_CB_ABORT_ON_ERR 17198 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 17199 sal_free(intf_array); 17200 return (rv); 17201 } 17202 #endif 17203 } 17204 } 17205 17206 #endif 17207 sal_free(intf_array); 17208 return (BCM_E_NONE); 17209 } 17210 17211 17212 int 17213 _bcm_xgs3_l3_ecmp_info_get( 17214 int unit, 17215 bcm_l3_egress_ecmp_t *ecmp_info) 17216 { 17217 int ecmp_group_idx; 17218 #ifdef BCM_TRIDENT3_SUPPORT 17219 int lb_mode = 0; 17220 #endif 17221 _bcm_l3_tbl_t *tbl_ptr; 17222 17223 if (ecmp_info == NULL) { 17224 return BCM_E_PARAM; 17225 } 17226 17227 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) { 17228 return BCM_E_PARAM; 17229 } 17230 17231 /* Get ecmp group index. */ 17232 ecmp_group_idx = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17233 17234 /* Make sure entry is inuse. */ 17235 #ifdef BCM_TOMAHAWK3_SUPPORT 17236 if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) && 17237 (ecmp_group_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) && 17238 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 17239 ecmp_mode_hierarchical)) { 17240 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 17241 } else 17242 #endif 17243 { 17244 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 17245 } 17246 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_idx)) { 17247 return (BCM_E_NOT_FOUND); 17248 } 17249 17250 /* Start to get the ECMP group's information */ 17251 ecmp_info->flags = 0; 17252 17253 BCM_IF_ERROR_RETURN( 17254 bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, ecmp_info->ecmp_intf, 17255 &ecmp_info->max_paths, NULL)); 17256 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx, 17257 BCM_L3_ECMP_PATH_NO_SORTING)) { 17258 ecmp_info->ecmp_group_flags = BCM_L3_ECMP_PATH_NO_SORTING; 17259 } else { 17260 ecmp_info->ecmp_group_flags = 0; 17261 } 17262 #ifdef BCM_TOMAHAWK_SUPPORT 17263 /* Get ECMP Level flags */ 17264 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 17265 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx, 17266 BCM_L3_ECMP_UNDERLAY)) { 17267 ecmp_info->ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY; 17268 } 17269 } 17270 #endif 17271 17272 #if defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 17273 /* Get ECMP Overlay Flag */ 17274 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 17275 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx, 17276 BCM_L3_ECMP_OVERLAY)) { 17277 ecmp_info->ecmp_group_flags |= BCM_L3_ECMP_OVERLAY; 17278 } 17279 } 17280 #endif 17281 17282 ecmp_info->dynamic_mode = 0; 17283 ecmp_info->dynamic_size = 0; 17284 ecmp_info->dynamic_age = 0; 17285 ecmp_info->dynamic_load_exponent = 0; 17286 ecmp_info->dynamic_expected_load_exponent = 0; 17287 ecmp_info->dgm.threshold = 0; 17288 ecmp_info->dgm.cost = 0; 17289 ecmp_info->dgm.bias = 0; 17290 17291 #ifdef BCM_TRIUMPH3_SUPPORT 17292 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 17293 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 17294 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 17295 BCM_IF_ERROR_RETURN( 17296 bcm_th2_l3_egress_ecmp_dlb_get(unit, ecmp_info)); 17297 } else 17298 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 17299 { 17300 BCM_IF_ERROR_RETURN( 17301 bcm_tr3_l3_egress_ecmp_dlb_get(unit, ecmp_info)); 17302 } 17303 } 17304 #endif /* BCM_TRIUMPH3_SUPPORT */ 17305 17306 #ifdef BCM_TRIDENT2_SUPPORT 17307 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) && 17308 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 17309 #ifdef BCM_TRIDENT3_SUPPORT 17310 if (SOC_IS_TRIDENT3X(unit)) { 17311 int ecmp_group; 17312 ecmp_count_entry_t ecmp_count_entry; 17313 17314 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) { 17315 ecmp_group = ecmp_info->ecmp_intf - 17316 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17317 17318 BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, 17319 ecmp_group, &ecmp_count_entry)); 17320 lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit, 17321 &ecmp_count_entry, LB_MODEf); 17322 } 17323 } 17324 #endif 17325 if ( (!(SOC_IS_TRIDENT3X(unit))) 17326 #ifdef BCM_TRIDENT3_SUPPORT 17327 || ((lb_mode == BCM_ECMP_LB_MODE_ENHANCED_HASH) 17328 && (ecmp_info->dynamic_mode == 0)) 17329 #endif 17330 ) { 17331 BCM_IF_ERROR_RETURN( 17332 bcm_td2_l3_egress_ecmp_rh_get(unit, ecmp_info)); 17333 } 17334 } 17335 #endif /* BCM_TRIDENT2_SUPPORT */ 17336 17337 #ifdef BCM_TOMAHAWK_SUPPORT 17338 17339 if ( 17340 #ifdef BCM_TRIDENT3_SUPPORT 17341 ( ((SOC_IS_TRIDENT3X(unit)) && (lb_mode != BCM_ECMP_LB_MODE_ENHANCED_HASH))) || 17342 #endif 17343 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 17344 BCM_IF_ERROR_RETURN( 17345 bcm_opt_l3_egress_ecmp_lb_get(unit, ecmp_info)); 17346 } 17347 #endif /* BCM_TOMAHAWK_SUPPORT */ 17348 #if defined(BCM_TOMAHAWK3_SUPPORT) 17349 if (ecmp_info->ecmp_group_flags & BCM_L3_ECMP_WEIGHTED) { 17350 /* Weighted groups are never sorted */ 17351 ecmp_info->ecmp_group_flags &= ~BCM_L3_ECMP_PATH_NO_SORTING; 17352 } 17353 #endif 17354 17355 return BCM_E_NONE; 17356 } 17357 17358 /* 17359 * Function: 17360 * _bcm_xgs3_l3_ecmp_member_alloc 17361 * Purpose: 17362 * Allocate l3 ecmp group members array. 17363 * Parameters: 17364 * unit - (IN) BCM device number. 17365 * ptr - (IN) Allocated group pointer 17366 * Returns: 17367 * BCM_X_XXX 17368 */ 17369 int 17370 _bcm_xgs3_l3_ecmp_member_alloc(int unit, bcm_l3_ecmp_member_t **ptr) 17371 { 17372 int alloc_size; 17373 17374 /* Make sure module was initialized. */ 17375 if (NULL == ptr) { 17376 return (BCM_E_NONE); 17377 } 17378 17379 17380 alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit); 17381 17382 *ptr = NULL; 17383 BCM_XGS3_L3_ALLOC((*ptr), alloc_size, "ecmp members array"); 17384 17385 /* Input parameters check */ 17386 if (NULL == *ptr) { 17387 return (BCM_E_MEMORY); 17388 } 17389 return (BCM_E_NONE); 17390 } 17391 17392 /* 17393 * Function: 17394 * _bcm_xgs3_l3_ecmp_member_failover_set 17395 * Purpose: 17396 * Set the Ethertypes that are eligible or ineligible for 17397 * ECMP dynamic load balancing or resilient hashing. 17398 * Parameters: 17399 * unit - Unit number. 17400 * ecmp_info - ECMP group information. 17401 * member_index - member offset in ECMP group. 17402 * ecmp_member - ECMP member's information. 17403 * Returns: 17404 * BCM_E_XXX 17405 */ 17406 STATIC int 17407 _bcm_xgs3_l3_ecmp_member_failover_set( 17408 int unit, 17409 bcm_l3_egress_ecmp_t *ecmp_info, 17410 int member_index, 17411 bcm_l3_ecmp_member_t *ecmp_member) 17412 { 17413 int rv = BCM_E_NONE; 17414 17415 #ifdef BCM_TRIUMPH2_SUPPORT 17416 if (soc_feature(unit, soc_feature_ecmp_failover)) { 17417 int grp_idx; 17418 int nh_index, prot_nh_index; 17419 int failover_id, failover_egress_if; 17420 int failover_id_valid = FALSE; 17421 17422 if (_bcm_esw_failover_id_check( 17423 unit, ecmp_member->failover_id) == BCM_E_NONE) { 17424 failover_id_valid = TRUE; 17425 } 17426 17427 #ifdef BCM_TOMAHAWK2_SUPPORT 17428 if (soc_feature(unit, soc_feature_ecmp_failover_config_check)) { 17429 if (ecmp_info->dynamic_mode) { 17430 /* ECMP failover is only available to static hash */ 17431 rv = failover_id_valid ? BCM_E_PARAM : BCM_E_NONE; 17432 return rv; 17433 } else { 17434 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 17435 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 17436 ecmp_member->egress_if)) { 17437 /* Failover is not suitable for ecmp group */ 17438 rv = failover_id_valid ? BCM_E_PARAM : BCM_E_NONE; 17439 return rv; 17440 } 17441 } 17442 } else 17443 #endif /* BCM_TOMAHAWK2_SUPPORT */ 17444 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 17445 ecmp_member->egress_if)) { 17446 rv = failover_id_valid ? BCM_E_PARAM : BCM_E_NONE; 17447 return rv; 17448 } 17449 17450 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) { 17451 return (BCM_E_PARAM); 17452 } 17453 17454 if (! (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member->egress_if) || 17455 (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)))) { 17456 return (BCM_E_PARAM); 17457 } 17458 17459 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 17460 #if defined(BCM_TRIDENT3_SUPPORT) 17461 if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) { 17462 if (ecmp_info->ecmp_group_flags & BCM_L3_ECMP_OVERLAY || 17463 ecmp_info->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY) { 17464 /* Failover is not supported in Hierarchical ECMP configuration. */ 17465 if (failover_id_valid) { 17466 return (BCM_E_PARAM); 17467 } 17468 } 17469 } 17470 #endif /* BCM_TRIDENT3_SUPPORT */ 17471 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 17472 17473 grp_idx = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17474 if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)){ 17475 nh_index = ecmp_member->egress_if - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 17476 } else { 17477 nh_index = ecmp_member->egress_if - BCM_XGS3_EGRESS_IDX_MIN(unit); 17478 } 17479 failover_id = ecmp_member->failover_id; 17480 failover_egress_if = ecmp_member->failover_egress_if; 17481 17482 if (failover_id_valid && 17483 BCM_XGS3_L3_EGRESS_IDX_VALID(unit, failover_egress_if)) { 17484 prot_nh_index = 17485 ecmp_member->failover_egress_if - BCM_XGS3_EGRESS_IDX_MIN(unit); 17486 17487 rv = _bcm_esw_failover_ecmp_prot_nhi_create(unit, grp_idx, 17488 member_index, 17489 nh_index, failover_id, 17490 prot_nh_index); 17491 } else { 17492 rv = _bcm_esw_failover_ecmp_prot_nhi_cleanup(unit, grp_idx, 17493 member_index, 17494 nh_index); 17495 } 17496 } 17497 #endif /* BCM_TRIUMPH2_SUPPORT */ 17498 17499 return rv; 17500 } 17501 17502 /* 17503 * Function: 17504 * _bcm_xgs3_l3_ecmp_member_failover_get 17505 * Purpose: 17506 * Get the Ethertypes that are eligible or ineligible for 17507 * ECMP dynamic load balancing or resilient hashing. 17508 * Parameters: 17509 * unit - Unit number. 17510 * ecmp_info - ECMP group information. 17511 * member_index - member offset in ECMP group. 17512 * ecmp_member - ECMP member's information. 17513 * Returns: 17514 * BCM_E_XXX 17515 */ 17516 17517 STATIC int 17518 _bcm_xgs3_l3_ecmp_member_failover_get( 17519 int unit, 17520 bcm_l3_egress_ecmp_t *ecmp_info, 17521 int member_index, 17522 bcm_l3_ecmp_member_t *ecmp_member) 17523 { 17524 int rv = BCM_E_NONE; 17525 17526 #ifdef BCM_TRIUMPH2_SUPPORT 17527 if (soc_feature(unit, soc_feature_ecmp_failover)) { 17528 int nh_index, prot_nh_index; 17529 int grp_idx, failover_id, failover_intf; 17530 17531 #ifdef BCM_TOMAHAWK2_SUPPORT 17532 if (soc_feature(unit, soc_feature_ecmp_failover_config_check)) { 17533 if (ecmp_info->dynamic_mode) { 17534 /* ECMP failover is only available to static hash */ 17535 return (BCM_E_NONE); 17536 } else { 17537 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 17538 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID( 17539 unit, ecmp_member->egress_if)) { 17540 /* Failover is not suitable for ecmp group */ 17541 return (BCM_E_NONE); 17542 } 17543 } 17544 } else 17545 #endif /* BCM_TOMAHAWK2_SUPPORT */ 17546 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 17547 ecmp_member->egress_if)) { 17548 rv = BCM_E_NONE; 17549 return rv; 17550 } 17551 17552 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) { 17553 return (BCM_E_PARAM); 17554 } 17555 17556 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)) { 17557 return (BCM_E_PARAM); 17558 } 17559 17560 grp_idx = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17561 nh_index = ecmp_member->egress_if - BCM_XGS3_EGRESS_IDX_MIN(unit); 17562 17563 rv = _bcm_esw_failover_ecmp_prot_nhi_get(unit, grp_idx, 17564 member_index, nh_index, 17565 &failover_id, &prot_nh_index); 17566 if (BCM_SUCCESS(rv)) { 17567 failover_intf = prot_nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit); 17568 ecmp_member->failover_id = failover_id; 17569 ecmp_member->failover_egress_if = failover_intf; 17570 } 17571 } 17572 #endif /* BCM_TRIUMPH2_SUPPORT */ 17573 17574 return rv; 17575 } 17576 17577 17578 int 17579 _bcm_xgs3_l3_ecmp_member_get( 17580 int unit, 17581 bcm_l3_egress_ecmp_t *ecmp_info, 17582 int ecmp_member_size, 17583 bcm_l3_ecmp_member_t *ecmp_member_array, 17584 int *ecmp_member_count) 17585 { 17586 int rv, i; 17587 int alloc_size, intf_count; 17588 bcm_if_t *intf_array = NULL; 17589 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 17590 int alternate_count = 0; 17591 #endif 17592 if (ecmp_info == NULL) { 17593 return BCM_E_PARAM; 17594 } 17595 17596 /* Start to get the ECMP member's information */ 17597 if (ecmp_member_size > 0) { 17598 alloc_size = ecmp_member_size * sizeof(bcm_if_t); 17599 intf_array = sal_alloc(alloc_size, "L3 ECMP intf_array"); 17600 if (intf_array == NULL) { 17601 rv = BCM_E_MEMORY; 17602 goto clean_up; 17603 } 17604 } 17605 17606 /* Get ECMP group's existing interface array */ 17607 rv = bcm_esw_l3_egress_multipath_get(unit, ecmp_info->ecmp_intf, ecmp_member_size, 17608 intf_array, &intf_count); 17609 if (BCM_FAILURE(rv)) { 17610 goto clean_up; 17611 } 17612 17613 *ecmp_member_count = intf_count; 17614 17615 if (ecmp_member_size > 0) { 17616 for (i = 0; i < *ecmp_member_count; i++) { 17617 /* Get ECMP member's interface id */ 17618 ecmp_member_array[i].egress_if = intf_array[i]; 17619 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 17620 if (soc_feature(unit, soc_feature_dgm)) { 17621 alternate_count = BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit) 17622 [ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)]; 17623 if (i >= (intf_count - alternate_count)) { 17624 ecmp_member_array[i].flags |= BCM_L3_ECMP_MEMBER_DGM_ALTERNATE; 17625 } 17626 } 17627 #endif 17628 /* Get ECMP member's failover information */ 17629 rv = _bcm_xgs3_l3_ecmp_member_failover_get(unit, ecmp_info, 17630 i, &ecmp_member_array[i]); 17631 if (rv == BCM_E_NOT_FOUND) { 17632 rv = BCM_E_NONE; 17633 } 17634 if (BCM_FAILURE(rv)) { 17635 goto clean_up; 17636 } 17637 } 17638 } 17639 clean_up: 17640 if (intf_array) { 17641 sal_free(intf_array); 17642 intf_array = NULL; 17643 } 17644 17645 return rv; 17646 } 17647 17648 int 17649 _bcm_xgs3_l3_ecmp_member_set( 17650 int unit, 17651 bcm_l3_egress_ecmp_t *ecmp_info, 17652 int ecmp_member_count, 17653 bcm_l3_ecmp_member_t *ecmp_member) 17654 { 17655 int rv = BCM_E_NONE; 17656 int i; 17657 17658 /* 17659 * Next hop indexes must be sorted in the group 17660 * in order to produce identical hash every time. 17661 */ 17662 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) || 17663 !((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) || 17664 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) && 17665 (ecmp_info->ecmp_group_flags & BCM_L3_ECMP_PATH_NO_SORTING))) { 17666 #if defined(BCM_TOMAHAWK3_SUPPORT) 17667 if (!(ecmp_info->ecmp_group_flags & BCM_L3_ECMP_WEIGHTED)) 17668 #endif 17669 _shr_sort(ecmp_member, ecmp_member_count, sizeof(bcm_l3_ecmp_member_t), 17670 _bcm_xgs3_cmp_ecmp_member); 17671 } 17672 17673 /* Configure the member's attributions */ 17674 for (i = 0; i < ecmp_member_count; i++) { 17675 /* Configure the failover_id and failover_intf */ 17676 rv = _bcm_xgs3_l3_ecmp_member_failover_set(unit, ecmp_info, 17677 i, &ecmp_member[i]); 17678 17679 if (BCM_FAILURE(rv)) { 17680 return rv; 17681 } 17682 } 17683 17684 17685 return rv; 17686 } 17687 17688 int 17689 bcm_xgs3_l3_ecmp_destroy( 17690 int unit, 17691 bcm_if_t ecmp_group_id) 17692 { 17693 int rv; 17694 17695 rv = bcm_xgs3_l3_egress_multipath_destroy(unit, ecmp_group_id); 17696 17697 #ifdef BCM_TRIUMPH3_SUPPORT 17698 if (BCM_SUCCESS(rv)) { 17699 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 17700 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 17701 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 17702 rv = bcm_th2_l3_egress_ecmp_dlb_destroy(unit, ecmp_group_id); 17703 } else 17704 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 17705 { 17706 rv = bcm_tr3_l3_egress_ecmp_dlb_destroy(unit, ecmp_group_id); 17707 } 17708 } 17709 } 17710 #endif /* BCM_TRIUMPH3_SUPPORT */ 17711 17712 #ifdef BCM_TRIDENT2_SUPPORT 17713 if (BCM_SUCCESS(rv)) { 17714 if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 17715 #ifdef BCM_TRIDENT3_SUPPORT 17716 int lb_mode = 0; 17717 int ecmp_group; 17718 ecmp_count_entry_t ecmp_count_entry; 17719 17720 if (SOC_IS_TRIDENT3X(unit)) { 17721 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_group_id)) { 17722 17723 ecmp_group = ecmp_group_id - 17724 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17725 17726 BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, 17727 ecmp_group, &ecmp_count_entry)); 17728 lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit, 17729 &ecmp_count_entry, LB_MODEf); 17730 } 17731 } 17732 #endif 17733 if ( (!(SOC_IS_TRIDENT3X(unit))) 17734 #ifdef BCM_TRIDENT3_SUPPORT 17735 || (lb_mode == BCM_ECMP_LB_MODE_ENHANCED_HASH) 17736 #endif 17737 ) { 17738 rv = bcm_td2_l3_egress_ecmp_rh_destroy(unit, ecmp_group_id); 17739 } 17740 } 17741 } 17742 #endif /* BCM_TRIDENT2_SUPPORT */ 17743 17744 #ifdef BCM_TOMAHAWK_SUPPORT 17745 if (BCM_SUCCESS(rv)) { 17746 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 17747 rv = bcm_opt_l3_egress_ecmp_rh_destroy(unit, ecmp_group_id); 17748 } 17749 } 17750 if (BCM_SUCCESS(rv) && 17751 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 17752 rv = bcm_opt_ecmp_lb_mode_reset(unit, ecmp_group_id); 17753 } 17754 if (BCM_SUCCESS(rv) && soc_feature(unit, soc_feature_hierarchical_ecmp)) { 17755 /* Reset the group flags */ 17756 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, 17757 ecmp_group_id - 17758 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), 17759 BCM_L3_ECMP_OVERLAY); 17760 BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, 17761 ecmp_group_id - 17762 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), 17763 BCM_L3_ECMP_UNDERLAY); 17764 } 17765 #endif /* BCM_TOMAHAWK_SUPPORT */ 17766 17767 return rv; 17768 } 17769 17770 int 17771 bcm_xgs3_l3_ecmp_get( 17772 int unit, 17773 bcm_l3_egress_ecmp_t *ecmp_info, 17774 int ecmp_member_size, 17775 bcm_l3_ecmp_member_t *ecmp_member_array, 17776 int *ecmp_member_count) 17777 { 17778 int rv; 17779 17780 if (ecmp_info == NULL) { 17781 return BCM_E_PARAM; 17782 } 17783 17784 /* Get the ECMP group's information */ 17785 rv = _bcm_xgs3_l3_ecmp_info_get(unit, ecmp_info); 17786 BCM_IF_ERROR_RETURN(rv); 17787 17788 /* Get the ECMP member's information */ 17789 rv = _bcm_xgs3_l3_ecmp_member_get(unit, ecmp_info, ecmp_member_size, 17790 ecmp_member_array, ecmp_member_count); 17791 BCM_IF_ERROR_RETURN(rv); 17792 17793 return rv; 17794 } 17795 17796 int 17797 bcm_xgs3_l3_ecmp_find( 17798 int unit, 17799 int ecmp_member_count, 17800 bcm_l3_ecmp_member_t *ecmp_member_array, 17801 bcm_l3_egress_ecmp_t *ecmp_info) 17802 { 17803 int rv, i, intf_count; 17804 bcm_if_t *intf_array = NULL; 17805 17806 if (ecmp_member_count == 0 || 17807 ecmp_member_array == NULL || 17808 ecmp_info == NULL) { 17809 return BCM_E_PARAM; 17810 } 17811 17812 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &intf_array)); 17813 17814 intf_count = ecmp_member_count; 17815 17816 for (i = 0; i < intf_count; i++) { 17817 intf_array[i] = ecmp_member_array[i].egress_if; 17818 } 17819 17820 rv = bcm_xgs3_l3_egress_multipath_find(unit, intf_count, intf_array, 17821 &ecmp_info->ecmp_intf); 17822 17823 if (BCM_FAILURE(rv)) { 17824 goto clean_up; 17825 } 17826 17827 rv = _bcm_xgs3_l3_ecmp_info_get(unit, ecmp_info); 17828 if (BCM_FAILURE(rv)) { 17829 goto clean_up; 17830 } 17831 17832 clean_up: 17833 if (intf_array) { 17834 sal_free(intf_array); 17835 intf_array = NULL; 17836 } 17837 17838 return rv; 17839 } 17840 17841 17842 int 17843 _bcm_xgs3_l3_ecmp_range_traverse(int unit, int start, int end, _bcm_l3_tbl_t *tbl_ptr, 17844 bcm_l3_ecmp_member_t *ecmp_member_array, bcm_l3_ecmp_traverse_cb trav_fn, 17845 void *user_data) 17846 { 17847 int rv = 0; 17848 int idx = 0; 17849 bcm_l3_egress_ecmp_t ecmp_info; 17850 int ecmp_member_count; /* Egress interfaces count. */ 17851 17852 for (idx = start; idx <= end; idx++) { 17853 /* If group is not in use continue to the next one. */ 17854 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx)) { 17855 continue; 17856 } 17857 17858 bcm_l3_egress_ecmp_t_init(&ecmp_info); 17859 17860 ecmp_info.ecmp_intf = idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 17861 17862 rv = bcm_esw_l3_ecmp_get(unit, &ecmp_info, BCM_XGS3_L3_ECMP_MAX(unit), 17863 ecmp_member_array, &ecmp_member_count); 17864 if (BCM_FAILURE(rv)) { 17865 return rv; 17866 } 17867 17868 rv = (*trav_fn)(unit, &ecmp_info, ecmp_member_count, ecmp_member_array, 17869 user_data); 17870 #if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT) 17871 if (SOC_IS_SCORPION(unit) || SOC_IS_TRIUMPH(unit)) { 17872 /* Group index matches base index in ECMP table */ 17873 idx += (ecmp_info.max_paths - 1); 17874 } else 17875 #endif /* BCM_SCORPION_SUPPORT || BCM_TRIUMPH_SUPPORT */ 17876 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) && 17877 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 17878 /* Each group takes two entries */ 17879 idx++; 17880 } 17881 #ifdef BCM_CB_ABORT_ON_ERR 17882 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 17883 return rv; 17884 } 17885 #endif 17886 } 17887 return rv; 17888 } 17889 17890 17891 int 17892 bcm_xgs3_l3_ecmp_traverse( 17893 int unit, 17894 bcm_l3_ecmp_traverse_cb trav_fn, 17895 void *user_data) 17896 { 17897 int rv = BCM_E_NONE, idx; 17898 _bcm_l3_tbl_t *tbl_ptr; /* Unit ecmp table pointer. */ 17899 bcm_l3_ecmp_member_t *ecmp_member_array = NULL; /* Ecmp group from hw. */ 17900 17901 /* Make sure unit supports multipath egress mode. */ 17902 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit)); 17903 17904 /* Input parameters check. */ 17905 if (NULL == trav_fn) { 17906 return (BCM_E_PARAM); 17907 } 17908 17909 /* Check if unit supports ecmp. */ 17910 if (!BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) { 17911 return (BCM_E_NONE); 17912 } 17913 17914 /* Allocate ecmp group buffer. */ 17915 BCM_IF_ERROR_RETURN( 17916 _bcm_xgs3_l3_ecmp_member_alloc(unit, &ecmp_member_array)); 17917 17918 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 17919 idx = tbl_ptr->idx_min; 17920 17921 #ifdef BCM_TRIDENT2_SUPPORT 17922 /* In Trident2/Tomahawk, reserved indices for VP-LAG should not be reported */ 17923 if (soc_feature(unit, soc_feature_vp_lag)) { 17924 idx = soc_property_get(unit, spn_MAX_VP_LAGS, 17925 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 17926 } 17927 #endif /* BCM_TRIDENT2_SUPPORT */ 17928 17929 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 17930 /* 17931 * TD2P has split indexes for overlay and underlay. 17932 * vp lags are in second range for underlay domain. 17933 * therefore skip indexes which are reserved for vp lag. 17934 */ 17935 if ((tbl_ptr->split_idx > 0)) { 17936 idx += tbl_ptr->split_idx; 17937 17938 /* traverse overlay indexes */ 17939 rv = _bcm_xgs3_l3_ecmp_range_traverse(unit, tbl_ptr->idx_min, 17940 tbl_ptr->split_maxused, tbl_ptr, ecmp_member_array, trav_fn, user_data); 17941 17942 if (BCM_FAILURE(rv)) { 17943 goto clean_up; 17944 } 17945 } 17946 #endif 17947 #if defined(BCM_TOMAHAWK3_SUPPORT) 17948 if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 17949 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 17950 ecmp_mode_hierarchical)) { 17951 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 17952 17953 idx = tbl_ptr->idx_min; 17954 17955 /* traverse overlay indexes */ 17956 rv = _bcm_xgs3_l3_ecmp_range_traverse(unit, idx, tbl_ptr->idx_maxused, tbl_ptr, 17957 ecmp_member_array, trav_fn, user_data); 17958 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 17959 idx = tbl_ptr->idx_min; 17960 } 17961 #endif 17962 /* traverse underlay indexes */ 17963 rv = _bcm_xgs3_l3_ecmp_range_traverse(unit, idx, tbl_ptr->idx_maxused, tbl_ptr, 17964 ecmp_member_array, trav_fn, user_data); 17965 if (BCM_FAILURE(rv)) { 17966 goto clean_up; 17967 } 17968 17969 clean_up: 17970 if (ecmp_member_array) { 17971 sal_free(ecmp_member_array); 17972 ecmp_member_array = NULL; 17973 } 17974 return (rv); 17975 } 17976 17977 /* 17978 * Function: 17979 * bcm_xgs3_host_to_route 17980 * Purpose: 17981 * Service routine used to copy host data in a route format 17982 * Parameters: 17983 * unit - (IN)SOC unit number. 17984 * l3cfg - (IN) Host information. 17985 * lpm_cfg - (OUT) Corresponding route info. 17986 * Returns: 17987 * BCM_E_XXX 17988 */ 17989 STATIC INLINE int 17990 bcm_xgs3_host_to_route(int unit, _bcm_l3_cfg_t *l3cfg, 17991 _bcm_defip_cfg_t *lpm_cfg) 17992 { 17993 /* Input parameters check. */ 17994 if ((NULL == l3cfg) || (NULL == lpm_cfg)) { 17995 return (BCM_E_PARAM); 17996 } 17997 /* Reset destination buffer. */ 17998 sal_memset(lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 17999 18000 /* Prepare route entry. */ 18001 lpm_cfg->defip_flags = (l3cfg->l3c_flags | BCM_L3_HOST_AS_ROUTE); 18002 lpm_cfg->defip_vrf = l3cfg->l3c_vrf; 18003 18004 if (l3cfg->l3c_flags & BCM_L3_IP6) { 18005 sal_memcpy(lpm_cfg->defip_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 18006 lpm_cfg->defip_sub_len = BCM_XGS3_L3_IPV6_PREFIX_LEN; 18007 } else { 18008 lpm_cfg->defip_ip_addr = l3cfg->l3c_ip_addr; 18009 lpm_cfg->defip_sub_len = BCM_XGS3_L3_IPV4_PREFIX_LEN; 18010 } 18011 sal_memcpy(lpm_cfg->defip_mac_addr, l3cfg->l3c_mac_addr, 18012 sizeof(bcm_mac_t)); 18013 lpm_cfg->defip_intf = l3cfg->l3c_intf; 18014 lpm_cfg->defip_port_tgid = l3cfg->l3c_port_tgid; 18015 lpm_cfg->defip_modid = l3cfg->l3c_modid; 18016 lpm_cfg->defip_vid = l3cfg->l3c_vid; 18017 return (BCM_E_NONE); 18018 } 18019 18020 /* 18021 * Function: 18022 * bcm_xgs3_route_to_host 18023 * Purpose: 18024 * Service routine used to copy route data in a host format 18025 * Parameters: 18026 * unit - (IN)SOC unit number. 18027 * lpm_cfg - (IN) Route info. 18028 * l3cfg - (OUT) Host information. 18029 * Returns: 18030 * BCM_E_XXX 18031 */ 18032 STATIC INLINE int 18033 bcm_xgs3_route_to_host(int unit, _bcm_defip_cfg_t *lpm_cfg, 18034 _bcm_l3_cfg_t *l3cfg) 18035 { 18036 /* Input parameters check. */ 18037 if ((NULL == l3cfg) || (NULL == lpm_cfg)) { 18038 return (BCM_E_PARAM); 18039 } 18040 18041 /* Reset destination buffer. */ 18042 sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 18043 18044 /* Prepare host entry. */ 18045 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 18046 if (lpm_cfg->defip_sub_len != BCM_XGS3_L3_IPV6_PREFIX_LEN) { 18047 return (BCM_E_NOT_FOUND); 18048 } 18049 sal_memcpy(l3cfg->l3c_ip6, lpm_cfg->defip_ip6_addr, sizeof(bcm_ip6_t)); 18050 } else { 18051 if (lpm_cfg->defip_sub_len != BCM_XGS3_L3_IPV4_PREFIX_LEN) { 18052 return (BCM_E_NOT_FOUND); 18053 } 18054 l3cfg->l3c_ip_addr = lpm_cfg->defip_ip_addr; 18055 } 18056 18057 l3cfg->l3c_flags = (lpm_cfg->defip_flags | BCM_L3_HOST_AS_ROUTE); 18058 l3cfg->l3c_vrf = lpm_cfg->defip_vrf; 18059 18060 sal_memcpy(l3cfg->l3c_mac_addr, lpm_cfg->defip_mac_addr, 18061 sizeof(bcm_mac_t)); 18062 l3cfg->l3c_intf = lpm_cfg->defip_intf; 18063 l3cfg->l3c_port_tgid = lpm_cfg->defip_port_tgid; 18064 l3cfg->l3c_modid = lpm_cfg->defip_modid; 18065 l3cfg->l3c_vid = lpm_cfg->defip_vid; 18066 return (BCM_E_NONE); 18067 } 18068 18069 /* 18070 * Function: 18071 * _bcm_xgs3_host_ecmp_del 18072 * Purpose: 18073 * Delete IP host with multipaths from L3 entry table table 18074 * Parameters: 18075 * unit - (IN)SOC unit number. 18076 * _bcm_l3_cfg_t - (IN)Host Entry data. 18077 * ecmp_group_id - (IN)Ecmp group id. 18078 * Returns: 18079 * BCM_E_XXX 18080 */ 18081 STATIC int 18082 _bcm_xgs3_host_ecmp_del(int unit, _bcm_l3_cfg_t *l3cfg, 18083 int ecmp_group_id) 18084 { 18085 int ecmp_count; /* Next hop count in the group. */ 18086 int *ecmp_grp; /* Ecmp group from hw. */ 18087 int rv; /* Internal operations status. */ 18088 18089 18090 /* Input parameters check. */ 18091 /* ECMP support for Host Entries */ 18092 if (NULL == l3cfg || 18093 !soc_feature(unit, soc_feature_l3_host_ecmp_group)) { 18094 return (BCM_E_PARAM); 18095 } 18096 18097 /* Only supported in egress mode */ 18098 if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 18099 return BCM_E_UNAVAIL; 18100 } 18101 18102 /* Allocate ecmp group buffer. */ 18103 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 18104 18105 /* Read ecmp group members from the hw. */ 18106 rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_id, 18107 ecmp_grp, &ecmp_count); 18108 if (BCM_FAILURE(rv)) { 18109 sal_free(ecmp_grp); 18110 return (rv); 18111 } 18112 18113 /* Delete entry from hw. */ 18114 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_del)) { 18115 BCM_XGS3_L3_MODULE_LOCK(unit); 18116 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del) (unit, l3cfg); 18117 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18118 } else { 18119 sal_free(ecmp_grp); 18120 return (BCM_E_UNAVAIL); 18121 } 18122 18123 18124 rv = bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0); 18125 sal_free(ecmp_grp); 18126 return rv; 18127 } 18128 18129 18130 18131 /* 18132 * Function: 18133 * bcm_xgs3_host_as_route 18134 * Purpose: 18135 * Service routine used to operate host entry as route. 18136 * Host inserted as route in case host table is full. 18137 * Parameters: 18138 * unit - (IN) SOC unit number. 18139 * l3cfg - (IN) Deleted host information. 18140 * operation - (IN) Host table operation. 18141 * orig_rv (IN) Host as route is not supported on 18142 * some devices/configurations. 18143 * Returns: 18144 * BCM_E_XXX 18145 */ 18146 int 18147 bcm_xgs3_host_as_route(int unit, _bcm_l3_cfg_t *l3cfg, 18148 int operation, int orig_rv) 18149 { 18150 _bcm_defip_cfg_t lpm_cfg; /* Route info. */ 18151 int retval; /* Operation return value. */ 18152 18153 /* Input parameters check. */ 18154 if (NULL == l3cfg) { 18155 return (BCM_E_PARAM); 18156 } 18157 18158 if (l3cfg->l3c_flags & BCM_L3_IP6) { 18159 if (!soc_feature(unit, soc_feature_lpm_prefix_length_max_128) || 18160 !(soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1))) { 18161 return (orig_rv); 18162 } 18163 } else { 18164 if (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0) { 18165 return (orig_rv); 18166 } 18167 } 18168 18169 BCM_IF_ERROR_RETURN(bcm_xgs3_host_to_route(unit, l3cfg, &lpm_cfg)); 18170 18171 switch (operation){ 18172 case BCM_XGS3_L3_OP_GET: 18173 retval = bcm_xgs3_defip_get(unit, &lpm_cfg); 18174 if (BCM_SUCCESS(retval)) { 18175 BCM_IF_ERROR_RETURN(bcm_xgs3_route_to_host(unit, &lpm_cfg, l3cfg)); 18176 } 18177 break; 18178 case BCM_XGS3_L3_OP_ADD: 18179 retval = bcm_xgs3_defip_add(unit, &lpm_cfg); 18180 break; 18181 case BCM_XGS3_L3_OP_DEL: 18182 retval = bcm_xgs3_defip_del(unit, &lpm_cfg); 18183 break; 18184 default: 18185 retval = BCM_E_INTERNAL; 18186 } 18187 return (retval); 18188 } 18189 18190 18191 /* 18192 * Function: 18193 * bcm_xgs3_l3_get 18194 * Purpose: 18195 * Get an entry from L3 table. 18196 * Parameters: 18197 * unit - (IN)SOC unit number. 18198 * l3cfg - (IN/OUT)Structure to fill l3 entry information. 18199 * Returns: 18200 * BCM_E_XXX 18201 */ 18202 int 18203 bcm_xgs3_l3_get(int unit, _bcm_l3_cfg_t *l3cfg) 18204 { 18205 int nh_idx; /* Next hop index. */ 18206 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 18207 18208 /* Make sure module was initialized. */ 18209 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 18210 return (BCM_E_INIT); 18211 } 18212 18213 /* Input parameters check */ 18214 if (NULL == l3cfg) { 18215 return (BCM_E_PARAM); 18216 } 18217 18218 /* Check if address is multicast. */ 18219 if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) { 18220 /* Read multicast entry. */ 18221 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) { 18222 BCM_XGS3_L3_MODULE_LOCK(unit); 18223 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, l3cfg); 18224 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18225 } 18226 } else { 18227 /* Unicast handling. */ 18228 /* Read l3 host entry. */ 18229 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) { 18230 BCM_XGS3_L3_MODULE_LOCK(unit); 18231 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, l3cfg, &nh_idx); 18232 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18233 } 18234 18235 if (BCM_SUCCESS(rv)) { 18236 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_get_nh_info(unit, l3cfg, nh_idx)); 18237 } else if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) && 18238 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) { 18239 rv = bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_GET, rv); 18240 if (BCM_SUCCESS(rv)) { 18241 /* Special return value - as entry retrieved from ROUTE table */ 18242 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv); 18243 } 18244 } 18245 } 18246 return rv; 18247 } 18248 /* 18249 * Function: 18250 * bcm_xgs3_l3_add 18251 * Purpose: 18252 * Add an entry in L3 table. 18253 * Parameters: 18254 * unit - (IN)SOC unit number. 18255 * l3cfg - (IN)Structure with l3 entry information. 18256 * Returns: 18257 * BCM_E_XXX 18258 */ 18259 int 18260 bcm_xgs3_l3_add(int unit, _bcm_l3_cfg_t *l3cfg) 18261 { 18262 int nh_idx; /* Next hop index. */ 18263 int rv = BCM_E_UNAVAIL; /* Operation return value */ 18264 int mpath = 0; /* Multipath */ 18265 18266 /* Make sure module was initialized. */ 18267 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 18268 return (BCM_E_INIT); 18269 } 18270 18271 /* Input parameters check */ 18272 if (NULL == l3cfg) { 18273 return (BCM_E_PARAM); 18274 } 18275 18276 if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) { 18277 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) { 18278 BCM_XGS3_L3_MODULE_LOCK(unit); 18279 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg); 18280 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18281 } else { 18282 return (BCM_E_UNAVAIL); 18283 } 18284 } else { 18285 /* Multipath is only supported in Egress Switching Mode */ 18286 if (soc_feature(unit, soc_feature_l3_host_ecmp_group)) { 18287 mpath = l3cfg->l3c_flags & BCM_L3_MULTIPATH; 18288 if (mpath) { 18289 if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 18290 return BCM_E_UNAVAIL; 18291 } 18292 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 18293 l3cfg->l3c_intf)) { 18294 return BCM_E_PARAM; 18295 } 18296 } 18297 if (!mpath && 18298 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) { 18299 return BCM_E_PARAM; 18300 } 18301 } else { 18302 if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) { 18303 return BCM_E_UNAVAIL; 18304 } 18305 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) { 18306 return BCM_E_PARAM; 18307 } 18308 } 18309 18310 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 18311 /* Trunk id validation. */ 18312 BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags, 18313 l3cfg->l3c_port_tgid); 18314 } 18315 18316 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) { 18317 BCM_XGS3_L3_MODULE_LOCK(unit); 18318 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, l3cfg, NULL); 18319 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18320 } 18321 18322 /* Any reason why replace is not checked? */ 18323 BCM_XGS3_IF_ERROR_OR_ENTRY_EXISTS_RETURN(rv); 18324 if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid) || 18325 (l3cfg->l3c_flags & BCM_L3_DST_DISCARD)) { 18326 nh_idx = BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit); 18327 } else { 18328 /* Get next hop index. */ 18329 BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx)); 18330 } 18331 18332 #ifdef BCM_TOMAHAWK_SUPPORT 18333 if (soc_feature(unit, soc_feature_extended_view_no_trunk_support) && 18334 BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx) && 18335 (l3cfg->l3c_flags & BCM_L3_TGID)) { 18336 return BCM_E_UNAVAIL; 18337 } 18338 #endif /* BCM_TOMAHAWK_SUPPORT */ 18339 18340 /* Write entry to hw. */ 18341 l3cfg->l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX; /* Add /No overrite. */ 18342 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) { 18343 BCM_XGS3_L3_MODULE_LOCK(unit); 18344 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add) (unit, l3cfg, nh_idx); 18345 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18346 } else { 18347 rv = BCM_E_UNAVAIL; 18348 } 18349 18350 /* Do best effort clean_up if needed. */ 18351 if (BCM_FAILURE(rv)) { 18352 if (mpath) { 18353 /* coverity[negative_returns : FALSE] */ 18354 bcm_xgs3_ecmp_group_del(unit, nh_idx, 0); 18355 } else { 18356 bcm_xgs3_nh_del(unit, 0, nh_idx); 18357 } 18358 } 18359 /* If l3 table full or disabled customer allowed to write */ 18360 /* the entry to lpm table. */ 18361 if (((BCM_E_FULL == rv) || (BCM_E_DISABLED == rv)) && 18362 (l3cfg->l3c_flags & BCM_L3_HOST_AS_ROUTE) && 18363 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) { 18364 rv = bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv); 18365 if (BCM_SUCCESS(rv)) { 18366 /* Special return value - as entry added to ROUTE table */ 18367 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv); 18368 } 18369 } 18370 } 18371 18372 return rv; 18373 } 18374 18375 /* 18376 * Function: 18377 * bcm_xgs3_l3_del 18378 * Purpose: 18379 * Delete an entry in L3 table. 18380 * Parameters: 18381 * unit - SOC unit number. 18382 * l3cfg - Pointer to memory for l3 table related information. 18383 * Returns: 18384 * BCM_E_XXX 18385 */ 18386 int 18387 bcm_xgs3_l3_del(int unit, _bcm_l3_cfg_t *l3cfg) 18388 { 18389 int nh_idx; /* Next hop index. */ 18390 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 18391 18392 /* Make sure module was initialized. */ 18393 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 18394 return (BCM_E_INIT); 18395 } 18396 18397 /* Input parameters check */ 18398 if (NULL == l3cfg) { 18399 return (BCM_E_PARAM); 18400 } 18401 18402 if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) { 18403 /* Delete entry from hw. */ 18404 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_del)) { 18405 BCM_XGS3_L3_MODULE_LOCK(unit); 18406 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_del) (unit, l3cfg); 18407 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18408 } 18409 BCM_IF_ERROR_RETURN(rv); 18410 } else { 18411 /* Read l3 host entry to get next hop index. */ 18412 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) { 18413 BCM_XGS3_L3_MODULE_LOCK(unit); 18414 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, l3cfg, &nh_idx); 18415 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18416 } 18417 18418 if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) && 18419 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) { 18420 rv = bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_DEL, rv); 18421 if (BCM_SUCCESS(rv)) { 18422 /* Special return value - as entry deleted from ROUTE table */ 18423 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv); 18424 } 18425 return rv; 18426 } 18427 BCM_IF_ERROR_RETURN(rv); 18428 18429 if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) { 18430 rv = _bcm_xgs3_host_ecmp_del(unit, l3cfg, nh_idx); 18431 } else { 18432 /* Delete entry from hw. */ 18433 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_del)) { 18434 BCM_XGS3_L3_MODULE_LOCK(unit); 18435 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del) (unit, l3cfg); 18436 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18437 } else { 18438 return (BCM_E_UNAVAIL); 18439 } 18440 18441 /* Release next hop index. */ 18442 if(BCM_SUCCESS(rv)) { 18443 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx)); 18444 } 18445 } 18446 } 18447 return rv; 18448 } 18449 18450 /* 18451 * Function: 18452 * _bcm_xgs3_l3_nh_intf_cmp 18453 * Purpose: 18454 * Compare interface of next hop with a given interface index. 18455 * Parameters: 18456 * unit - (IN)SOC unit number. 18457 * ifindex - (IN)Interface index. 18458 * nh_idx - (IN)Next hop index. 18459 * cmp_result- (OUT)Comparison result. 18460 * Returns: 18461 * BCM_E_XXX 18462 */ 18463 int 18464 _bcm_xgs3_l3_nh_intf_cmp(int unit, int ifindex, int nh_idx, int *cmp_result) 18465 { 18466 bcm_l3_egress_t nh_info; /* Next hop info buffer. */ 18467 18468 /* If next hop is trap to cpu - don't read nh table. */ 18469 if (nh_idx == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) { 18470 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18471 return (BCM_E_NONE); 18472 } 18473 18474 /* Get next hop entry from hw. */ 18475 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info)); 18476 18477 if (ifindex != nh_info.intf) { 18478 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18479 } else { 18480 *cmp_result = BCM_L3_CMP_EQUAL; 18481 } 18482 return (BCM_E_NONE); 18483 } 18484 18485 /* 18486 * Function: 18487 * _bcm_xgs3_l3_prefix_cmp 18488 * Purpose: 18489 * Compare prefix & vrf of l3 entry. 18490 * Parameters: 18491 * unit - (IN)SOC unit number. 18492 * pattern - (IN)Match pattern. 18493 * data1 - (IN)L3 entry. 18494 * data2 - UNUSED. 18495 * cmp_result- (OUT)Comparison result. 18496 * Returns: 18497 * BCM_E_XXX 18498 */ 18499 static INLINE int 18500 _bcm_xgs3_l3_prefix_cmp(int unit, void *pattern, 18501 void *data1, void *data2, int *cmp_result) 18502 { 18503 int idx; /* Iteration index. */ 18504 int ipv6; /* ipv6 entry flag. */ 18505 18506 _bcm_l3_cfg_t *l3_entry = (_bcm_l3_cfg_t *) data1; 18507 _bcm_l3_cfg_t *l3cfg = (_bcm_l3_cfg_t *) pattern; 18508 18509 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 18510 18511 if (l3_entry->l3c_vrf != l3cfg->l3c_vrf) { 18512 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18513 return (BCM_E_NONE); 18514 } 18515 18516 if (ipv6) { 18517 /* Compare ipv6 ip address. */ 18518 for (idx = 0; idx < BCM_IP6_ADDRLEN; idx++) { 18519 /* coverity[copy_paste_error : FALSE] */ 18520 if ((l3_entry->l3c_ip6[idx] & l3cfg->l3c_ip6_mask[idx]) != 18521 (l3cfg->l3c_ip6[idx] & l3cfg->l3c_ip6_mask[idx])) { 18522 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18523 return (BCM_E_NONE); 18524 } 18525 } 18526 } else { 18527 /* Compare ipv4 ip address. */ 18528 if ((l3_entry->l3c_ip_addr & l3cfg->l3c_ip_mask) != 18529 (l3cfg->l3c_ip_addr & l3cfg->l3c_ip_mask)) { 18530 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18531 return (BCM_E_NONE); 18532 } 18533 } 18534 *cmp_result = BCM_L3_CMP_EQUAL; 18535 return (BCM_E_NONE); 18536 18537 } 18538 18539 /* 18540 * Function: 18541 * _bcm_xgs3_l3_intf_cmp 18542 * Purpose: 18543 * Compare l3 entry interface with a given interface id. 18544 * Parameters: 18545 * unit - (IN)SOC unit number. 18546 * pattern - (IN)Match pattern (interface id & negate). 18547 * data1 - UNUSED. 18548 * data2 - (IN)Next hop index. 18549 * cmp_result- (OUT)Comparison result. 18550 * 18551 * Returns: 18552 * BCM_E_XXX 18553 */ 18554 int 18555 _bcm_xgs3_l3_intf_cmp(int unit, void *pattern, void *data1, 18556 void *data2, int *cmp_result) 18557 { 18558 _bcm_if_del_pattern_t *trv_data; /* Interface & negate combination. */ 18559 int if_cmp_result; /* Interface comparison return. */ 18560 int nh_idx = *(int *)data2; /* Next hop index. */ 18561 _bcm_l3_cfg_t *l3cfg_info = NULL; 18562 18563 trv_data = (_bcm_if_del_pattern_t *) pattern; 18564 18565 COMPILER_REFERENCE(l3cfg_info); 18566 #ifdef BCM_TRIDENT3_SUPPORT 18567 l3cfg_info = (_bcm_l3_cfg_t *) data1; 18568 if (soc_feature(unit, soc_feature_flex_flow) && 18569 (l3cfg_info->l3c_flow_handle)) { 18570 if ((l3cfg_info->l3c_flags & BCM_L3_IPMC)) { 18571 /*Flex flow L3 Entry IPMC cannot be deleted by 18572 * l3c_intf */ 18573 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18574 return BCM_E_NONE; 18575 } 18576 } 18577 #endif /* BCM_TRIDENT3_SUPPORT */ 18578 #ifdef BCM_TRIUMPH3_SUPPORT 18579 if (nh_idx == BCM_XGS3_L3_INVALID_INDEX && 18580 soc_feature(unit, soc_feature_l3_extended_host_entry)) { 18581 l3cfg_info = (_bcm_l3_cfg_t *) data1; 18582 if (l3cfg_info->l3c_intf == trv_data->l3_intf) { 18583 if_cmp_result = BCM_L3_CMP_EQUAL; 18584 } else { 18585 if_cmp_result = BCM_L3_CMP_NOT_EQUAL; 18586 } 18587 } else 18588 #endif /* BCM_TRIUMPH3_SUPPORT */ 18589 { 18590 18591 /* coverity[negative_returns : FALSE] */ 18592 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_nh_intf_cmp(unit, trv_data->l3_intf, 18593 nh_idx, &if_cmp_result)); 18594 } 18595 18596 /* Calculate final result based on negate and interface index comparison. */ 18597 if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, trv_data->negate)) { 18598 *cmp_result = BCM_L3_CMP_EQUAL; 18599 } else { 18600 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18601 } 18602 return (BCM_E_NONE); 18603 } 18604 18605 /* 18606 * Function: 18607 * _bcm_xgs3_l3_cmp_hit 18608 * Purpose: 18609 * Check l3 entry hit bit. 18610 * Parameters: 18611 * unit - (IN)SOC unit number. 18612 * pattern - (IN)Match pattern (l3cfg hit flag) 18613 * data1 - (IN)L3 entry. 18614 * data2 - UNUSED. 18615 * cmp_result- (OUT)Comparison result. 18616 * Returns: 18617 * BCM_E_XXX 18618 */ 18619 static INLINE int 18620 _bcm_xgs3_l3_cmp_hit(int unit, void *pattern, void *data1, 18621 void *data2, int *cmp_result) 18622 { 18623 uint32 flags = *(uint32 *)pattern; 18624 _bcm_l3_cfg_t *l3cfg = (_bcm_l3_cfg_t *) data1; 18625 int nh_idx = 0; 18626 18627 COMPILER_REFERENCE(nh_idx); 18628 #ifdef BCM_TRIUMPH3_SUPPORT 18629 nh_idx = *(int *)data2; 18630 if (nh_idx == BCM_XGS3_L3_INVALID_INDEX && 18631 soc_feature(unit, soc_feature_l3_extended_host_entry)) { 18632 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18633 return (BCM_E_NONE); 18634 } else 18635 #endif /* BCM_TRIUMPH3_SUPPORT */ 18636 { 18637 /* If compare function provided match the entry against pattern */ 18638 if ((flags & BCM_L3_HIT_CLEAR) && (l3cfg->l3c_flags & BCM_L3_HIT)) { 18639 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 18640 return (BCM_E_NONE); 18641 } 18642 } 18643 18644 /* Unused entry -> matches "not hit" pattern. */ 18645 *cmp_result = BCM_L3_CMP_EQUAL; 18646 return (BCM_E_NONE); 18647 } 18648 18649 /* 18650 * Function: 18651 * _bcm_xgs3_host_ent_init 18652 * Purpose: 18653 * Fill host entry for callbacks. 18654 * Parameters: 18655 * unit - (IN)SOC unit number. 18656 * l3cfg - (IN)L3 entry info. 18657 * nh_valid - (IN)Flag indicates passed next hop info is valid. 18658 * host_info - (OUT)Buffer to be filled. 18659 * Returns: 18660 * void 18661 */ 18662 void 18663 _bcm_xgs3_host_ent_init(int unit, _bcm_l3_cfg_t *l3cfg, int nh_valid, 18664 bcm_l3_host_t *host_info) 18665 { 18666 18667 /* Input parameters sanity. */ 18668 if ((NULL == host_info) || (NULL == l3cfg)) { 18669 return; 18670 } 18671 18672 /* Init host entry. */ 18673 bcm_l3_host_t_init(host_info); 18674 18675 /* Set vrf. */ 18676 host_info->l3a_vrf = l3cfg->l3c_vrf; 18677 18678 /* Set ip address. */ 18679 if (l3cfg->l3c_flags & BCM_L3_IP6) { 18680 sal_memcpy(host_info->l3a_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 18681 } else { 18682 host_info->l3a_ip_addr = l3cfg->l3c_ip_addr; 18683 } 18684 /* Set flags. */ 18685 host_info->l3a_flags = l3cfg->l3c_flags; 18686 18687 /* For devices that support the overlaid_address_range, if the RPE 18688 field is '0', the 4 bits of PRI are the upper 4 bits 18689 (of total 10 bits) of the classId, the lower 6 come from classId 18690 as usual, for rest of the cases, the classID and PRI are copied 18691 over directly. 18692 */ 18693 if (soc_feature(unit, soc_feature_overlaid_address_class) && 18694 !BCM_L3_RPE_SET(l3cfg->l3c_flags)) { 18695 host_info->l3a_lookup_class = ((l3cfg->l3c_prio & 0xF) << 6); 18696 host_info->l3a_lookup_class |= (l3cfg->l3c_lookup_class & 0x3F); 18697 } else { 18698 host_info->l3a_lookup_class = l3cfg->l3c_lookup_class; 18699 } 18700 18701 if (nh_valid) { 18702 /* Set mac address. */ 18703 sal_memcpy(host_info->l3a_nexthop_mac, l3cfg->l3c_mac_addr, 18704 sizeof(bcm_mac_t)); 18705 /* Set module id. */ 18706 host_info->l3a_modid = l3cfg->l3c_modid; 18707 /* Set port/trunk id. */ 18708 host_info->l3a_port_tgid = l3cfg->l3c_port_tgid; 18709 /* Set interface index. */ 18710 host_info->l3a_intf = l3cfg->l3c_intf; 18711 } 18712 } 18713 18714 /* 18715 * Function: 18716 * _bcm_xgs3_trvrs_flags_cmp 18717 * Purpose: 18718 * Service routine used to compare l3 entry flags with 18719 * travers input parameters and update iteration index accordingly. 18720 * Parameters: 18721 * unit - (IN)SOC unit number. 18722 * req_flags - (IN)Travers request flags. 18723 * ent_flags - (IN)Entry flags. 18724 * idx - (OUT)Traverse index. 18725 * Returns: 18726 * BCM_L3_CMP_EQUAL if flags match 18727 * BCM_L3_CMP_NOT_EQUAL otherwise. 18728 */ 18729 int 18730 _bcm_xgs3_trvrs_flags_cmp(int unit, int req_flags, int ent_flags, int *idx) 18731 { 18732 /* If protocol doesn't match skip the entry. */ 18733 if (req_flags & BCM_L3_IP6) { 18734 if (!(ent_flags & BCM_L3_IP6)) { 18735 return (BCM_L3_CMP_NOT_EQUAL); 18736 } 18737 } else if (ent_flags & BCM_L3_IP6) { 18738 #ifdef BCM_FIREBOLT_SUPPORT 18739 BCM_XGS3_INC_IF_FIREBOLT(unit, (*idx)); 18740 #endif /* BCM_FIREBOLT_SUPPORT */ 18741 return (BCM_L3_CMP_NOT_EQUAL); 18742 } 18743 18744 /* Check ipmc flag. */ 18745 if ((!(req_flags & BCM_L3_IPMC)) && (ent_flags & BCM_L3_IPMC)) { 18746 #ifdef BCM_FIREBOLT_SUPPORT 18747 if (req_flags & BCM_L3_IP6) { 18748 BCM_XGS3_INC_IF_FIREBOLT(unit, (*idx)); 18749 } 18750 #endif /* BCM_FIREBOLT_SUPPORT */ 18751 return (BCM_L3_CMP_NOT_EQUAL); 18752 } 18753 return (BCM_L3_CMP_EQUAL); 18754 } 18755 18756 /* 18757 * Function: 18758 * _bcm_xgs3_l3_del_match 18759 * Purpose: 18760 * Delete an entry in L3 table matches a certain rule. 18761 * Parameters: 18762 * unit - (IN)SOC unit number. 18763 * flags. - (IN)Generic l3 flags. 18764 * pattern - (IN)Comparison match argurment. 18765 * cmp_func - (IN)Comparison function. 18766 * notify_cb - (IN)Delete notification callback. 18767 * user_data - (IN)User provided cookie for callback. 18768 * Returns: 18769 * BCM_E_XXX 18770 */ 18771 STATIC int 18772 _bcm_xgs3_l3_del_match(int unit, int flags, void *pattern, 18773 bcm_xgs3_ent_op_cb cmp_func, 18774 bcm_l3_host_traverse_cb notify_cb, void *user_data) 18775 { 18776 _bcm_l3_cfg_t l3cfg; /* Hw entry info. */ 18777 bcm_l3_host_t info; /* Host cb buffer. */ 18778 int cmp_result; /* Compare against pattern result. */ 18779 soc_mem_t mem; /* Table memory. */ 18780 int idx_max; /* Maximum iteration index. */ 18781 int idx_min; /* Minimum iteration index. */ 18782 int nh_idx; /* Next hop index. */ 18783 int ipv6; /* IPv6/IPv4 lookup flag. */ 18784 int idx; /* Iteration index. */ 18785 int rv; /* Operation return value. */ 18786 18787 18788 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) { 18789 return (BCM_E_UNAVAIL); 18790 } 18791 /* Init iteration parameters. */ 18792 18793 /* Check Protocol. */ 18794 ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE; 18795 18796 /* Get table boundaries. */ 18797 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 18798 defined(BCM_HAWKEYE_SUPPORT) 18799 if (soc_feature(unit, soc_feature_fp_based_routing)) { 18800 /* Table is not present on this device. */ 18801 idx_min = 1; 18802 idx_max = BCM_XGS3_L3_RP_MAX_PREFIXES(unit); 18803 } else 18804 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 18805 { 18806 /* Get table memory. */ 18807 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 18808 idx_max = soc_mem_index_max(unit, mem); 18809 idx_min = soc_mem_index_min(unit, mem); 18810 } 18811 18812 /* Iterate over all the entries - delete matching ones. */ 18813 for (idx = idx_min; idx <= idx_max; idx++) { 18814 18815 sal_memset(&l3cfg, 0, sizeof(l3cfg)); 18816 /* Set protocol. */ 18817 l3cfg.l3c_flags = flags; 18818 18819 /* Get entry from hw. */ 18820 BCM_XGS3_L3_MODULE_LOCK(unit); 18821 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, NULL, idx, 18822 &l3cfg, &nh_idx); 18823 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18824 18825 /* Check for read errors & invalid entries. */ 18826 if (rv < 0) { 18827 if (rv != BCM_E_NOT_FOUND) { 18828 return rv; 18829 } 18830 continue; 18831 } 18832 18833 #if defined(BCM_TRIDENT3_SUPPORT) 18834 if (soc_feature(unit, soc_feature_flex_flow) 18835 && (l3cfg.l3c_flow_handle) 18836 && (l3cfg.l3c_flags & BCM_L3_IPMC)) { 18837 LOG_VERBOSE(BSL_LS_BCM_L3, 18838 (BSL_META_U(unit, 18839 "L3 host: IPMC do not compare the l3 entry flags."))); 18840 if (BCM_L3_CMP_EQUAL != 18841 _bcm_td3_l3_flex_entry_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 18842 continue; 18843 } 18844 } else 18845 #endif /* BCM_TRIDENT3_SUPPORT */ 18846 { 18847 /* Check read entry flags & update index accordingly. */ 18848 if (BCM_L3_CMP_EQUAL != 18849 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 18850 continue; 18851 } 18852 } 18853 18854 /* If compare function provided match the entry against pattern */ 18855 if (cmp_func) { 18856 BCM_IF_ERROR_RETURN((*cmp_func) (unit, pattern, (void *)&l3cfg, 18857 (void *)&nh_idx, &cmp_result)); 18858 /* If entry doesn't match the pattern don't delete it. */ 18859 if (BCM_L3_CMP_EQUAL != cmp_result) { 18860 continue; 18861 } 18862 } 18863 18864 /* Entry matches the rule -> delete it. */ 18865 BCM_IF_ERROR_RETURN(bcm_xgs3_l3_del(unit, &l3cfg)); 18866 18867 /* Update ECMP refernce count */ 18868 if (l3cfg.l3c_flags & BCM_L3_MULTIPATH) { 18869 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 18870 rv = _bcm_xgs3_host_ecmp_del(unit, &l3cfg, nh_idx); 18871 } 18872 } 18873 18874 /* Check if notification required. */ 18875 if (notify_cb) { 18876 /* Fill host info. */ 18877 _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info); 18878 /* Call notification callback. */ 18879 (*notify_cb) (unit, idx, &info, user_data); 18880 } 18881 } 18882 return (BCM_E_NONE); 18883 } 18884 18885 18886 /* 18887 * Function: 18888 * bcm_xgs3_l3_del_prefix 18889 * Purpose: 18890 * Delete an entry in L3 table. 18891 * Parameters: 18892 * unit - (IN)SOC unit number. 18893 * l3cfg - (IN)Pointer to memory for l3 table related information. 18894 * Returns: 18895 * BCM_E_XXX 18896 */ 18897 int 18898 bcm_xgs3_l3_del_prefix(int unit, _bcm_l3_cfg_t *l3cfg) 18899 { 18900 int rv; 18901 /* Make sure module was initialized. */ 18902 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 18903 return (BCM_E_INIT); 18904 } 18905 18906 /* Input parameters check */ 18907 if (NULL == l3cfg) { 18908 return (BCM_E_PARAM); 18909 } 18910 18911 BCM_XGS3_L3_MODULE_LOCK(unit); 18912 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match) 18913 (unit, l3cfg->l3c_flags, 18914 (void *)l3cfg, 18915 _bcm_xgs3_l3_prefix_cmp, 18916 NULL, NULL); 18917 BCM_XGS3_L3_MODULE_UNLOCK(unit); 18918 return rv; 18919 } 18920 18921 /* 18922 * Function: 18923 * bcm_xgs3_l3_del_intf 18924 * Purpose: 18925 * Delete all the entries in L3 table with nh matching a certain 18926 * interface. 18927 * Parameters: 18928 * unit - (IN)SOC unit number. 18929 * l3cfg - (IN)Pointer to memory for l3 table related information. 18930 * negate - (IN)0 means interface match; 1 means not match 18931 * Returns: 18932 * BCM_E_XXX 18933 */ 18934 int 18935 bcm_xgs3_l3_del_intf(int unit, _bcm_l3_cfg_t *l3cfg, int negate) 18936 { 18937 _bcm_if_del_pattern_t pattern; /* Interface & negate combination 18938 to be used for every l3 entry 18939 comparision. */ 18940 bcm_l3_egress_t egr; /* Egress object. */ 18941 int nh_index; /* Next hop index. */ 18942 bcm_if_t intf; /* Deleted interface id. */ 18943 int tmp_rv; /* First error occured. */ 18944 int rv; /* Operation return status. */ 18945 18946 /* Make sure module was initialized. */ 18947 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 18948 return (BCM_E_INIT); 18949 } 18950 18951 /* Input parameters check */ 18952 if (NULL == l3cfg) { 18953 return (BCM_E_PARAM); 18954 } 18955 18956 intf = l3cfg->l3c_intf; 18957 18958 /* Check l3 switching mode. */ 18959 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 18960 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 18961 BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 18962 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 18963 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 18964 } else { 18965 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 18966 } 18967 /* Get egress object information. */ 18968 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr)); 18969 /* Use egress object interface for iteration */ 18970 intf = egr.intf; 18971 } 18972 } 18973 18974 pattern.l3_intf = intf; 18975 pattern.negate = negate; 18976 18977 /* Delete all ipv4 entries matching the interface. */ 18978 tmp_rv = _bcm_xgs3_l3_del_match(unit, 0, (void *)&pattern, 18979 _bcm_xgs3_l3_intf_cmp, NULL, NULL); 18980 18981 /* Delete all ipv6 entries matching the interface. */ 18982 rv = _bcm_xgs3_l3_del_match(unit, BCM_L3_IP6, (void *)&pattern, 18983 _bcm_xgs3_l3_intf_cmp, NULL, NULL); 18984 return (tmp_rv < 0) ? tmp_rv : rv; 18985 } 18986 18987 /* 18988 * Function: 18989 * bcm_xgs3_l3_del_all 18990 * Purpose: 18991 * Delete all entries in L3 table. 18992 * Parameters: 18993 * unit - (IN)SOC unit number. 18994 * Returns: 18995 * BCM_E_XXX 18996 */ 18997 int 18998 bcm_xgs3_l3_del_all(int unit) 18999 { 19000 int tmp_rv; /* First error occured. */ 19001 int rv; /* Operation return status. */ 19002 19003 /* Make sure module was initialized. */ 19004 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19005 return (BCM_E_INIT); 19006 } 19007 19008 /* Delete all ipv4 entries. */ 19009 BCM_XGS3_L3_MODULE_LOCK(unit); 19010 tmp_rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match) 19011 (unit, 0, NULL, NULL, NULL, NULL); 19012 19013 /* Delete all ipv6 entries. */ 19014 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match) 19015 (unit, BCM_L3_IP6, NULL, NULL, NULL, NULL); 19016 19017 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19018 19019 return (tmp_rv < 0) ? tmp_rv : rv; 19020 } 19021 19022 /* 19023 * Function: 19024 * bcm_xgs3_l3_age 19025 * Purpose: 19026 * Age out the l3 entry based on L3SH, L3DH or both. 19027 * Parameters: 19028 * unit - (IN)SOC unit number. 19029 * flags - (IN)The criteria used to age or reset entry hit . 19030 * age_out - (IN)Call back routine. 19031 * user_data - (IN)User provided cookie for callback. 19032 * Returns: 19033 * BCM_E_XXX. 19034 */ 19035 int 19036 bcm_xgs3_l3_age(int unit, uint32 flags, bcm_l3_host_traverse_cb age_out, 19037 void *user_data) 19038 { 19039 int tmp_rv; /* First error occured. */ 19040 int rv; /* Operation return status. */ 19041 19042 /* Make sure module was initialized. */ 19043 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19044 return (BCM_E_INIT); 19045 } 19046 19047 /* Reset set flags to reset hit if required. */ 19048 /* SEEMS LIKE API INCONSISTENCY. */ 19049 if (flags & BCM_L3_HIT) { 19050 flags = BCM_L3_HIT_CLEAR; 19051 } 19052 19053 BCM_XGS3_L3_MODULE_LOCK(unit); 19054 /* Age all ipv4 entries. */ 19055 tmp_rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match) 19056 (unit, flags, (void *)&flags, 19057 _bcm_xgs3_l3_cmp_hit, age_out, user_data); 19058 19059 /* Age all ipv6 entries. */ 19060 flags |= BCM_L3_IP6; 19061 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match) 19062 (unit, flags, (void *)&flags, 19063 _bcm_xgs3_l3_cmp_hit, age_out, user_data); 19064 19065 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19066 19067 return (tmp_rv < 0) ? tmp_rv : rv; 19068 } 19069 19070 /* 19071 * Function: 19072 * bcm_xgs3_l3_replace 19073 * Purpose: 19074 * Replace an entry in L3 table. 19075 * Parameters: 19076 * unit - (IN)SOC unit number. 19077 * l3cfg - (IN)L3 entry information. 19078 * Returns: 19079 * BCM_E_XXX 19080 */ 19081 int 19082 bcm_xgs3_l3_replace(int unit, _bcm_l3_cfg_t *l3cfg) 19083 { 19084 _bcm_l3_cfg_t entry; /* Original l3 entry. */ 19085 int nh_idx_old; /* Original entry next hop index. */ 19086 int nh_idx_new; /* New allocated next hop index */ 19087 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 19088 19089 /* Make sure module was initialized. */ 19090 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19091 return (BCM_E_INIT); 19092 } 19093 19094 /* Input parameters check. */ 19095 if (NULL == l3cfg) { 19096 return (BCM_E_PARAM); 19097 } 19098 19099 /* Set lookup key. */ 19100 entry = *l3cfg; 19101 19102 if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) { 19103 /* ipmc_get here is to retrieve base flex counter id 19104 previous attached if any */ 19105 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) { 19106 BCM_XGS3_L3_MODULE_LOCK(unit); 19107 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, &entry); 19108 if (BCM_E_NONE == rv) { 19109 l3cfg->l3c_flex_ctr_base_id = entry.l3c_flex_ctr_base_id; 19110 l3cfg->l3c_flex_ctr_mode = entry.l3c_flex_ctr_mode; 19111 l3cfg->l3c_flex_ctr_pool = entry.l3c_flex_ctr_pool; 19112 } 19113 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19114 } else { 19115 return (BCM_E_UNAVAIL); 19116 } 19117 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) { 19118 BCM_XGS3_L3_MODULE_LOCK(unit); 19119 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg); 19120 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19121 } else { 19122 return (BCM_E_UNAVAIL); 19123 } 19124 } else { 19125 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 19126 /* Trunk id validation. */ 19127 BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags, 19128 l3cfg->l3c_port_tgid); 19129 } 19130 19131 if ((l3cfg->l3c_flags & BCM_L3_MULTIPATH) && 19132 (!soc_feature(unit, soc_feature_l3_host_ecmp_group))) { 19133 return BCM_E_UNAVAIL; 19134 } 19135 19136 /* Check if identical entry exits. */ 19137 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) { 19138 BCM_XGS3_L3_MODULE_LOCK(unit); 19139 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, &entry, 19140 &nh_idx_old); 19141 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19142 } 19143 if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) && 19144 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) { 19145 rv = bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv); 19146 if (BCM_SUCCESS(rv)) { 19147 /* Special return value - as entry Replaced within ROUTE table */ 19148 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv); 19149 } 19150 return rv; 19151 } else if (BCM_FAILURE(rv)) { 19152 return rv; 19153 } 19154 19155 if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid)) { 19156 nh_idx_new = 0; 19157 } else { 19158 /* Get next hop index. */ 19159 BCM_IF_ERROR_RETURN 19160 (_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx_new)); 19161 } 19162 19163 #ifdef BCM_TOMAHAWK_SUPPORT 19164 if (soc_feature(unit, soc_feature_extended_view_no_trunk_support) && 19165 BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx_new) && 19166 (l3cfg->l3c_flags & BCM_L3_TGID)) { 19167 return BCM_E_UNAVAIL; 19168 } 19169 #endif /* BCM_TOMAHAWK_SUPPORT */ 19170 19171 /* Write entry to hw. */ 19172 l3cfg->l3c_hw_index = entry.l3c_hw_index; /*Replacement index & flag. */ 19173 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) { 19174 BCM_XGS3_L3_MODULE_LOCK(unit); 19175 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add)(unit, l3cfg, nh_idx_new); 19176 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19177 } else { 19178 rv = BCM_E_UNAVAIL; 19179 } 19180 19181 /* Do best effort clean_up if needed. */ 19182 if (BCM_FAILURE(rv)) { 19183 if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) { 19184 /* coverity[negative_returns : FALSE] */ 19185 bcm_xgs3_ecmp_group_del(unit, nh_idx_new, 0); 19186 } else { 19187 bcm_xgs3_nh_del(unit, 0, nh_idx_new); 19188 } 19189 } else { 19190 /* Free original next hop index. */ 19191 if (entry.l3c_flags & BCM_L3_MULTIPATH) { 19192 BCM_IF_ERROR_RETURN( 19193 bcm_xgs3_ecmp_group_del(unit, nh_idx_old, 0)); 19194 } else { 19195 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx_old)); 19196 } 19197 } 19198 } 19199 return rv; 19200 } 19201 19202 /* 19203 * Function: 19204 * _bcm_xgs3_l3_traverse 19205 * Purpose: 19206 * Walk over range of entries in l3 in the table. 19207 * Parameters: 19208 * unit - SOC unit number. 19209 * flags - L3 entry flags to match during traverse. 19210 * start - First index to read. 19211 * end - Last index to read. 19212 * cb - Caller notification callback. 19213 * user_data - User cookie, which should be returned in cb. 19214 * Returns: 19215 * BCM_E_XXX 19216 */ 19217 STATIC int 19218 _bcm_xgs3_l3_traverse(int unit, int flags, uint32 start, uint32 end, 19219 bcm_l3_host_traverse_cb cb, void *user_data) 19220 { 19221 _bcm_l3_cfg_t l3cfg; /* HW entry info. */ 19222 bcm_l3_host_t info; /* Callback info buffer. */ 19223 int table_ent_size; /* Table entry size. */ 19224 int table_size; /* Number of entries in the table. */ 19225 soc_mem_t mem; /* Table memory. */ 19226 int idx_max; /* Maximum iteration index. */ 19227 int idx_min; /* Minimum iteration index. */ 19228 int nh_idx; /* Next hop index. */ 19229 int ipv6; /* Protocol IPv6/IPv4. */ 19230 int idx; /* Iterator index. */ 19231 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 19232 int total = 0; /* Total number of entries walked. */ 19233 int rv = BCM_E_NONE; /* Operation return value. */ 19234 19235 /* If no callback provided, we are done. */ 19236 if (NULL == cb) { 19237 return (BCM_E_NONE); 19238 } 19239 19240 /* Make sure required hw call is defined. */ 19241 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) { 19242 return (BCM_E_UNAVAIL); 19243 } 19244 19245 ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE; 19246 /* If table is empty -> there is nothing to read. */ 19247 if (ipv6 && (!BCM_XGS3_L3_IP6_CNT(unit))) { 19248 return (BCM_E_NONE); 19249 } 19250 if (!ipv6 && (!BCM_XGS3_L3_IP4_CNT(unit))) { 19251 return (BCM_E_NONE); 19252 } 19253 19254 /* Get table boundaries. */ 19255 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 19256 defined(BCM_HAWKEYE_SUPPORT) 19257 if (soc_feature(unit, soc_feature_fp_based_routing)) { 19258 /* Table is not present on this device. */ 19259 idx_min = 1; 19260 idx_max = BCM_XGS3_L3_RP_MAX_PREFIXES(unit); 19261 table_size = idx_max; 19262 } else 19263 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 19264 { 19265 /* Get table memory. */ 19266 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 19267 idx_max = soc_mem_index_max(unit, mem); 19268 idx_min = soc_mem_index_min(unit, mem); 19269 /* Get single entry size. */ 19270 table_ent_size = 19271 (ipv6) ? BCM_XGS3_L3_ENT_SZ(unit, v6) : BCM_XGS3_L3_ENT_SZ(unit, v4); 19272 19273 /* Dma the table - to speed up operation. */ 19274 BCM_IF_ERROR_RETURN 19275 (bcm_xgs3_l3_tbl_dma(unit, mem, table_ent_size, 19276 "l3_tbl", &l3_tbl_ptr, &table_size)); 19277 } 19278 19279 /* Input indexes sanity. */ 19280 if (start > (uint32)table_size || start > end) { 19281 return (BCM_E_NOT_FOUND); 19282 } 19283 19284 19285 /* Iterate over all the entries - show matching ones. */ 19286 for (idx = idx_min; idx <= idx_max; idx++) { 19287 /* Reset buffer before read. */ 19288 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 19289 l3cfg.l3c_flags = flags; 19290 19291 /* Get entry from hw. */ 19292 BCM_XGS3_L3_MODULE_LOCK(unit); 19293 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, l3_tbl_ptr, 19294 idx, &l3cfg, 19295 &nh_idx); 19296 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19297 19298 /* Check for read errors & invalid entries. */ 19299 if (rv < 0) { 19300 if (rv != BCM_E_NOT_FOUND) { 19301 break; 19302 } 19303 continue; 19304 } 19305 19306 /* Check read entry flags & update index accordingly. */ 19307 if (BCM_L3_CMP_EQUAL != 19308 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 19309 continue; 19310 } 19311 19312 /* Valid entry found -> increment total table_sizeer */ 19313 total++; 19314 if ((uint32)total < start) { 19315 continue; 19316 } 19317 19318 /* Don't read beyond last required index. */ 19319 if ((uint32)total > end) { 19320 break; 19321 } 19322 19323 /* Get next hop info. */ 19324 rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx); 19325 if (rv < 0) { 19326 continue; 19327 } 19328 19329 /* Fill host info. */ 19330 _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info); 19331 rv = (*cb) (unit, total, &info, user_data); 19332 #ifdef BCM_CB_ABORT_ON_ERR 19333 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 19334 break; 19335 } 19336 #endif 19337 } 19338 19339 if(l3_tbl_ptr) { 19340 soc_cm_sfree(unit, l3_tbl_ptr); 19341 } 19342 19343 /* Reset last read status. */ 19344 if (BCM_E_NOT_FOUND == rv) { 19345 rv = BCM_E_NONE; 19346 } 19347 19348 return (rv); 19349 } 19350 19351 /* 19352 * Function: 19353 * bcm_xgs3_l3_ip4_traverse 19354 * Purpose: 19355 * Walk over range of entries in l3 in the table. 19356 * Parameters: 19357 * unit - SOC unit number. 19358 * start - First index to read. 19359 * end - Last index to read. 19360 * cb - Caller notification callback. 19361 * user_data - User cookie, which should be returned in cb. 19362 * Returns: 19363 * BCM_E_XXX 19364 */ 19365 int 19366 bcm_xgs3_l3_ip4_traverse(int unit, uint32 flags, uint32 start, 19367 uint32 end, bcm_l3_host_traverse_cb cb, 19368 void *user_data) 19369 { 19370 int rv; 19371 /* Make sure module was initialized. */ 19372 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19373 return (BCM_E_INIT); 19374 } 19375 19376 BCM_XGS3_L3_MODULE_LOCK(unit); 19377 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_traverse) 19378 (unit, flags, start, end, cb, user_data); 19379 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19380 return rv; 19381 } 19382 19383 /* 19384 * Function: 19385 * bcm_xgs3_l3_ip6_traverse 19386 * Purpose: 19387 * Walk over range of entries in l3 in the table. 19388 * Parameters: 19389 * unit - SOC unit number. 19390 * start - First index to read. 19391 * end - Last index to read. 19392 * cb - Caller notification callback. 19393 * user_data - User cookie, which should be returned in cb. 19394 * Returns: 19395 * BCM_E_XXX 19396 */ 19397 int 19398 bcm_xgs3_l3_ip6_traverse(int unit, uint32 flags, uint32 start, 19399 uint32 end, bcm_l3_host_traverse_cb cb, 19400 void *user_data) 19401 { 19402 int rv; 19403 /* Make sure module was initialized. */ 19404 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19405 return (BCM_E_INIT); 19406 } 19407 19408 BCM_XGS3_L3_MODULE_LOCK(unit); 19409 rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, l3_traverse) 19410 (unit, flags, start, end, cb, user_data)); 19411 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19412 return rv; 19413 } 19414 19415 /* 19416 * Function: 19417 * _bcm_xgs3_ip_key_to_l3cfg 19418 * Purpose: 19419 * Translate l3 key to l3_cfg structure, which can be submitted for 19420 * hw lookup. 19421 * Parameters: 19422 * unit - (IN)SOC unit number. 19423 * ipkey - (IN)IP address key. 19424 * l3cfg - (IN)Lookup structure to fill. 19425 * Returns: 19426 * BCM_E_XXX 19427 */ 19428 STATIC INLINE int 19429 _bcm_xgs3_ip_key_to_l3cfg(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg) 19430 { 19431 int ipv6; /* IPV6 key. */ 19432 19433 /* Input parameters check */ 19434 if ((NULL == ipkey) || (NULL == l3cfg)) { 19435 return (BCM_E_PARAM); 19436 } 19437 19438 /* Reset destination buffer first. */ 19439 sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 19440 19441 ipv6 = (ipkey->l3k_flags & BCM_L3_IP6); 19442 19443 /* Set vrf id. */ 19444 l3cfg->l3c_vrf = ipkey->l3k_vrf; 19445 l3cfg->l3c_vid = ipkey->l3k_vid; 19446 19447 if (ipv6) { 19448 if (BCM_IP6_MULTICAST(ipkey->l3k_ip6_addr)) { 19449 /* Copy ipv6 group, source & vid. */ 19450 sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t)); 19451 sal_memcpy(l3cfg->l3c_sip6, ipkey->l3k_sip6_addr, 19452 sizeof(bcm_ip6_t)); 19453 l3cfg->l3c_vid = ipkey->l3k_vid; 19454 l3cfg->l3c_flags = (BCM_L3_IP6 | BCM_L3_IPMC); 19455 } else { 19456 /* Copy ipv6 address. */ 19457 sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t)); 19458 l3cfg->l3c_flags = BCM_L3_IP6; 19459 } 19460 } else { 19461 if (BCM_IP4_MULTICAST(ipkey->l3k_ip_addr)) { 19462 /* Copy ipv4 mcast group, source & vid. */ 19463 l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr; 19464 l3cfg->l3c_src_ip_addr = ipkey->l3k_sip_addr; 19465 l3cfg->l3c_vid = ipkey->l3k_vid; 19466 l3cfg->l3c_flags = BCM_L3_IPMC; 19467 } else { 19468 /* Copy ipv4 address . */ 19469 l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr; 19470 } 19471 } 19472 return (BCM_E_NONE); 19473 } 19474 19475 /* 19476 * Function: 19477 * _bcm_xgs3_l3cfg_to_ipkey 19478 * Purpose: 19479 * Translate ipkey to l3_cfg structure, which can be submitted for 19480 * hw lookup. 19481 * Parameters: 19482 * unit - (IN)SOC unit number. 19483 * ipkey - (IN)IP address key. 19484 * l3cfg - (IN)Lookup structure to fill. 19485 * Returns: 19486 * BCM_E_XXX 19487 */ 19488 STATIC INLINE int 19489 _bcm_xgs3_l3cfg_to_ipkey(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg) 19490 { 19491 /* Input parameters check */ 19492 if ((NULL == ipkey) || (NULL == l3cfg)) { 19493 return (BCM_E_PARAM); 19494 } 19495 19496 /* Reset destination buffer first. */ 19497 sal_memset(ipkey, 0, sizeof(bcm_l3_key_t)); 19498 19499 ipkey->l3k_vrf = l3cfg->l3c_vrf; 19500 ipkey->l3k_vid = l3cfg->l3c_vid; 19501 19502 if (l3cfg->l3c_flags & BCM_L3_IP6) { 19503 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 19504 /* Copy ipv6 group, source & vid. */ 19505 sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 19506 sal_memcpy(ipkey->l3k_sip6_addr, l3cfg->l3c_sip6, 19507 sizeof(bcm_ip6_t)); 19508 ipkey->l3k_vid = l3cfg->l3c_vid; 19509 } else { 19510 /* Copy ipv6 address. */ 19511 sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 19512 } 19513 } else { 19514 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 19515 /* Copy ipv4 mcast group, source & vid. */ 19516 ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr; 19517 ipkey->l3k_sip_addr = l3cfg->l3c_src_ip_addr; 19518 ipkey->l3k_vid = l3cfg->l3c_vid; 19519 } else { 19520 /* Copy ipv4 address . */ 19521 ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr; 19522 } 19523 } 19524 /* Store entry flags. */ 19525 ipkey->l3k_flags = l3cfg->l3c_flags; 19526 return (BCM_E_NONE); 19527 } 19528 19529 19530 /* 19531 * Function: 19532 * bcm_xgs3_l3_get_by_index 19533 * Purpose: 19534 * Get L3 entry at index 19535 * Parameters: 19536 * unit - (IN)SOC unit number. 19537 * idx - (IN)Entry index to read. 19538 * l3cfg - (OUT) decoded L3 entry 19539 * Returns: 19540 * BCM_E_XXX 19541 */ 19542 int 19543 bcm_xgs3_l3_get_by_index(int unit, int idx, _bcm_l3_cfg_t *l3cfg) 19544 { 19545 int rv = BCM_E_UNAVAIL; /* Operation return code. */ 19546 19547 /* Make sure module was initialized. */ 19548 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19549 return (BCM_E_INIT); 19550 } 19551 19552 BCM_XGS3_L3_MODULE_LOCK(unit); 19553 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 19554 /* Get multicast entry. */ 19555 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get_by_idx)) { 19556 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get_by_idx) (unit, NULL, 19557 idx, l3cfg); 19558 } 19559 } else { 19560 /* Get unicast entry. */ 19561 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) { 19562 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, NULL, idx, 19563 l3cfg, NULL); 19564 } 19565 } 19566 19567 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19568 return rv; 19569 } 19570 19571 /* 19572 * Function: 19573 * bcm_xgs3_l3_conflict_get 19574 * Purpose: 19575 * Given a IP address, return conflicts in the L3 table. 19576 * Parameters: 19577 * unit - SOC unit number. 19578 * ipkey - IP address to test conflict condition 19579 * cf_array - (OUT) arrary of conflicting addresses(at most 8) 19580 * cf_max - max number of conflicts wanted 19581 * count - (OUT) actual # of conflicting addresses 19582 * Returns: 19583 * BCM_E_XXX 19584 */ 19585 int 19586 bcm_xgs3_l3_conflict_get(int unit, bcm_l3_key_t *ipkey, 19587 bcm_l3_key_t *cf_array, int cf_max, int *cf_count) 19588 { 19589 _bcm_l3_cfg_t l3cfg; /* Lookup entry info. */ 19590 int l3_index; /* Adjusted table index. */ 19591 int bucket_primary; /* Primary bucket in bank 0. */ 19592 int bucket_secondary; /* Secondary bucket in bank 1.*/ 19593 int bucket_iterator; /* Bucket iterator. */ 19594 int idx; /* Iteration index. */ 19595 int idx_max; /* Iteration end index. */ 19596 int rv = BCM_E_UNAVAIL; /* Operation return value. */ 19597 19598 19599 /* Make sure module was initialized. */ 19600 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19601 return (BCM_E_INIT); 19602 } 19603 19604 /* Input parameters check. */ 19605 if ((NULL == ipkey) || (NULL == cf_count) || 19606 (NULL == cf_array) || (cf_max <= 0)) { 19607 return (BCM_E_PARAM); 19608 } 19609 19610 /* Make sure hw call to read ip4 entries is initialized. */ 19611 if ((!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) || 19612 (!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_bucket_get))) { 19613 return (BCM_E_UNAVAIL); 19614 } 19615 19616 *cf_count = 0; 19617 19618 /* Translate lookup key to l3cfg format. */ 19619 BCM_IF_ERROR_RETURN(_bcm_xgs3_ip_key_to_l3cfg(unit, ipkey, &l3cfg)); 19620 19621 /* Ge. */ 19622 19623 BCM_XGS3_L3_MODULE_LOCK(unit); 19624 rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, l3_bucket_get)(unit, &l3cfg, 19625 &bucket_primary, 19626 &bucket_secondary)); 19627 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19628 BCM_IF_ERROR_RETURN(rv); 19629 19630 /* 19631 * Loop through all L3_BUCKET_SIZE entries in this bucket 19632 */ 19633 for (bucket_iterator = 0; bucket_iterator < 2; bucket_iterator++) { 19634 idx = (bucket_iterator) ? bucket_secondary : bucket_primary; 19635 idx_max = idx + SOC_L3X_BUCKET_SIZE(unit)/2; 19636 19637 for (;idx < idx_max && (*cf_count < cf_max); idx++) { 19638 /* Reset entry flags so we alwayes read ipv4 entry. */ 19639 l3cfg.l3c_flags = 0; 19640 19641 BCM_XGS3_L3_MODULE_LOCK(unit); 19642 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, NULL, idx, 19643 &l3cfg, NULL); 19644 BCM_XGS3_L3_MODULE_UNLOCK(unit); 19645 if (rv == BCM_E_NOT_FOUND) { 19646 continue; 19647 } 19648 if (BCM_FAILURE(rv)) { 19649 return rv; 19650 } 19651 19652 /* Reread entry if it is not ipv4 unicast one. */ 19653 if (l3cfg.l3c_flags & (BCM_L3_IP6 | BCM_L3_IPMC)) { 19654 l3_index = idx; 19655 #ifdef BCM_FIREBOLT_SUPPORT 19656 BCM_XGS3_FB_IPMC_IP6_IDX_CALC(unit, idx, l3_index, l3cfg.l3c_flags); 19657 #endif /* BCM_FIREBOLT_SUPPORT */ 19658 BCM_IF_ERROR_RETURN 19659 (bcm_xgs3_l3_get_by_index(unit, l3_index, &l3cfg)); 19660 } 19661 19662 /* Fill conflicting entry in key format. */ 19663 _bcm_xgs3_l3cfg_to_ipkey(unit, cf_array + (*cf_count), &l3cfg); 19664 if ((++(*cf_count)) >= cf_max) { 19665 return (BCM_E_NONE); 19666 } 19667 } 19668 } 19669 return (BCM_E_NONE); 19670 } 19671 19672 /* 19673 * Function: 19674 * bcm_xgs3_l3_info 19675 * Purpose: 19676 * Get the status of hardware. 19677 * Parameters: 19678 * unit - (IN)SOC unit number 19679 * l3info - (OUT)Structure to fill with L3 related information. 19680 * Returns: 19681 * BCM_E_XXX. 19682 */ 19683 int 19684 bcm_xgs3_l3_info(int unit, bcm_l3_info_t *l3info) 19685 { 19686 #ifdef BCM_KATANA_SUPPORT 19687 int ipv6_128b_used = 0; 19688 soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit); 19689 #endif 19690 19691 #ifdef BCM_TRIUMPH_SUPPORT 19692 soc_mem_t mem; 19693 BCM_IF_ERROR_RETURN(_bcm_tr_l3_defip_mem_get(unit, 0, 0, &mem)); 19694 #endif /* BCM_TRIUMPH_SUPPORT */ 19695 19696 /* Make sure module was initialized. */ 19697 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 19698 return (BCM_E_INIT); 19699 } 19700 19701 /* Input parameters check. */ 19702 if (NULL == l3info) { 19703 return (BCM_E_PARAM); 19704 } 19705 19706 #ifdef BCM_KATANA_SUPPORT 19707 if (SOC_IS_KATANA(unit) && LOG_CHECK(BSL_LS_BCM_L3 | BSL_INFO)) { 19708 _bcm_kt_l3_info_dump(unit); 19709 } 19710 #endif 19711 19712 l3info->l3info_max_vrf = SOC_VRF_MAX(unit); 19713 l3info->l3info_used_vrf = -1; 19714 l3info->l3info_max_intf = BCM_XGS3_L3_IF_MAX_COUNT(unit); 19715 l3info->l3info_max_intf_group = SOC_INTF_CLASS_MAX(unit); 19716 l3info->l3info_max_l3 = BCM_XGS3_L3_TBL_SIZE(unit); 19717 #ifdef BCM_TRIUMPH3_SUPPORT 19718 if (SOC_IS_TRIUMPH3(unit) && 19719 (soc_feature(unit, soc_feature_esm_support))) { 19720 l3info->l3info_max_l3 += 19721 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, v4_esm)); 19722 } 19723 #endif 19724 l3info->l3info_max_defip = BCM_XGS3_L3_DEFIP_TBL_SIZE(unit); 19725 #ifdef BCM_TRIUMPH2_SUPPORT 19726 l3info->l3info_max_ecmp_groups = BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); 19727 #endif 19728 l3info->l3info_max_ecmp = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 19729 l3info->l3info_occupied_intf = BCM_XGS3_L3_IF_COUNT(unit); 19730 l3info->l3info_max_host = l3info->l3info_max_l3; 19731 l3info->l3info_max_lpm_block = 0; 19732 l3info->l3info_used_lpm_block = 0; 19733 19734 #ifdef BCM_TRIUMPH_SUPPORT 19735 if ((soc_feature(unit, soc_feature_esm_support)) && (L3_DEFIPm != mem)) { 19736 /* ESM - One route per entry */ 19737 l3info->l3info_max_route = l3info->l3info_max_defip; 19738 } else 19739 #endif /* BCM_TRIUMPH_SUPPORT */ 19740 { /* Two routes per entry */ 19741 l3info->l3info_max_route = l3info->l3info_max_defip << 1; 19742 #ifdef BCM_TOMAHAWK2_SUPPORT 19743 if (soc_feature(unit, soc_feature_half_of_l3_defip_ipv4_capacity)) { 19744 l3info->l3info_max_route >>= 1; 19745 } 19746 #endif 19747 if (soc_feature(unit, soc_feature_defip_2_tcams_with_separate_rpf)) { 19748 l3info->l3info_max_route = (R2P_V4_MAX << 1); 19749 } 19750 19751 if (soc_feature(unit, soc_feature_lpm_atomic_write)) { 19752 int reserved_entries; 19753 19754 BCM_IF_ERROR_RETURN(soc_lpm_reserved_route_get(unit, 19755 &reserved_entries, NULL, NULL)); 19756 l3info->l3info_max_route -= reserved_entries; 19757 } 19758 #ifdef BCM_TRIDENT2_SUPPORT 19759 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_IPV4m)) { 19760 if (soc_mem_index_count(unit, L3_DEFIP_ALPM_IPV4m)) { 19761 l3info->l3info_max_route = 19762 soc_mem_index_count(unit, L3_DEFIP_ALPM_IPV4m); 19763 } 19764 } 19765 #ifdef ALPM_ENABLE 19766 if (soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) && 19767 SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_LEVEL3m)) { 19768 if (soc_mem_index_count(unit, L3_DEFIP_ALPM_LEVEL3m)) { 19769 l3info->l3info_max_route = ALPM_EPB_MAX * \ 19770 soc_mem_index_count(unit, L3_DEFIP_ALPM_LEVEL3m); 19771 } 19772 } 19773 #endif 19774 #endif 19775 } 19776 19777 #if defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_GREYHOUND_SUPPORT) 19778 if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) || 19779 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) { 19780 /* One route per entry */ 19781 l3info->l3info_max_route = l3info->l3info_max_defip; 19782 } 19783 #endif /* BCM_HURRICANE2_SUPPORT||BCM_GREYHOUND_SUPPORT */ 19784 19785 #ifdef BCM_FIREBOLT_SUPPORT 19786 if (SOC_IS_FBX(unit)) { 19787 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 19788 defined(BCM_HAWKEYE_SUPPORT) 19789 if (soc_feature(unit, soc_feature_fp_based_routing)) { 19790 l3info->l3info_max_route = l3info->l3info_max_defip; 19791 l3info->l3info_occupied_l3 = 19792 BCM_XGS3_L3_IP4_CNT(unit) + BCM_XGS3_L3_IP6_CNT(unit); 19793 l3info->l3info_occupied_defip = 19794 BCM_XGS3_L3_DEFIP_IP4_CNT(unit) + BCM_XGS3_L3_DEFIP_IP6_CNT(unit); 19795 } else 19796 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 19797 { 19798 if (SOC_IS_TR_VL(unit)) { 19799 l3info->l3info_occupied_l3 = BCM_XGS3_L3_IP4_CNT(unit) + 19800 2 * BCM_XGS3_L3_IP4_IPMC_CNT(unit) + 19801 2 * BCM_XGS3_L3_IP6_CNT(unit) + 19802 4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit); 19803 19804 l3info->l3info_used_host_ip4 = BCM_XGS3_L3_IP4_CNT(unit) + 19805 2 * BCM_XGS3_L3_IP4_IPMC_CNT(unit); 19806 l3info->l3info_used_host_ip6 = 19807 2 * BCM_XGS3_L3_IP6_CNT(unit) + 19808 4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit); 19809 } else { 19810 l3info->l3info_occupied_l3 = BCM_XGS3_L3_IP4_CNT(unit) + 19811 BCM_XGS3_L3_IP4_IPMC_CNT(unit) + 19812 2 * BCM_XGS3_L3_IP6_CNT(unit) + 19813 4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit); 19814 19815 l3info->l3info_used_host_ip4 = BCM_XGS3_L3_IP4_CNT(unit) + 19816 BCM_XGS3_L3_IP4_IPMC_CNT(unit); 19817 l3info->l3info_used_host_ip6 = 19818 2 * BCM_XGS3_L3_IP6_CNT(unit) + 19819 4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit); 19820 } 19821 19822 /* Entries occupied in L3_DEFIPm excluding L3_DEFIP_128m */ 19823 #if defined(BCM_KATANA_SUPPORT) 19824 if (SOC_IS_KATANA(unit)) { 19825 19826 if (lpm_ipv6_info->ipv6_128b.depth > 0) { 19827 ipv6_128b_used = _bcm_kt_defip_pair128_used_count_get(unit); 19828 } 19829 l3info->l3info_occupied_defip = 19830 BCM_XGS3_L3_DEFIP_IP4_CNT(unit) 19831 + ((BCM_XGS3_L3_DEFIP_IP6_CNT(unit) - ipv6_128b_used) * 2); 19832 } else 19833 #endif 19834 #if defined(BCM_TRIDENT2_SUPPORT) 19835 if (soc_feature(unit, soc_feature_td2_style_l3_defip_cnt)) { 19836 int defip_128_used = 0; 19837 if (BCM_DEFIP_PAIR128(unit)) { 19838 defip_128_used = BCM_DEFIP_PAIR128_USED_COUNT(unit); 19839 } 19840 l3info->l3info_occupied_defip = BCM_XGS3_L3_DEFIP_IP4_CNT(unit) + 19841 (BCM_XGS3_L3_DEFIP_IP6_CNT(unit) - defip_128_used) * 2; 19842 } else 19843 #endif 19844 { 19845 l3info->l3info_occupied_defip = BCM_XGS3_L3_DEFIP_IP4_CNT(unit) + 19846 (BCM_XGS3_L3_DEFIP_IP6_CNT(unit) * 2); 19847 } 19848 } 19849 } 19850 #endif /* BCM_FIREBOLT_SUPPORT */ 19851 l3info->l3info_occupied_host = l3info->l3info_occupied_l3; 19852 l3info->l3info_occupied_route = l3info->l3info_occupied_defip; 19853 l3info->l3info_max_nexthop = BCM_XGS3_L3_NH_TBL_SIZE(unit); 19854 l3info->l3info_used_nexthop = BCM_XGS3_L3_NH_CNT(unit); 19855 19856 if(!soc_feature(unit, soc_feature_no_tunnel)) { 19857 l3info->l3info_max_tunnel_init = BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit); 19858 l3info->l3info_used_tunnel_init = BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused; 19859 if (soc_mem_is_valid(unit, L3_TUNNELm)) { 19860 l3info->l3info_max_tunnel_term = soc_mem_index_count(unit, L3_TUNNELm); 19861 l3info->l3info_used_tunnel_term = soc_tunnel_term_used_get(unit); 19862 } 19863 } else { 19864 if (soc_feature(unit, soc_feature_vxlan_lite)) { 19865 l3info->l3info_max_tunnel_init = 19866 BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit); 19867 l3info->l3info_used_tunnel_init = 19868 BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused; 19869 l3info->l3info_max_tunnel_term = 0; 19870 l3info->l3info_used_tunnel_term = 0; 19871 } else { 19872 l3info->l3info_max_tunnel_init = 0; 19873 l3info->l3info_used_tunnel_init = 0; 19874 l3info->l3info_max_tunnel_term = 0; 19875 l3info->l3info_used_tunnel_term = 0; 19876 } 19877 } 19878 19879 return (BCM_E_NONE); 19880 } 19881 19882 /* 19883 * Function: 19884 * _bcm_xgs3_lpm_get_nh_info 19885 * Purpose: 19886 * Fill next hop info to lpm entry. 19887 * Parameters: 19888 * unit - (IN)SOC unit number. 19889 * lpm_cfg- (IN)Buffer to fill defip information. 19890 * nh_idx - (IN)Next hop index. 19891 * Returns: 19892 * BCM_E_XXX 19893 */ 19894 STATIC int 19895 _bcm_xgs3_lpm_get_nh_info(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_idx) 19896 { 19897 bcm_l3_egress_t nh_info; /* Next hop info buffer. */ 19898 19899 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 19900 if (soc_feature(unit, soc_feature_ipmc_defip) && 19901 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 19902 19903 return BCM_E_NONE; 19904 } 19905 #endif 19906 /* In egress switching mode - set egress object id only. */ 19907 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 19908 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 19909 lpm_cfg->defip_intf = nh_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 19910 } else { 19911 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info)); 19912 if (nh_info.encap_id > 0 && 19913 nh_info.encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) { 19914 lpm_cfg->defip_intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 19915 } else { 19916 #ifdef BCM_RIOT_SUPPORT 19917 if (BCMI_RIOT_IS_ENABLED(unit) && 19918 (_bcm_vp_is_vfi_type(unit, nh_info.port))) { 19919 lpm_cfg->defip_intf = 19920 nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 19921 } else 19922 #endif 19923 { 19924 lpm_cfg->defip_intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit); 19925 } 19926 } 19927 } 19928 return (BCM_E_NONE); 19929 } 19930 19931 /* If next hop is trap to cpu - don't read nh table. */ 19932 if (nh_idx == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) { 19933 /* Set flags to bridge to cpu. */ 19934 lpm_cfg->defip_flags |= BCM_L3_DEFIP_LOCAL; 19935 /* Set interface index to last one in the table. */ 19936 lpm_cfg->defip_intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit); 19937 /* Set module id to a local module. */ 19938 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &lpm_cfg->defip_modid)); 19939 /* Set port to be a cpu port. */ 19940 lpm_cfg->defip_port_tgid = CMIC_PORT(unit); 19941 /* No vlan/interface info. */ 19942 lpm_cfg->defip_vid = 0; 19943 lpm_cfg->defip_tunnel = 0; 19944 /* Reset mac address. */ 19945 sal_memset(lpm_cfg->defip_mac_addr, 0, sizeof(bcm_mac_t)); 19946 return (BCM_E_NONE); 19947 } 19948 19949 /* Get next hop entry from hw. */ 19950 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info)); 19951 19952 /* Fill next hop info to l3 entry. */ 19953 if (nh_info.flags & BCM_L3_TGID) { /* Trunk */ 19954 lpm_cfg->defip_flags |= BCM_L3_TGID; 19955 } 19956 /* Set module id. */ 19957 lpm_cfg->defip_modid = nh_info.module; 19958 /* Set trunk/port info. */ 19959 lpm_cfg->defip_port_tgid = 19960 (nh_info.flags & BCM_L3_TGID) ? nh_info.trunk : nh_info.port; 19961 /* Set interface index. */ 19962 lpm_cfg->defip_intf = nh_info.intf; 19963 /* Set physical address. */ 19964 sal_memcpy(lpm_cfg->defip_mac_addr, nh_info.mac_addr, sizeof(bcm_mac_t)); 19965 19966 /* Get tunnel id info. */ 19967 BCM_IF_ERROR_RETURN 19968 (_bcm_xgs3_l3_get_tunnel_id(unit, nh_info.intf, 19969 &lpm_cfg->defip_tunnel)); 19970 #ifdef BCM_FIREBOLT_SUPPORT 19971 if (SOC_IS_FBX(unit)) { 19972 lpm_cfg->defip_vid = nh_info.vlan; 19973 } 19974 #endif /* BCM_FIREBOLT_SUPPORT */ 19975 return (BCM_E_NONE); 19976 } 19977 19978 /* 19979 * Function: 19980 * _bcm_xgs3_defip_set_route_info 19981 * Purpose: 19982 * Fill user callbacks route info. 19983 * Parameters: 19984 * unit - (IN)SOC unit number. 19985 * lpm_cfg - (IN)Defip information. 19986 * route_info - (OUT)Buffer to fill route info. 19987 * nh_idx - (IN)Next hop index. 19988 * Returns: 19989 * BCM_E_XXX 19990 */ 19991 STATIC int 19992 _bcm_xgs3_defip_set_route_info(int unit, _bcm_defip_cfg_t *lpm_cfg, 19993 bcm_l3_route_t *route_info, int nh_idx) 19994 { 19995 _bcm_defip_cfg_t lpm_temp; /* Avoid modifying original lpm entry.*/ 19996 int ipv6; /* IPv6 entry indicator. */ 19997 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 19998 ipmc_1_entry_t ipmc_1_entry; 19999 bcm_ipmc_addr_t ipmc; 20000 #endif 20001 #if defined(BCM_TRIDENT3_SUPPORT) 20002 int i = 0; 20003 #endif /* BCM_TRIDENT3_SUPPORT */ 20004 20005 /* Input parameters check. */ 20006 if (NULL == lpm_cfg) { 20007 return (BCM_E_PARAM); 20008 } 20009 20010 lpm_temp = *lpm_cfg; 20011 ipv6 = (lpm_temp.defip_flags & BCM_L3_IP6); 20012 20013 /* Init route entry. */ 20014 bcm_l3_route_t_init(route_info); 20015 20016 /* Set vrf id. */ 20017 route_info->l3a_vrf = lpm_temp.defip_vrf; 20018 20019 if (ipv6) { 20020 /* Set ipv6 address. */ 20021 sal_memcpy(route_info->l3a_ip6_net, lpm_temp.defip_ip6_addr, 20022 sizeof(bcm_ip6_t)); 20023 20024 /* Set subnet mask. */ 20025 bcm_ip6_mask_create(route_info->l3a_ip6_mask, lpm_temp.defip_sub_len); 20026 20027 /* Set entry flags to ipv6 */ 20028 route_info->l3a_flags = BCM_L3_IP6; 20029 } else { 20030 /* Set ipv4 address. */ 20031 route_info->l3a_subnet = lpm_temp.defip_ip_addr; 20032 20033 /* Set subnet mask. */ 20034 route_info->l3a_ip_mask = 20035 BCM_IP4_MASKLEN_TO_ADDR(lpm_temp.defip_sub_len); 20036 20037 /* Reset entry flags */ 20038 route_info->l3a_flags = 0; 20039 } 20040 20041 #ifdef BCM_TRIDENT3_SUPPORT 20042 if ((soc_feature(unit, soc_feature_flex_flow)) && 20043 (lpm_temp.defip_num_of_fields)) { 20044 for (i = 0; 20045 i < lpm_temp.defip_num_of_fields; 20046 i++) { 20047 route_info->logical_fields[i].id = 20048 lpm_temp.defip_logical_fields[i].id; 20049 route_info->logical_fields[i].value = 20050 lpm_temp.defip_logical_fields[i].value; 20051 route_info->num_of_fields = lpm_temp.defip_num_of_fields; 20052 } 20053 } 20054 #endif /* BCM_TRIDENT3_SUPPORT */ 20055 /* Priority & Class ID */ 20056 if (soc_feature(unit, soc_feature_overlaid_address_class) && 20057 !BCM_L3_RPE_SET(lpm_temp.defip_flags)) { 20058 route_info->l3a_lookup_class = ((lpm_temp.defip_prio & 0xF) << 6); 20059 route_info->l3a_lookup_class |= (lpm_temp.defip_lookup_class & 0x3F); 20060 } else { 20061 route_info->l3a_lookup_class = lpm_temp.defip_lookup_class; 20062 route_info->l3a_pri = lpm_temp.defip_prio; 20063 } 20064 20065 /* Fill next hop info Or multicast route Info if needed. */ 20066 if ((nh_idx != BCM_XGS3_L3_INVALID_INDEX) || 20067 (lpm_temp.defip_flags & BCM_L3_IPMC)) { 20068 20069 /* Entry flags. */ 20070 route_info->l3a_flags |= lpm_temp.defip_flags; 20071 20072 /* Fill Multicast route info if needed*/ 20073 if (lpm_temp.defip_flags & BCM_L3_IPMC) { 20074 route_info->l3a_ipmc_flags |= lpm_temp.defip_ipmc_flags; 20075 route_info->l3a_expected_intf = lpm_temp.defip_expected_intf; 20076 route_info->l3a_rp = lpm_temp.defip_l3a_rp; 20077 route_info->l3a_mc_group = lpm_temp.defip_mc_group; 20078 } 20079 if (nh_idx != BCM_XGS3_L3_INVALID_INDEX) { 20080 /* Get next hop info. */ 20081 BCM_IF_ERROR_RETURN(_bcm_xgs3_lpm_get_nh_info(unit, &lpm_temp, nh_idx)); 20082 } 20083 20084 /* Interface index/Egress object id. */ 20085 route_info->l3a_intf = lpm_temp.defip_intf; 20086 20087 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20088 /* If it is a Multicast route entry, get the source port 20089 * information 20090 */ 20091 if (soc_feature(unit, soc_feature_ipmc_defip) && 20092 soc_mem_is_valid(unit, L3_IPMC_1m) && 20093 lpm_cfg->defip_flags & BCM_L3_IPMC) { 20094 sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t)); 20095 BCM_IF_ERROR_RETURN 20096 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, 20097 lpm_temp.defip_mc_group, &ipmc_1_entry)); 20098 BCM_IF_ERROR_RETURN 20099 (_tr2_ipmc_glp_get(unit, &ipmc, &ipmc_1_entry)); 20100 if (!(ipmc.flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) { 20101 BCM_IF_ERROR_RETURN( 20102 _bcm_esw_l3_gport_construct(unit, ipmc.port_tgid, 20103 ipmc.mod_id, 20104 ipmc.port_tgid, 20105 ipmc.ts ? BCM_L3_TGID : 0, 20106 &(route_info->l3a_expected_src_gport))); 20107 } else { 20108 route_info->l3a_ipmc_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 20109 } 20110 } 20111 #endif 20112 /* Don't fill additional info in egress switching mode. */ 20113 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 20114 return (BCM_E_NONE); 20115 } 20116 20117 /* Trunk */ 20118 if (lpm_temp.defip_flags & BCM_L3_TGID) { 20119 route_info->l3a_flags |= BCM_L3_TGID; 20120 } 20121 /* Module id. */ 20122 route_info->l3a_modid = lpm_temp.defip_modid; 20123 /* Port/Trunk info. */ 20124 route_info->l3a_port_tgid = lpm_temp.defip_port_tgid; 20125 /* Vlan id. */ 20126 route_info->l3a_vid = lpm_temp.defip_vid; 20127 /* Mac address. */ 20128 sal_memcpy(route_info->l3a_nexthop_mac, lpm_temp.defip_mac_addr, 20129 sizeof(bcm_mac_t)); 20130 } 20131 20132 return (BCM_E_NONE); 20133 } 20134 20135 /* 20136 * Function: 20137 * _bcm_xgs3_lpm_call_user_cb 20138 * Purpose: 20139 * Fill user callbacks route info and call user callback. 20140 * Parameters: 20141 * unit - (IN)SOC unit number. 20142 * trv_data - (IN)User cookie & callback routine. 20143 * lpm_cfg - (IN)Defip information. 20144 * nh_idx - next hop index. 20145 * Returns: 20146 * BCM_E_XXX 20147 */ 20148 STATIC int 20149 _bcm_xgs3_lpm_call_user_cb(int unit, _bcm_l3_trvrs_data_t *trv_data, 20150 _bcm_defip_cfg_t *lpm_cfg, int nh_idx) 20151 { 20152 bcm_l3_route_t route_info; 20153 20154 /* Fill route info. */ 20155 BCM_IF_ERROR_RETURN 20156 (_bcm_xgs3_defip_set_route_info(unit, lpm_cfg, &route_info, nh_idx)); 20157 20158 /* Call user notification routine. */ 20159 if (NULL != trv_data->defip_cb) { 20160 (*trv_data->defip_cb) (unit, lpm_cfg->defip_index, 20161 &route_info, trv_data->cookie); 20162 } 20163 return (BCM_E_NONE); 20164 } 20165 20166 /* 20167 * Function: 20168 * bcm_xgs3_max_ecmp_set 20169 * Purpose: 20170 * Set the max allowable number of ECMP paths that is less 20171 * than the hardware allowed value 20172 * Parameters: 20173 * unit - (IN) SOC device unit number 20174 * max_paths - (IN) Maximum number of ecmp paths. 20175 * Returns: 20176 * BCM_E_XXX 20177 */ 20178 int 20179 bcm_xgs3_max_ecmp_set(int unit, int max_paths) 20180 { 20181 int rv = BCM_E_NONE; /* Operation return value. */ 20182 20183 if (!SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ecmp)) || 20184 !soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ecmp))) { 20185 return (BCM_E_UNAVAIL); 20186 } 20187 20188 if (BCM_XGS3_L3_ECMP_IN_USE(unit)) { 20189 LOG_ERROR(BSL_LS_BCM_L3, 20190 (BSL_META_U(unit, 20191 "ECMP already in use, max path can't be reset\n"))); 20192 return (BCM_E_BUSY); 20193 } 20194 20195 /* Max paths sanity. */ 20196 if (max_paths < 2 || max_paths > BCM_XGS3_L3_ECMP_MAX(unit)) { 20197 return (BCM_E_PARAM); 20198 } 20199 20200 #ifdef BCM_TOMAHAWK_SUPPORT 20201 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) { 20202 int _max_ecmp_paths = 1024; 20203 if (!(soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 20204 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 20205 ecmp_mode_hierarchical) && (max_paths > 128)) { 20206 return (BCM_E_PARAM); 20207 } 20208 #ifdef BCM_TOMAHAWK3_SUPPORT 20209 if (soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) { 20210 _max_ecmp_paths = 4096; 20211 } 20212 #endif 20213 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_single) && 20214 (max_paths > _max_ecmp_paths)) { 20215 return (BCM_E_PARAM); 20216 } 20217 } 20218 /* In the low latency mode, max value of max paths is 128 */ 20219 if (soc_feature(unit, soc_feature_fast_ecmp)) { 20220 if (max_paths > 128) { 20221 return (BCM_E_PARAM); 20222 } 20223 } 20224 #endif /* BCM_TOMAHAWK_SUPPORT */ 20225 20226 /* Free original groups array. */ 20227 sal_free(BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr); 20228 BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr = NULL; 20229 20230 /* Set maximum number of paths. */ 20231 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = max_paths; 20232 20233 /* Reinitialize ecmp group table. */ 20234 rv = _bcm_xgs3_l3_ecmp_group_init(unit); 20235 20236 return rv; 20237 } 20238 20239 /* 20240 * Function: 20241 * bcm_xgs3_max_ecmp_get 20242 * Purpose: 20243 * Get the max allowable number of ECMP paths. 20244 * Parameters: 20245 * unit - (IN) SOC device unit number 20246 * max_paths - (IN) Maximum number of ecmp paths. 20247 * Returns: 20248 * BCM_E_XXX 20249 */ 20250 int 20251 bcm_xgs3_max_ecmp_get(int unit, int *max_paths) 20252 { 20253 #if defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE_SUPPORT) 20254 if ( SOC_IS_HAWKEYE(unit) || SOC_IS_HURRICANE(unit) || 20255 SOC_IS_HURRICANE2(unit)) { 20256 return (BCM_E_UNAVAIL); 20257 } 20258 #endif 20259 if (soc_feature(unit, soc_feature_l3_no_ecmp)) { 20260 return (BCM_E_UNAVAIL); 20261 } 20262 20263 if (NULL == max_paths) { 20264 return (BCM_E_PARAM); 20265 } 20266 20267 /* Set maximum number of paths. */ 20268 *max_paths = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 20269 20270 return (BCM_E_NONE); 20271 } 20272 20273 /* 20274 * Function: 20275 * _bcm_xgs3_defip_mpath_add 20276 * Purpose: 20277 * Update multipath route in the hw. 20278 * Parameters: 20279 * unit - (IN)SOC unit number. 20280 * lpm_cfg - (IN)Route data. 20281 * ecmp_group_id - (IN)New Ecmp group id. 20282 * Returns: 20283 * BCM_E_XXX 20284 */ 20285 STATIC int 20286 _bcm_xgs3_defip_mpath_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int ecmp_group_id) 20287 { 20288 int ecmp_index; /* Index in ecmp table. */ 20289 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 20290 20291 /* Ecmp table index for the allocated group. */ 20292 ecmp_index = ecmp_group_id; 20293 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 20294 ecmp_index = ecmp_group_id * BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 20295 } 20296 20297 /* Set zero based number of paths to lpm entry. */ 20298 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_id, 20299 &lpm_cfg->defip_ecmp_count); 20300 if (rv < 0) { 20301 return rv; 20302 } 20303 lpm_cfg->defip_ecmp_count--; 20304 20305 /* Add route to the hw. */ 20306 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_add)) { 20307 BCM_XGS3_L3_MODULE_LOCK(unit); 20308 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_add) (unit, lpm_cfg, ecmp_index); 20309 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20310 } 20311 /* Decrement group reference count if operation failed. */ 20312 if (rv < 0) { 20313 bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0); 20314 return rv; 20315 } 20316 20317 return (BCM_E_NONE); 20318 } 20319 20320 /* 20321 * Function: 20322 * _bcm_xgs3_defip_ecmp_write 20323 * Purpose: 20324 * Write route with multipaths to the hw. 20325 * Parameters: 20326 * unit - (IN)SOC unit number. 20327 * lpm_cfg - (IN)Route data. 20328 * ecmp_group - (IN)Ecmp group. 20329 * ecmp_count - (IN)Count of next hop indexes in ecmp group. 20330 * Returns: 20331 * BCM_E_XXX 20332 */ 20333 STATIC int 20334 _bcm_xgs3_defip_ecmp_write(int unit, _bcm_defip_cfg_t *lpm_cfg, uint32 ecmp_flags, 20335 int *ecmp_group, int ecmp_count) 20336 { 20337 int ecmp_group_id; /* New ecmp group index. */ 20338 int ecmp_index; /* Index in ecmp table. */ 20339 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 20340 20341 /* Add ecmp group to the hw. */ 20342 rv = _bcm_xgs3_ecmp_group_add(unit, 0, ecmp_flags, ecmp_count, 20343 0, 20344 ecmp_group, 20345 &ecmp_group_id, 20346 ecmp_count, NULL); 20347 BCM_IF_ERROR_RETURN(rv); 20348 20349 /* Ecmp table index for the allocated group. */ 20350 ecmp_index = ecmp_group_id; 20351 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 20352 ecmp_index = ecmp_group_id * BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 20353 } 20354 20355 /* Set zero based number of paths to lpm entry. */ 20356 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, 20357 ecmp_group_id, 20358 &lpm_cfg->defip_ecmp_count); 20359 if (rv < 0) { 20360 return rv; 20361 } 20362 lpm_cfg->defip_ecmp_count--; 20363 20364 /* Add route to the hw. */ 20365 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_add)) { 20366 BCM_XGS3_L3_MODULE_LOCK(unit); 20367 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_add) (unit, lpm_cfg, ecmp_index); 20368 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20369 } 20370 20371 if (BCM_FAILURE(rv)) { 20372 bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0); 20373 return rv; 20374 } 20375 return (BCM_E_NONE); 20376 } 20377 20378 /* 20379 * Function: 20380 * _bcm_xgs3_defip_ecmp_add 20381 * Purpose: 20382 * IP route with multipaths to DEFIP table 20383 * Parameters: 20384 * unit - (IN)SOC unit number. 20385 * lpm_cfg - (IN)Route data. 20386 * ecmp_group_idx - (IN)Ecmp group index. 20387 * nh_index - (IN)Next hop index. 20388 * Returns: 20389 * BCM_E_XXX 20390 */ 20391 STATIC int 20392 _bcm_xgs3_defip_ecmp_add(int unit, _bcm_defip_cfg_t *lpm_cfg, 20393 int ecmp_group_idx, int nh_index) 20394 { 20395 int ecmp_max_count = 0; /* Maximum next hop count in the group.*/ 20396 int ecmp_count = 0; /* Next hop count in the group. */ 20397 uint32 ecmp_flags = 0; /* ECMP group flags */ 20398 int *ecmp_grp; /* Ecmp group from hw. */ 20399 int rv; /* Operation return status. */ 20400 20401 /* Allocate ecmp group buffer. */ 20402 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 20403 20404 /*If ecmp group exists just update next hops set. */ 20405 if (BCM_XGS3_L3_INVALID_INDEX != ecmp_group_idx) { 20406 20407 /* Extract maximum ecmp group size. */ 20408 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &ecmp_max_count); 20409 if (rv < 0) { 20410 sal_free(ecmp_grp); 20411 return rv; 20412 } 20413 20414 #if defined(BCM_TOMAHAWK3_SUPPORT) 20415 if ((ecmp_group_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) && 20416 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 20417 ecmp_mode_hierarchical)) { 20418 ecmp_flags |= BCM_L3_ECMP_OVERLAY; 20419 } 20420 #endif 20421 20422 /* Read ecmp group members from hw. */ 20423 rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_idx, 20424 ecmp_grp, &ecmp_count); 20425 if (BCM_FAILURE(rv)) { 20426 sal_free(ecmp_grp); 20427 return (rv); 20428 } 20429 20430 20431 /* Enforce max number of multipaths. */ 20432 if (ecmp_count == ecmp_max_count) { 20433 sal_free(ecmp_grp); 20434 LOG_ERROR(BSL_LS_BCM_L3, 20435 (BSL_META_U(unit, 20436 "Maximum number of ECMP paths reached\n"))); 20437 return (BCM_E_RESOURCE); 20438 } 20439 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx, 20440 BCM_L3_ECMP_PATH_NO_SORTING)) { 20441 ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING; 20442 } 20443 } else { /* New route. */ 20444 ecmp_count = 0; 20445 } 20446 20447 /* Store new ecmp index in the group. */ 20448 ecmp_grp[ecmp_count] = nh_index; 20449 20450 /* Write group & route to hardware. */ 20451 rv = _bcm_xgs3_defip_ecmp_write(unit, lpm_cfg, ecmp_flags, ecmp_grp, (ecmp_count + 1)); 20452 20453 sal_free(ecmp_grp); 20454 return (rv); 20455 } 20456 20457 /* 20458 * Function: 20459 * _bcm_xgs3_defip_del 20460 * Purpose: 20461 * Delete IP route with multipaths from DEFIP table 20462 * Parameters: 20463 * unit - (IN)SOC unit number. 20464 * lpm_cfg - (IN)Route data. 20465 * nh_idx - (IN)Next hop/Ecmp group index. 20466 * Returns: 20467 * BCM_E_XXX 20468 */ 20469 STATIC int 20470 _bcm_xgs3_defip_del(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_idx) 20471 { 20472 int rv = BCM_E_UNAVAIL; 20473 20474 /* Delete route from the hw. */ 20475 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_del)) { 20476 BCM_XGS3_L3_MODULE_LOCK(unit); 20477 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_del) (unit, lpm_cfg); 20478 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20479 } 20480 /* If route deletion successfull decrement next hop reference count. */ 20481 if (rv >= 0) { 20482 bcm_xgs3_nh_del(unit, 0, nh_idx); 20483 } 20484 return rv; 20485 } 20486 20487 /* 20488 * Function: 20489 * _bcm_xgs3_defip_ecmp_del 20490 * Purpose: 20491 * Delete IP route with multipaths from DEFIP table 20492 * Parameters: 20493 * unit - (IN)SOC unit number. 20494 * lpm_cfg - (IN)Route data. 20495 * ecmp_group_id - (IN)Ecmp group id. 20496 * Returns: 20497 * BCM_E_XXX 20498 */ 20499 STATIC int 20500 _bcm_xgs3_defip_ecmp_del(int unit, _bcm_defip_cfg_t *lpm_cfg, 20501 int ecmp_group_id) 20502 { 20503 bcm_l3_egress_t nh_info; /* Deleted next hop info. */ 20504 int cmp_result; /* Next hop comparison result. */ 20505 int ecmp_count = 0; /* Next hop count in the group. */ 20506 uint32 ecmp_flags = 0; /* Ecmp group flags */ 20507 int *ecmp_grp; /* Ecmp group from hw. */ 20508 uint16 hash; /* Hash used to find next hop entry. */ 20509 int idx; /* Iteration index. */ 20510 int del_nh_index; /* Matching next hop index. */ 20511 int rv; /* Internal operations status. */ 20512 20513 20514 /* Input parameters check. */ 20515 if (NULL == lpm_cfg) { 20516 return (BCM_E_PARAM); 20517 } 20518 20519 /* Allocate ecmp group buffer. */ 20520 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 20521 20522 #if defined(BCM_TOMAHAWK3_SUPPORT) 20523 if ((ecmp_group_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) && 20524 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 20525 ecmp_mode_hierarchical)) { 20526 ecmp_flags |= BCM_L3_ECMP_OVERLAY; 20527 } 20528 #endif 20529 20530 if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 20531 /* Read ecmp group members from the hw. */ 20532 rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_id, 20533 ecmp_grp, &ecmp_count); 20534 if (BCM_FAILURE(rv)) { 20535 sal_free(ecmp_grp); 20536 return (rv); 20537 } 20538 } 20539 20540 /* 20541 * If caller didn't specify multipath or group contains a single entry. 20542 * just delete a whole ecmp group. 20543 */ 20544 if ((ecmp_count == 1) || (!(lpm_cfg->defip_flags & BCM_L3_MULTIPATH)) || 20545 (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 20546 /* Delete route from the hw. */ 20547 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_del)) { 20548 BCM_XGS3_L3_MODULE_LOCK(unit); 20549 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_del) (unit, lpm_cfg); 20550 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20551 } else { 20552 sal_free(ecmp_grp); 20553 return (BCM_E_UNAVAIL); 20554 } 20555 20556 /* Decrease reference count for all group member nexthops. */ 20557 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 20558 _bcm_xgs3_ecmp_group_nh_delete(unit, ecmp_grp, ecmp_count); 20559 } 20560 } else { 20561 /* 20562 * 1) BCM_L3_MULTIPATH flag is set && 20563 * 2) Next hop information is present && 20564 * 3) number of entries > 1. 20565 * We need to find next hop index marked for deletion. 20566 */ 20567 /* Prepare next hop info. */ 20568 rv = _bcm_xgs3_nh_entry_init(unit, &nh_info, NULL, lpm_cfg); 20569 if (BCM_FAILURE(rv)) { 20570 sal_free(ecmp_grp); 20571 return (rv); 20572 } 20573 20574 /* If no interface information present use customer provided vlan id. */ 20575 if(!nh_info.vlan) { 20576 nh_info.vlan = lpm_cfg->defip_vid; 20577 } 20578 20579 /* Convert API next hop entry to HW space format. */ 20580 rv = _bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_info); 20581 if (BCM_FAILURE(rv)) { 20582 sal_free(ecmp_grp); 20583 return (rv); 20584 } 20585 20586 /* Calculate entry hash. */ 20587 _bcm_xgs3_nh_hash_calc(unit, (void *)&nh_info, &hash); 20588 20589 /* Find next hop entry from ecmp group. */ 20590 for (idx = 0; idx < ecmp_count; idx++) { 20591 20592 /* Compare next hop hash. */ 20593 if (!BCM_XGS3_L3_ENT_HASH_CMP(BCM_XGS3_L3_TBL_PTR(unit, next_hop), 20594 ecmp_grp[idx], hash)) { 20595 continue; 20596 } 20597 20598 /* Compare entire next hop entry. */ 20599 rv = _bcm_xgs3_nh_ent_cmp(unit, (void *)&nh_info, 20600 ecmp_grp[idx], &cmp_result); 20601 if (BCM_FAILURE(rv)) { 20602 sal_free(ecmp_grp); 20603 return (rv); 20604 } 20605 if (BCM_L3_CMP_EQUAL == cmp_result) { 20606 break; 20607 } /* Next hops are identical check. */ 20608 } /* Loop over all next hop indexes in the group. */ 20609 20610 /* If we didn't find deleted next hop return an error. */ 20611 if (idx >= ecmp_count) { 20612 sal_free(ecmp_grp); 20613 return (BCM_E_PARAM); 20614 } 20615 20616 /* Preserve matching next hop. */ 20617 del_nh_index = ecmp_grp[idx]; 20618 20619 /* Decrement ecmp count. */ 20620 ecmp_count--; 20621 20622 /* Copy last next hop index into the deleted index spot. */ 20623 if (idx < ecmp_count) { 20624 ecmp_grp[idx] = ecmp_grp[ecmp_count]; 20625 } 20626 20627 /* Reset last next hop index in the group. */ 20628 ecmp_grp[ecmp_count] = 0; 20629 20630 /* Write group & route to hardware. */ 20631 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_id, 20632 BCM_L3_ECMP_PATH_NO_SORTING)) { 20633 ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING; 20634 } 20635 20636 rv = _bcm_xgs3_defip_ecmp_write(unit, lpm_cfg, ecmp_flags, ecmp_grp, ecmp_count); 20637 20638 if (BCM_FAILURE(rv)) { 20639 sal_free(ecmp_grp); 20640 return (rv); 20641 } 20642 /* Release next hop index. */ 20643 bcm_xgs3_nh_del(unit, 0, del_nh_index); 20644 } 20645 /* 20646 * Decrement original ecmp group reference count, 20647 * and possibly delete the group. 20648 */ 20649 rv = bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0); 20650 sal_free(ecmp_grp); 20651 return rv; 20652 } 20653 20654 /* 20655 * Function: 20656 * bcm_xgs3_defip_get 20657 * Purpose: 20658 * Get an entry from DEFIP table. 20659 * Parameters: 20660 * unit - (IN)SOC unit number. 20661 * lpm_cfg - (IN)Buffer to fill defip information. 20662 * Returns: 20663 * BCM_E_XXX 20664 */ 20665 int 20666 bcm_xgs3_defip_get(int unit, _bcm_defip_cfg_t *lpm_cfg) 20667 { 20668 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 20669 int *ecmp_grp; /* Ecmp group from hw. */ 20670 int nh_idx; /* Next hop index. */ 20671 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 20672 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20673 ipmc_1_entry_t ipmc_1_entry; 20674 bcm_ipmc_addr_t ipmc; 20675 #endif 20676 20677 /* Input parameters check. */ 20678 if (NULL == lpm_cfg) { 20679 return (BCM_E_PARAM); 20680 } 20681 20682 /* Input parameters checks. */ 20683 BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg); 20684 20685 /* Get lpm entry. */ 20686 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) { 20687 BCM_XGS3_L3_MODULE_LOCK(unit); 20688 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, lpm_cfg, 20689 &nh_ecmp_idx); 20690 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20691 } 20692 20693 BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND); 20694 /* Translate ecmp index to ecmp group id. */ 20695 if (lpm_cfg->defip_ecmp) { 20696 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 20697 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 20698 } 20699 } 20700 20701 /* If route is multipath get nh info from the first path. */ 20702 if (lpm_cfg->defip_ecmp && (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))) { 20703 /* Allocate ecmp group buffer. */ 20704 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 20705 20706 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 20707 ecmp_grp, &lpm_cfg->defip_ecmp_count); 20708 if (BCM_FAILURE(rv)) { 20709 sal_free(ecmp_grp); 20710 return (rv); 20711 } 20712 nh_idx = ecmp_grp[0]; 20713 sal_free(ecmp_grp); 20714 } else { 20715 nh_idx = nh_ecmp_idx; 20716 } 20717 20718 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20719 /* If it is a Multicast route entry, get the source port 20720 * information 20721 */ 20722 if (soc_feature(unit, soc_feature_ipmc_defip) && 20723 soc_mem_is_valid(unit, L3_IPMC_1m) && 20724 lpm_cfg->defip_flags & BCM_L3_IPMC) { 20725 sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t)); 20726 BCM_IF_ERROR_RETURN 20727 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, 20728 lpm_cfg->defip_mc_group, &ipmc_1_entry)); 20729 BCM_IF_ERROR_RETURN 20730 (_tr2_ipmc_glp_get(unit, &ipmc, &ipmc_1_entry)); 20731 lpm_cfg->defip_source_ts = ipmc.ts; 20732 lpm_cfg->defip_source_port_tgid = ipmc.port_tgid; 20733 lpm_cfg->defip_source_modid = ipmc.mod_id; 20734 lpm_cfg->defip_ipmc_flags |= ipmc.flags; 20735 } 20736 #endif 20737 20738 /* Fill next hop info to the prefix. */ 20739 BCM_IF_ERROR_RETURN(_bcm_xgs3_lpm_get_nh_info(unit, lpm_cfg, nh_idx)); 20740 20741 return (BCM_E_NONE); 20742 } 20743 20744 /* 20745 * Function: 20746 * bcm_xgs3_defip_find 20747 * Purpose: 20748 * Find an Longest prefix matched entry from LPM/ALPM table. 20749 * Parameters: 20750 * unit - (IN)SOC unit number. 20751 * lpm_cfg - (IN/OUT)Buffer to fill defip information. 20752 * Returns: 20753 * BCM_E_XXX 20754 */ 20755 int 20756 bcm_xgs3_defip_find(int unit, _bcm_defip_cfg_t *lpm_cfg) 20757 { 20758 #ifdef ALPM_ENABLE 20759 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 20760 int *ecmp_grp; /* Ecmp group from hw. */ 20761 int nh_idx; /* Next hop index. */ 20762 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 20763 20764 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20765 ipmc_1_entry_t ipmc_1_entry; 20766 bcm_ipmc_addr_t ipmc; 20767 #endif 20768 20769 /* Input parameters check. */ 20770 if (NULL == lpm_cfg) { 20771 return (BCM_E_PARAM); 20772 } 20773 20774 if (!SOC_IS_TRIDENT2X(unit) && !SOC_IS_TOMAHAWKX(unit) && !SOC_IS_TRIDENT3X(unit)) { 20775 return (BCM_E_UNAVAIL); 20776 } 20777 20778 if (!(soc_feature(unit, soc_feature_alpm) && 20779 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0))) { 20780 return (BCM_E_CONFIG); 20781 } 20782 20783 /* Input parameters checks. */ 20784 BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg); 20785 20786 /* Get lpm entry. */ 20787 BCM_XGS3_L3_MODULE_LOCK(unit); 20788 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 20789 rv = _bcm_td2_alpm_find(unit, lpm_cfg, &nh_ecmp_idx); 20790 } 20791 #if defined(BCM_TOMAHAWK_SUPPORT) 20792 else if (soc_feature(unit, soc_feature_alpm2)) { 20793 rv = bcm_esw_alpm_find(unit, lpm_cfg, &nh_ecmp_idx); 20794 } 20795 #endif 20796 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 20797 else { 20798 rv = _bcm_th_alpm_find(unit, lpm_cfg, &nh_ecmp_idx); 20799 } 20800 #endif 20801 20802 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20803 20804 BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND); 20805 /* Translate ecmp index to ecmp group id. */ 20806 if (lpm_cfg->defip_ecmp) { 20807 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 20808 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 20809 } 20810 } 20811 20812 /* If route is multipath get nh info from the first path. */ 20813 if (lpm_cfg->defip_ecmp && (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))) { 20814 /* Allocate ecmp group buffer. */ 20815 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 20816 20817 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 20818 ecmp_grp, &lpm_cfg->defip_ecmp_count); 20819 if (BCM_FAILURE(rv)) { 20820 sal_free(ecmp_grp); 20821 return (rv); 20822 } 20823 nh_idx = ecmp_grp[0]; 20824 sal_free(ecmp_grp); 20825 } else { 20826 nh_idx = nh_ecmp_idx; 20827 } 20828 20829 /* Fill next hop info to the prefix. */ 20830 BCM_IF_ERROR_RETURN(_bcm_xgs3_lpm_get_nh_info(unit, lpm_cfg, nh_idx)); 20831 20832 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20833 /* If it is a Multicast route entry, get the source port 20834 * information 20835 */ 20836 if (soc_feature(unit, soc_feature_ipmc_defip) && 20837 soc_mem_is_valid(unit, L3_IPMC_1m) && 20838 lpm_cfg->defip_flags & BCM_L3_IPMC) { 20839 sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t)); 20840 BCM_IF_ERROR_RETURN 20841 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, 20842 lpm_cfg->defip_mc_group, &ipmc_1_entry)); 20843 BCM_IF_ERROR_RETURN 20844 (_tr2_ipmc_glp_get(unit, &ipmc, &ipmc_1_entry)); 20845 lpm_cfg->defip_source_ts = ipmc.ts; 20846 lpm_cfg->defip_source_port_tgid = ipmc.port_tgid; 20847 lpm_cfg->defip_source_modid = ipmc.mod_id; 20848 lpm_cfg->defip_ipmc_flags |= ipmc.flags; 20849 } 20850 #endif 20851 20852 return (BCM_E_NONE); 20853 #else 20854 return (BCM_E_UNAVAIL); 20855 #endif 20856 20857 } 20858 20859 20860 /* 20861 * Function: 20862 * bcm_xgs3_defip_path_validate 20863 * Purpose: 20864 * Service routine used to validate route path for non-egress mode. 20865 * Parameters: 20866 * unit - (IN) Bcm device number. 20867 * new_route - (IN) Added route information. 20868 * old_route - (IN) Previously existing route. 20869 * Returns: 20870 * BCM_E_NONE - Route path is valid. 20871 * BCM_E_XXX - Otherwise. 20872 */ 20873 int 20874 bcm_xgs3_defip_path_validate(int unit, _bcm_defip_cfg_t *new_route, 20875 _bcm_defip_cfg_t *old_route) 20876 { 20877 /* Validate trunk id. */ 20878 BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, new_route->defip_flags, 20879 new_route->defip_port_tgid); 20880 20881 if (new_route->defip_flags & BCM_L3_MULTIPATH) { 20882 /* Make sure device supports ecmp forwarding. */ 20883 if (0 == BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) { 20884 return (BCM_E_UNAVAIL); 20885 } 20886 20887 /* Trap to cpu is not allowed as member of ecmp group. */ 20888 if (new_route->defip_flags & BCM_L3_DEFIP_LOCAL) { 20889 return (BCM_E_PARAM); 20890 } 20891 } 20892 20893 /* If it is not addition of new path to a multipath route. */ 20894 /* BCM_L3_REPLACE flag must be set. */ 20895 if (NULL != old_route) { 20896 if ((!(old_route->defip_flags & BCM_L3_MULTIPATH)) || 20897 (!(new_route->defip_flags & BCM_L3_MULTIPATH))) { 20898 if (!(new_route->defip_flags & BCM_L3_REPLACE)) { 20899 return (BCM_E_EXISTS); 20900 } 20901 } 20902 } 20903 return (BCM_E_NONE); 20904 } 20905 20906 /* 20907 * Function: 20908 * bcm_xgs3_defip_add 20909 * Purpose: 20910 * Add IP route to DEFIP table 20911 * Parameters: 20912 * unit - (IN)SOC unit number. 20913 * lpm_cfg - (IN)Added route information. 20914 * Returns: 20915 * BCM_E_XXX 20916 */ 20917 int 20918 bcm_xgs3_defip_add(int unit, _bcm_defip_cfg_t *lpm_cfg) 20919 { 20920 _bcm_defip_cfg_t entry; /* Lookup buffer. */ 20921 _bcm_defip_cfg_t *old_route; /* Lookup result pointer. */ 20922 int nh_idx; /* Next hop index. */ 20923 int mpath; /* New route is multipath. */ 20924 int nh_remove; /* Flag to remove mpath nhops*/ 20925 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 20926 int lkup_result = BCM_E_UNAVAIL; /* Lookup result. */ 20927 int nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; /* Next hop/Ecmp group index.*/ 20928 int old_ecmp_grp = BCM_XGS3_L3_INVALID_INDEX;/* Original route ecmp group.*/ 20929 #ifdef BCM_TRIDENT2_SUPPORT 20930 soc_mem_t mem_v4 = L3_DEFIP_ALPM_IPV4m; 20931 #endif 20932 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20933 bcm_ipmc_addr_t ipmc; 20934 int need_write; 20935 int new_entry; 20936 #endif 20937 20938 /* Route lookup key Subnet sanity check. */ 20939 BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg); 20940 20941 #ifdef BCM_TRIDENT2_SUPPORT 20942 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_IPV4m)) { 20943 mem_v4 = L3_DEFIP_ALPM_IPV4m; 20944 } 20945 #endif 20946 20947 20948 20949 /* Set lookup key. */ 20950 entry = *lpm_cfg; 20951 mpath = lpm_cfg->defip_flags & BCM_L3_MULTIPATH; 20952 if (!mpath && 20953 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, lpm_cfg->defip_intf)) { 20954 return BCM_E_PARAM; 20955 } 20956 if (mpath && BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 20957 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, lpm_cfg->defip_intf)) { 20958 return BCM_E_PARAM; 20959 } 20960 } 20961 20962 /* Check if route exists. */ 20963 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) { 20964 BCM_XGS3_L3_MODULE_LOCK(unit); 20965 lkup_result = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, &entry, 20966 &nh_ecmp_idx); 20967 BCM_XGS3_L3_MODULE_UNLOCK(unit); 20968 } 20969 lpm_cfg->defip_alpm_cookie = entry.defip_alpm_cookie; 20970 #ifdef ALPM_ENABLE 20971 if (soc_feature(unit, soc_feature_alpm2)) { 20972 lpm_cfg->l1_pvt_node = entry.l1_pvt_node; 20973 lpm_cfg->pvt_node = entry.pvt_node; 20974 lpm_cfg->bkt_node = entry.bkt_node; 20975 } 20976 #endif 20977 20978 if (BCM_SUCCESS(lkup_result)) { 20979 /* Save route entry index in hw to indicate */ 20980 /* existing entry replacement. */ 20981 lpm_cfg->defip_flex_ctr_base_id = entry.defip_flex_ctr_base_id; 20982 lpm_cfg->defip_flex_ctr_mode = entry.defip_flex_ctr_mode; 20983 lpm_cfg->defip_flex_ctr_pool = entry.defip_flex_ctr_pool; 20984 lpm_cfg->defip_index = entry.defip_index; 20985 lpm_cfg->defip_flags_high = entry.defip_flags_high; 20986 old_route = &entry; 20987 /* eXTRACT ecmp group group only if original route was multipath.*/ 20988 if (old_route->defip_flags & BCM_L3_MULTIPATH) { 20989 /* Trunslate next hop index to ecmp group id. */ 20990 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 20991 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 20992 } 20993 old_ecmp_grp = nh_ecmp_idx; 20994 } 20995 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 20996 new_entry = FALSE; 20997 #endif 20998 } else if (lkup_result == BCM_E_NOT_FOUND){ 20999 /* In case of host replacement - make sure host was present. */ 21000 if ((lpm_cfg->defip_flags & BCM_L3_REPLACE) && 21001 (lpm_cfg->defip_flags & BCM_L3_HOST_AS_ROUTE)) { 21002 return (lkup_result); 21003 } 21004 21005 /* New route. */ 21006 lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX; 21007 #ifdef BCM_TRIDENT2_SUPPORT 21008 /* defip_index has a cookie which we don't want to lose. BCM_E_NOT_FOUND 21009 * info for ALPM is available in the cookie 21010 */ 21011 if (SOC_MEM_IS_VALID(unit, mem_v4) && 21012 soc_mem_index_count(unit, mem_v4)) { 21013 /* in alpm mode */ 21014 lpm_cfg->defip_index = entry.defip_index; 21015 } 21016 #endif /* BCM_TRIDENT2_SUPPORT */ 21017 old_route = NULL; 21018 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 21019 new_entry = TRUE; 21020 #endif 21021 } else { 21022 return lkup_result; 21023 } 21024 21025 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 21026 if (soc_feature(unit, soc_feature_ipmc_defip) && 21027 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21028 sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t)); 21029 ipmc.flags = lpm_cfg->defip_ipmc_flags; 21030 ipmc.ts = lpm_cfg->defip_source_ts; 21031 ipmc.port_tgid = lpm_cfg->defip_source_port_tgid; 21032 ipmc.mod_id = lpm_cfg->defip_source_modid; 21033 ipmc.v = 1; 21034 if (new_entry) { 21035 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit, 21036 lpm_cfg->defip_mc_group, &ipmc, 0, &need_write)); 21037 /* Increment the reference count of the given ipmc_index. */ 21038 IPMC_DEFIP_USED_SET(unit, lpm_cfg->defip_mc_group); 21039 } else { 21040 if (entry.defip_mc_group != lpm_cfg->defip_mc_group) { 21041 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit, 21042 lpm_cfg->defip_mc_group, &ipmc, 0, &need_write)); 21043 IPMC_DEFIP_USED_SET(unit, lpm_cfg->defip_mc_group); 21044 IPMC_DEFIP_USED_CLR(unit, entry.defip_mc_group); 21045 } else { 21046 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit, 21047 lpm_cfg->defip_mc_group, &ipmc, 1, &need_write)); 21048 } 21049 } 21050 21051 if (need_write) { 21052 /* Write L3_IPMC table entry. */ 21053 rv = bcm_tr_ipmc_write(unit, lpm_cfg->defip_mc_group, &ipmc); 21054 if (BCM_FAILURE(rv)) { 21055 IPMC_DEFIP_USED_CLR(unit, entry.defip_mc_group); 21056 return (rv); 21057 } 21058 } 21059 } 21060 #endif 21061 21062 if (BCM_GPORT_IS_BLACK_HOLE(lpm_cfg->defip_port_tgid)) { 21063 nh_idx = 0; 21064 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 21065 } else if (soc_feature(unit, soc_feature_ipmc_defip) && 21066 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21067 nh_idx = BCM_XGS3_L3_INVALID_INDEX; 21068 #endif 21069 } else { 21070 /* Validate forwarding path. */ 21071 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 21072 /* No path sanity checks for egress mode, */ 21073 /* Path sanity done during egress object addition.*/ 21074 BCM_IF_ERROR_RETURN 21075 (bcm_xgs3_defip_path_validate(unit, lpm_cfg, old_route)); 21076 } else if (BCM_SUCCESS(lkup_result)){ 21077 if (!(lpm_cfg->defip_flags & BCM_L3_REPLACE)) { 21078 return (BCM_E_EXISTS); 21079 } 21080 } 21081 /* Get next hop index. */ 21082 BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_init_add(unit, NULL, lpm_cfg, &nh_idx)); 21083 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 21084 if (nh_idx == BCM_XGS3_L3_INVALID_INDEX) { 21085 return SOC_E_PARAM; 21086 } 21087 } 21088 } 21089 21090 /* 21091 * If adding new paths to ECMP route, add new paths 21092 * and update ecmp count in LPM table. 21093 */ 21094 if (mpath) { 21095 /* For egress switching mode just set the route entry. */ 21096 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 21097 /* Validate NH idx */ 21098 if (BCM_XGS3_L3_INVALID_INDEX == nh_idx) { 21099 return BCM_E_PARAM; 21100 } 21101 #ifdef BCM_TRIDENT2_SUPPORT 21102 /* If an old ECMP group is replaced by a new one, and if 21103 * they have members in common, the resilient hash flow set 21104 * entries containing the shared members are copied from the old 21105 * ECMP group to the new ECMP group, in order to minimize 21106 * flow-to-member reassignments. 21107 */ 21108 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) && 21109 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 21110 if (BCM_SUCCESS(lkup_result) && 21111 (old_route->defip_flags & BCM_L3_MULTIPATH)) { 21112 BCM_IF_ERROR_RETURN(bcm_td2_l3_egress_ecmp_rh_shared_copy(unit, 21113 old_ecmp_grp, nh_idx)); 21114 } 21115 } 21116 #ifdef BCM_TOMAHAWK_SUPPORT 21117 if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit))&& 21118 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 21119 if (BCM_SUCCESS(lkup_result) && 21120 (old_route->defip_flags & BCM_L3_MULTIPATH)) { 21121 BCM_IF_ERROR_RETURN(bcm_opt_l3_egress_ecmp_rh_shared_copy(unit, 21122 old_ecmp_grp, nh_idx)); 21123 } 21124 } 21125 #endif /* BCM_TOMAHAWK_SUPPORT */ 21126 21127 #endif /* BCM_TRIDENT2_SUPPORT */ 21128 /* In egress mode increment path reference & update the route.*/ 21129 rv = _bcm_xgs3_defip_mpath_add(unit, lpm_cfg, nh_idx); 21130 } else { 21131 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 21132 /* For non egress switching mode create ecmp group and route.*/ 21133 rv = _bcm_xgs3_defip_ecmp_add(unit, lpm_cfg, old_ecmp_grp, nh_idx); 21134 } else { 21135 return BCM_E_UNAVAIL; 21136 } 21137 } 21138 } else { 21139 /* Add route to the hw. */ 21140 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_add)) { 21141 BCM_XGS3_L3_MODULE_LOCK(unit); 21142 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_add) (unit, lpm_cfg, nh_idx); 21143 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21144 } 21145 } 21146 21147 /* In case of route update decrement original path/group reference count. */ 21148 if ((BCM_SUCCESS(lkup_result)) && (BCM_SUCCESS(rv))) { 21149 if(old_route->defip_flags & BCM_L3_MULTIPATH) { 21150 /* Destroy ecmp group. Keep member next hops if new route is */ 21151 /* multipath as well, otherwise remove them. */ 21152 /* Never touch next hops attched to an egress object. */ 21153 nh_remove = (!(mpath || BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))); 21154 BCM_IF_ERROR_RETURN 21155 (_bcm_xgs3_ecmp_group_remove(unit, nh_ecmp_idx, nh_remove)); 21156 } else { 21157 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_ecmp_idx)); 21158 } 21159 } 21160 21161 /* Regardless of status don't touch egress object multipath routes. */ 21162 if (mpath && BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 21163 return (rv); 21164 } 21165 21166 /* If route addition failed decrement next hop reference count. */ 21167 if (BCM_FAILURE(rv)) { 21168 /* Free next hop entry. */ 21169 bcm_xgs3_nh_del(unit, 0, nh_idx); 21170 /* Rollback for IPMC ref count */ 21171 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 21172 if (soc_feature(unit, soc_feature_ipmc_defip) && 21173 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21174 if (new_entry) { 21175 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group); 21176 } else if (entry.defip_mc_group != lpm_cfg->defip_mc_group) { 21177 IPMC_DEFIP_USED_SET(unit, entry.defip_mc_group); 21178 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group); 21179 } 21180 } 21181 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 21182 } 21183 return (rv); 21184 } 21185 21186 /* 21187 * Function: 21188 * bcm_xgs3_defip_del 21189 * Purpose: 21190 * Delete IP route from DEFIP table 21191 * Parameters: 21192 * unit - (IN)SOC unit number. 21193 * lpm_cfg - (IN)Deleted route information. 21194 * Returns: 21195 * BCM_E_XXX 21196 */ 21197 int 21198 bcm_xgs3_defip_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 21199 { 21200 _bcm_defip_cfg_t entry; /* Lookup buffer. */ 21201 int rv; /* Operation return status. */ 21202 int nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; /* Next hop/Ecmp group index. */ 21203 int lkup_result = BCM_E_UNAVAIL; /* Lookup result. */ 21204 21205 /* Input parameters checks. */ 21206 BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg); 21207 21208 /* Port trunk verification. */ 21209 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 21210 BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, lpm_cfg->defip_flags, 21211 lpm_cfg->defip_port_tgid); 21212 } 21213 21214 /* Set lookup key. */ 21215 entry = *lpm_cfg; 21216 21217 #ifdef ALPM_ENABLE 21218 #if defined(BCM_TOMAHAWK_SUPPORT) 21219 if (soc_feature(unit, soc_feature_alpm2) && 21220 ALPMC(unit) && !ALPM_HIT_SKIP(unit)) { 21221 entry.defip_flags |= BCM_L3_HIT_CLEAR; 21222 } 21223 #endif /* BCM_TOMAHAWK_SUPPORT */ 21224 #endif /* ALPM_ENABLE */ 21225 21226 /* Check if route exists. */ 21227 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) { 21228 BCM_XGS3_L3_MODULE_LOCK(unit); 21229 lkup_result = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, &entry, 21230 &nh_ecmp_idx); 21231 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21232 } 21233 if (lkup_result < 0) { 21234 return lkup_result; 21235 } 21236 21237 lpm_cfg->defip_flags_high = entry.defip_flags_high; 21238 lpm_cfg->defip_index = entry.defip_index; 21239 lpm_cfg->defip_alpm_cookie = entry.defip_alpm_cookie; 21240 #ifdef ALPM_ENABLE 21241 if (soc_feature(unit, soc_feature_alpm2)) { 21242 lpm_cfg->l1_pvt_node = entry.l1_pvt_node; 21243 lpm_cfg->pvt_node = entry.pvt_node; 21244 lpm_cfg->bkt_node = entry.bkt_node; 21245 } 21246 #endif 21247 if (entry.defip_flags & BCM_L3_IPMC && 21248 soc_feature(unit, soc_feature_ipmc_defip)) { 21249 lpm_cfg->defip_flags |= BCM_L3_IPMC; 21250 } 21251 /* Remove path from hw. */ 21252 if (entry.defip_flags & BCM_L3_MULTIPATH) { 21253 /* Trunslate next hop index to ecmp group id. */ 21254 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 21255 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 21256 } 21257 rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx); 21258 } else { 21259 rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx); 21260 } 21261 21262 if ((rv >= 0) && soc_feature(unit, soc_feature_ipmc_defip) && 21263 (entry.defip_flags & BCM_L3_IPMC)) { 21264 if (entry.defip_mc_group) { 21265 IPMC_DEFIP_USED_CLR(unit, entry.defip_mc_group); 21266 } 21267 } 21268 21269 return rv; 21270 } 21271 21272 /* 21273 * Function: 21274 * _bcm_xgs3_defip_intf_del_test_cb 21275 * Purpose: 21276 * Test entries in DEFIP table by intf match. 21277 * Parameters: 21278 * unit - (IN)SOC unit number. 21279 * pattern - (IN)Match pattern (interface id & negate). 21280 * data1 - (IN)Route info. 21281 * data2 - (IN)Next hop info. 21282 * cmp_result- (OUT)Comparison result. 21283 * Returns: 21284 * BCM_E_XXX 21285 */ 21286 STATIC int 21287 _bcm_xgs3_defip_intf_del_test_cb(int unit, void *pattern, 21288 void *data1, void *data2, int *cmp_result) 21289 { 21290 _bcm_l3_trvrs_data_t *trv_data; /* Travers data. */ 21291 _bcm_if_del_pattern_t *if_info; /* Interface id/negate info. */ 21292 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21293 int if_cmp_result = -1; /* Interface compare result. */ 21294 int nh_ecmp_idx; /* Next hop/ecmp group index. */ 21295 int ecmp_count = 0; /* Ecmp group size. */ 21296 int *ecmp_grp; /* Ecmp group from hw. */ 21297 int idx; /* Iteration index. */ 21298 int rv; /* Operation return status. */ 21299 21300 /* Cast input parameters. */ 21301 trv_data = (_bcm_l3_trvrs_data_t *) pattern; 21302 if_info = (_bcm_if_del_pattern_t *) trv_data->pattern; 21303 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21304 nh_ecmp_idx = *(int *)data2; 21305 21306 21307 if (lpm_cfg->defip_ecmp) { 21308 /* Translate next hop index to ecmp group id. */ 21309 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 21310 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 21311 } 21312 21313 /* Allocate ecmp group buffer. */ 21314 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 21315 21316 /* If route is multipath get next hops from ecmp group. */ 21317 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 21318 ecmp_grp, &ecmp_count); 21319 if (BCM_FAILURE(rv)) { 21320 sal_free(ecmp_grp); 21321 return (rv); 21322 } 21323 21324 /* Loop over all ecmp group members and check outgoing interface. */ 21325 for (idx = 0; idx < ecmp_count; idx++) { 21326 rv = _bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf, 21327 ecmp_grp[idx], &if_cmp_result); 21328 if (BCM_FAILURE(rv)) { 21329 sal_free(ecmp_grp); 21330 return (rv); 21331 } 21332 if (BCM_L3_CMP_EQUAL == *cmp_result) { 21333 break; 21334 } 21335 } /* Loop over ecmp group next hops. */ 21336 sal_free(ecmp_grp); 21337 } else { 21338 /* Check next hop outgoing interface. */ 21339 BCM_IF_ERROR_RETURN 21340 (_bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf, 21341 nh_ecmp_idx, &if_cmp_result)); 21342 } 21343 21344 /* Calculate final result based on negate and interface index comparison. */ 21345 if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, if_info->negate)) { 21346 *cmp_result = BCM_L3_CMP_EQUAL; 21347 } else { 21348 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 21349 } 21350 return (BCM_E_NONE); 21351 } 21352 21353 21354 /* 21355 * Function: 21356 * _bcm_xgs3_defip_intf_del_op_cb 21357 * Purpose: 21358 * Delete entries in DEFIP table by intf match. 21359 * Parameters: 21360 * unit - (IN)SOC unit number. 21361 * pattern - (IN)Match pattern (interface id & negate). 21362 * data1 - (IN)Route info. 21363 * data2 - (IN)Next hop info. 21364 * cmp_result- (OUT)Comparison result. 21365 * Returns: 21366 * BCM_E_XXX 21367 */ 21368 STATIC int 21369 _bcm_xgs3_defip_intf_del_op_cb(int unit, void *pattern, 21370 void *data1, void *data2, int *cmp_result) 21371 { 21372 _bcm_l3_trvrs_data_t *trv_data; /* Travers data. */ 21373 _bcm_if_del_pattern_t *if_info; /* Interface id/negate info. */ 21374 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21375 int if_cmp_result; /* Interface compare result. */ 21376 int nh_ecmp_idx; /* Next hop/ecmp group index. */ 21377 uint32 ecmp_flags = 0; /* Ecmp group flags */ 21378 int ecmp_count = 0; /* Ecmp group next hops count.*/ 21379 int *ecmp_grp; /* Ecmp group from hw. */ 21380 int idx; /* Iteration index. */ 21381 int rv; /* Operation return status. */ 21382 int new_ecmp_count = 0; /* New ecmp group nh count. */ 21383 21384 /* Cast input parameters. */ 21385 trv_data = (_bcm_l3_trvrs_data_t *) pattern; 21386 if_info = (_bcm_if_del_pattern_t *) trv_data->pattern; 21387 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21388 nh_ecmp_idx = *(int *)data2; 21389 21390 /* avoid route delete failure during callback in update match. */ 21391 lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX; 21392 21393 if (lpm_cfg->defip_ecmp) { /* Multipath. */ 21394 /* Translate next hop index to ecmp group id. */ 21395 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 21396 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 21397 } 21398 21399 /* Allocate ecmp group buffer. */ 21400 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp)); 21401 21402 /* If route is multipath get next hops from ecmp group. */ 21403 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 21404 ecmp_grp, &ecmp_count); 21405 if (BCM_FAILURE(rv)) { 21406 sal_free(ecmp_grp); 21407 return (rv); 21408 } 21409 21410 /* Loop over all ecmp group members and check outgoing interface. */ 21411 for (idx = 0; idx < ecmp_count; idx++) { 21412 rv = _bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf, 21413 ecmp_grp[idx], &if_cmp_result); 21414 if (BCM_FAILURE(rv)) { 21415 sal_free(ecmp_grp); 21416 return (rv); 21417 } 21418 21419 /* Update ecmp group based on comparison result. */ 21420 if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, if_info->negate)) { 21421 /* Overrite the entry with last group member. */ 21422 ecmp_grp[idx] = ecmp_grp[ecmp_count - 1]; 21423 BCM_XGS3_L3_DEC_IF_POSITIVE(ecmp_count); 21424 BCM_XGS3_L3_DEC_IF_POSITIVE(idx); 21425 } else { 21426 new_ecmp_count++; 21427 } 21428 } 21429 21430 /* If no paths left or at least one interface matches in 21431 l3 egress switching mode, delete the route. */ 21432 if ((!new_ecmp_count) || 21433 ((new_ecmp_count != ecmp_count) && 21434 (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))){ 21435 /* Unset multipath flag to indicate complete route deletion. */ 21436 lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH; 21437 sal_free(ecmp_grp); 21438 return _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx); 21439 } else if (new_ecmp_count != ecmp_count) { 21440 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, nh_ecmp_idx, 21441 BCM_L3_ECMP_PATH_NO_SORTING)) { 21442 ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING; 21443 } 21444 /* Next hops array changed rewrite ecmp group. */ 21445 #if defined(BCM_TOMAHAWK3_SUPPORT) 21446 if ((*ecmp_grp < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) && 21447 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 21448 ecmp_mode_hierarchical) && 21449 (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) { 21450 ecmp_flags |= BCM_L3_ECMP_OVERLAY; 21451 } 21452 #endif 21453 21454 rv = _bcm_xgs3_defip_ecmp_write(unit, lpm_cfg, ecmp_flags, ecmp_grp, 21455 new_ecmp_count); 21456 sal_free(ecmp_grp); 21457 BCM_IF_ERROR_RETURN(rv); 21458 21459 /* Free original ecmp group. */ 21460 BCM_IF_ERROR_RETURN(bcm_xgs3_ecmp_group_del(unit, nh_ecmp_idx, 0)); 21461 } else { 21462 sal_free(ecmp_grp); 21463 /* Else nothing changed don't touch the entry. */ 21464 } 21465 } else { /* Single path. */ 21466 /* Check next hop outgoing interface. */ 21467 BCM_IF_ERROR_RETURN 21468 (_bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf, 21469 nh_ecmp_idx, &if_cmp_result)); 21470 /* Based on comparison & negate decide to delete an entry or not. */ 21471 if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, if_info->negate)) { 21472 BCM_IF_ERROR_RETURN 21473 (_bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx)); 21474 } 21475 if (soc_feature(unit, soc_feature_ipmc_defip) && 21476 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21477 21478 if (lpm_cfg->defip_mc_group) { 21479 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group); 21480 } 21481 } 21482 } 21483 return (BCM_E_NONE); 21484 } 21485 21486 /* 21487 * Function: 21488 * bcm_xgs3_ip4_defip_del_intf 21489 * Purpose: 21490 * Delete entries in DEFIP table by intf match. 21491 * Parameters: 21492 * unit - SOC unit number. 21493 * defip - Pointer to memory for DEFIP table related information. 21494 * negate - 0 means interface match; 1 means not match 21495 * Returns: 21496 * BCM_E_XXX 21497 */ 21498 int 21499 bcm_xgs3_defip_del_intf(int unit, _bcm_defip_cfg_t *lpm_cfg, int negate) 21500 { 21501 _bcm_l3_trvrs_data_t trv_data; /* Travers initiator function input. */ 21502 _bcm_if_del_pattern_t pattern; /* Interface & negate combination 21503 to be used for comparision. */ 21504 int rv = BCM_E_UNAVAIL; /* Operation return value. */ 21505 21506 bcm_l3_egress_t egr; /* Egress object. */ 21507 int nh_index; /* Next hop index. */ 21508 bcm_if_t intf; /* Deleted interface id. */ 21509 21510 /* Make sure module was initialized. */ 21511 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 21512 return (BCM_E_INIT); 21513 } 21514 21515 /* Input parameters check */ 21516 if (NULL == lpm_cfg) { 21517 return (BCM_E_PARAM); 21518 } 21519 21520 intf = lpm_cfg->defip_intf; 21521 21522 /* Check l3 switching mode. */ 21523 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 21524 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 21525 BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 21526 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 21527 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 21528 } else { 21529 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 21530 } 21531 /* Get egress object information. */ 21532 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr)); 21533 /* Use egress object interface for iteration */ 21534 intf = egr.intf; 21535 } 21536 } 21537 21538 /* If table is empty -> there is nothing to delete. */ 21539 BCM_XGS3_L3_IF_DEFIP_CNT_ZERO_RETURN 21540 (unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 21541 21542 /* Zero traverse info. */ 21543 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 21544 21545 /* Set interface match pattern (interface index + negate) */ 21546 pattern.l3_intf = intf; 21547 pattern.negate = negate; 21548 21549 /* Fill traverse data struct. */ 21550 trv_data.flags = lpm_cfg->defip_flags | BCM_XGS3_L3_OP_DEL; 21551 trv_data.pattern = (void *)&pattern; 21552 trv_data.cmp_cb = _bcm_xgs3_defip_intf_del_test_cb; 21553 trv_data.op_cb = _bcm_xgs3_defip_intf_del_op_cb; 21554 21555 /* Delete routes matching the pattern from hw. */ 21556 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) { 21557 BCM_XGS3_L3_MODULE_LOCK(unit); 21558 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data); 21559 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21560 } 21561 trv_data.flags &= ~BCM_XGS3_L3_OP_DEL; 21562 return rv; 21563 } 21564 21565 /* 21566 * Function: 21567 * _bcm_xgs3_defip_del_all_op_cb 21568 * Purpose: 21569 * Delete all entries in DEFIP table. 21570 * Parameters: 21571 * unit - (IN)SOC unit number. 21572 * pattern - (IN)Match pattern. 21573 * data1 - (IN)Route info. 21574 * data2 - (IN)Next hop info. 21575 * cmp_result- (OUT)Comparison result. 21576 * Returns: 21577 * BCM_E_XXX 21578 */ 21579 STATIC int 21580 _bcm_xgs3_defip_del_all_op_cb(int unit, void *pattern, 21581 void *data1, void *data2, int *cmp_result) 21582 { 21583 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21584 int nh_ecmp_idx; /* Next hop/ecmp group index. */ 21585 int rv; /* Operation return status. */ 21586 21587 /* Cast input parameters. */ 21588 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21589 nh_ecmp_idx = *(int *)data2; 21590 21591 #ifdef ALPM_ENABLE 21592 /* If ALPM is enabled and it's TD2, keep defip_index */ 21593 if (!(SOC_IS_TRIDENT2(unit) && 21594 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) && 21595 soc_feature(unit, soc_feature_alpm))) 21596 #endif 21597 { 21598 /* otherwise set it invalid to trigger lookup */ 21599 lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX; 21600 } 21601 21602 /* clear hit bit */ 21603 #ifdef ALPM_ENABLE 21604 #if defined(BCM_TOMAHAWK_SUPPORT) 21605 if (soc_feature(unit, soc_feature_alpm2) && ALPMC(unit) && !ALPM_HIT_SKIP(unit)) { 21606 int alpm_global_routes = 0; 21607 if (!(lpm_cfg->defip_flags & BCM_L3_IPMC) && 21608 _soc_alpm_mode[unit] != 0 && 21609 (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE || 21610 (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL && 21611 _soc_alpm_mode[unit] == 3))) { 21612 alpm_global_routes = 1; 21613 } 21614 if (!alpm_global_routes) { 21615 lpm_cfg->defip_flags |= BCM_L3_HIT_CLEAR; 21616 /* Clear hit bit. */ 21617 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) { 21618 BCM_XGS3_L3_MODULE_LOCK(unit); 21619 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get)(unit, lpm_cfg, NULL); 21620 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21621 if (rv < 0) { 21622 return rv; 21623 } 21624 } 21625 } /* Don't clear Global Routes in ALPM mode */ 21626 } 21627 #endif /* BCM_TOMAHAWK_SUPPORT */ 21628 #endif /* ALPM_ENABLE */ 21629 21630 if (lpm_cfg->defip_ecmp) { 21631 /* Translate next hop index to ecmp group id. */ 21632 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 21633 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 21634 } 21635 /* 21636 * Reset multipath flag so the whole entry and not a specific path 21637 * will be deleted. 21638 */ 21639 lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH; 21640 rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx); 21641 } else { 21642 rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx); 21643 } 21644 if ((rv >= 0) && 21645 soc_feature(unit, soc_feature_ipmc_defip) && 21646 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21647 21648 if (lpm_cfg->defip_mc_group) { 21649 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group); 21650 } 21651 } 21652 21653 return rv; 21654 } 21655 21656 #ifdef ALPM_ENABLE 21657 #if defined(BCM_TOMAHAWK3_SUPPORT) 21658 /* 21659 * Function: 21660 * _bcm_xgs3_defip_fast_del_all_op_cb 21661 * Purpose: 21662 * Delete all entries in DEFIP table. 21663 * Parameters: 21664 * unit - (IN)SOC unit number. 21665 * pattern - (IN)Match pattern. 21666 * data1 - (IN)Route info. 21667 * data2 - (IN)Next hop info. 21668 * cmp_result- (OUT)Comparison result. 21669 * Returns: 21670 * BCM_E_XXX 21671 */ 21672 STATIC int 21673 _bcm_xgs3_defip_fast_del_all_op_cb(int unit, void *pattern, 21674 void *data1, void *data2, int *cmp_result) 21675 { 21676 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21677 int nh_ecmp_idx; /* Next hop/ecmp group index. */ 21678 int rv; /* Operation return status. */ 21679 21680 /* Cast input parameters. */ 21681 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21682 nh_ecmp_idx = *(int *)data2; 21683 21684 /* flag with fast_delete_all */ 21685 lpm_cfg->fast_delete_all = TRUE; 21686 21687 if (lpm_cfg->defip_ecmp) { 21688 /* Translate next hop index to ecmp group id. */ 21689 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 21690 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 21691 } 21692 /* 21693 * Reset multipath flag so the whole entry and not a specific path 21694 * will be deleted. 21695 */ 21696 lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH; 21697 rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx); 21698 } else { 21699 rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx); 21700 } 21701 if ((rv >= 0) && 21702 soc_feature(unit, soc_feature_ipmc_defip) && 21703 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21704 21705 if (lpm_cfg->defip_mc_group) { 21706 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group); 21707 } 21708 } 21709 21710 return rv; 21711 } 21712 #endif 21713 #endif 21714 21715 #if defined(BCM_TRIUMPH_SUPPORT) 21716 /* 21717 * Function: 21718 * bcm_xgs3_defip_verify_internal_mem_usage 21719 * Purpose: 21720 * Verify if entries are present within INT-DEFIP table 21721 * Parameters: 21722 * unit - (IN)SOC unit number. 21723 * Returns: 21724 * BCM_E_XXX 21725 */ 21726 21727 int 21728 bcm_xgs3_defip_verify_internal_mem_usage(int unit) 21729 { 21730 21731 if (soc_feature(unit, soc_feature_esm_support)) { 21732 if (soc_mem_index_count(unit, L3_DEFIPm)) { 21733 if (BCM_XGS3_L3_DEFIP_IP4_CNT(unit)) { 21734 return BCM_E_DISABLED; 21735 } 21736 21737 if (BCM_XGS3_L3_DEFIP_IP6_CNT(unit)) { 21738 return BCM_E_DISABLED; 21739 } 21740 21741 } 21742 BCM_IF_ERROR_RETURN(_bcm_trx_l3_defip_verify_internal_mem_usage(unit)); 21743 } 21744 return BCM_E_NONE; 21745 } 21746 #endif 21747 21748 /* 21749 * Function: 21750 * bcm_xgs3_defip_del_all 21751 * Purpose: 21752 * Delete all entries in DEFIP table 21753 * Parameters: 21754 * unit - (IN)SOC unit number. 21755 * Returns: 21756 * BCM_E_XXX 21757 */ 21758 int 21759 bcm_xgs3_defip_del_all(int unit) 21760 { 21761 _bcm_l3_trvrs_data_t trv_data; /* Travers initiator parameters. */ 21762 int tmp_rv; /* First error occured. */ 21763 int rv; /* Operation return status. */ 21764 21765 tmp_rv = rv = BCM_E_NONE; 21766 21767 /* Make sure module was initialized. */ 21768 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 21769 return (BCM_E_INIT); 21770 } 21771 21772 #ifdef ALPM_ENABLE 21773 #if defined(BCM_TOMAHAWK3_SUPPORT) 21774 /* Hard delete_all for TH3 ALPM */ 21775 if (SOC_IS_TOMAHAWK3(unit) && 21776 soc_feature(unit, soc_feature_alpm2) && 21777 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 21778 21779 _bcm_l3_trvrs_data_t trv_data1; /* ALPM route fast delete_all travers. */ 21780 21781 if ((BCM_XGS3_L3_DEFIP_IP4_CNT(unit) == 0) && 21782 (BCM_XGS3_L3_DEFIP_IP6_CNT(unit) == 0)) { 21783 return rv; 21784 } 21785 21786 /* Zero traverse info. */ 21787 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 21788 sal_memset(&trv_data1, 0, sizeof(_bcm_l3_trvrs_data_t)); 21789 21790 /* Fill traverse data struct. */ 21791 trv_data.op_cb = _bcm_xgs3_defip_del_all_op_cb; 21792 trv_data1.op_cb = _bcm_xgs3_defip_fast_del_all_op_cb; 21793 21794 BCM_XGS3_L3_MODULE_LOCK(unit); 21795 21796 /* Fast delete all (IPv4 & IPv6) by travel data */ 21797 rv = bcm_esw_alpm_cleanup(unit, &trv_data, &trv_data1); 21798 21799 if (BCM_SUCCESS(rv)) { 21800 BCM_XGS3_L3_DEFIP_IP4_CNT(unit) = 0; 21801 BCM_XGS3_L3_DEFIP_IP6_CNT(unit) = 0; 21802 } 21803 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21804 return rv; 21805 } 21806 #endif 21807 #endif 21808 21809 /* Make sure required hw call is defined. */ 21810 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) { 21811 return (BCM_E_UNAVAIL); 21812 } 21813 21814 /* Zero traverse info. */ 21815 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 21816 21817 /* Fill traverse data struct. */ 21818 trv_data.op_cb = _bcm_xgs3_defip_del_all_op_cb; 21819 21820 trv_data.flags = 0; 21821 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 21822 trv_data.flags |= BCM_XGS3_L3_OP_GET_REVERSE; 21823 } 21824 21825 BCM_XGS3_L3_MODULE_LOCK(unit); 21826 /* Delete ipv4 routes matching the pattern from hw. */ 21827 if (BCM_XGS3_L3_DEFIP_IP4_CNT(unit)) { 21828 tmp_rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, 21829 &trv_data); 21830 } 21831 21832 /* Delete ipv6 routes matching the pattern from hw. */ 21833 if (BCM_XGS3_L3_DEFIP_IP6_CNT(unit)) { 21834 trv_data.flags |= BCM_L3_IP6; 21835 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, 21836 &trv_data); 21837 } 21838 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21839 return (tmp_rv < 0) ? tmp_rv : rv; 21840 } 21841 21842 /* 21843 * Function: 21844 * _bcm_xgs3_defip_age_test_cb 21845 * Purpose: 21846 * Test hit bit in DEFIP entries. 21847 * Parameters: 21848 * unit - (IN)SOC unit number. 21849 * pattern - (IN)Match pattern. 21850 * data1 - (IN)Route info. 21851 * data2 - (IN)Next hop info. 21852 * cmp_result- (OUT)Comparison result. 21853 * Returns: 21854 * BCM_E_XXX 21855 */ 21856 STATIC int 21857 _bcm_xgs3_defip_age_test_cb(int unit, void *pattern, void *data1, 21858 void *data2, int *cmp_result) 21859 { 21860 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21861 21862 /* Cast input parameters. */ 21863 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21864 21865 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 21866 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 21867 } else { 21868 *cmp_result = BCM_L3_CMP_EQUAL; 21869 } 21870 return (BCM_E_NONE); 21871 } 21872 21873 21874 /* 21875 * Function: 21876 * _bcm_xgs3_defip_age_delete_cb 21877 * Purpose: 21878 * Delete unused entries in DEFIP table 21879 * and notify the user. 21880 * Parameters: 21881 * unit - (IN)SOC unit number. 21882 * pattern - (IN)Match pattern. 21883 * data1 - (IN)Route info. 21884 * data2 - (IN)Next hop info. 21885 * cmp_result- (OUT)Comparison result. 21886 * Returns: 21887 * BCM_E_XXX 21888 */ 21889 STATIC int 21890 _bcm_xgs3_defip_age_delete_cb(int unit, void *pattern, void *data1, 21891 void *data2, int *cmp_result) 21892 { 21893 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21894 _bcm_l3_trvrs_data_t *trv_data; /* Travers data. */ 21895 int nh_ecmp_idx; /* Next hop/Ecmp group index.*/ 21896 int rv = BCM_E_NONE; /* Operation return status. */ 21897 21898 int alpm_global_routes = 0; 21899 21900 /* Cast input parameters. */ 21901 trv_data = (_bcm_l3_trvrs_data_t *) pattern; 21902 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21903 nh_ecmp_idx = *(int *)data2; 21904 21905 #if defined(BCM_TRIDENT2_SUPPORT) 21906 if (!(lpm_cfg->defip_flags & BCM_L3_IPMC) && 21907 _soc_alpm_mode[unit] != 0 && 21908 (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE || 21909 lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL)) { 21910 alpm_global_routes = 1; 21911 } 21912 #endif 21913 21914 if (!(lpm_cfg->defip_flags & BCM_L3_HIT)) { 21915 /* avoid route delete failure during callback in update match. */ 21916 lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX; 21917 /* Remove path from hw. */ 21918 if (!alpm_global_routes) { 21919 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 21920 /* Unset multipath flag -> so all route path's can be deleted. */ 21921 lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH; 21922 rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx); 21923 } else { 21924 rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx); 21925 } 21926 } /* Don't delete Global Routes in ALPM mode */ 21927 21928 if ((rv >= 0) && 21929 soc_feature(unit, soc_feature_ipmc_defip) && 21930 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 21931 21932 if (lpm_cfg->defip_mc_group) { 21933 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group); 21934 } 21935 } 21936 /* Notify caller regarding unused entry. */ 21937 _bcm_xgs3_lpm_call_user_cb(unit, trv_data, lpm_cfg, 21938 BCM_XGS3_L3_INVALID_INDEX); 21939 } 21940 return (rv); 21941 } 21942 21943 21944 /* 21945 * Function: 21946 * _bcm_xgs3_defip_age_clear_hit_cb 21947 * Purpose: 21948 * Age entries in DEFIP table and notify the user. 21949 * Parameters: 21950 * unit - (IN)SOC unit number. 21951 * pattern - (IN)Match pattern. 21952 * data1 - (IN)Route info. 21953 * data2 - (IN)Next hop info. 21954 * cmp_result- (OUT)Comparison result. 21955 * Returns: 21956 * BCM_E_XXX 21957 */ 21958 STATIC int 21959 _bcm_xgs3_defip_age_clear_hit_cb(int unit, void *pattern, void *data1, 21960 void *data2, int *cmp_result) 21961 { 21962 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 21963 int rv = BCM_E_NONE; /* Operation return status. */ 21964 int alpm_global_routes = 0; 21965 21966 /* Comparison is always false - since no action required. */ 21967 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 21968 21969 /* Cast input parameters. */ 21970 lpm_cfg = (_bcm_defip_cfg_t *) data1; 21971 21972 #if defined(BCM_TRIDENT2_SUPPORT) 21973 if (!(lpm_cfg->defip_flags & BCM_L3_IPMC) && 21974 _soc_alpm_mode[unit] != 0 && 21975 (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE || 21976 (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL && 21977 _soc_alpm_mode[unit] == 3))) { 21978 alpm_global_routes = 1; 21979 } 21980 #endif 21981 21982 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 21983 if (!alpm_global_routes) { 21984 lpm_cfg->defip_flags |= BCM_L3_HIT_CLEAR; 21985 21986 /* Clear hit bit. */ 21987 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) { 21988 BCM_XGS3_L3_MODULE_LOCK(unit); 21989 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get)(unit, lpm_cfg, NULL); 21990 BCM_XGS3_L3_MODULE_UNLOCK(unit); 21991 if (rv < 0) { 21992 return rv; 21993 } 21994 } 21995 } /* Don't clear Global Routes in ALPM mode */ 21996 } 21997 return (BCM_E_NONE); 21998 } 21999 22000 /* 22001 * Function: 22002 * bcm_xgs3_defip_age 22003 * Purpose: 22004 * Age out the DEFIP table 22005 * Parameters: 22006 * unit - (IN)SOC unit number. 22007 * flags - (IN)IPv4/IPv6. 22008 * age_out - (IN)age_out Notification callback. 22009 * user_data - (IN)User provided cookie for callback. 22010 * Returns: 22011 * BCM_E_XXX 22012 */ 22013 int 22014 _bcm_xgs3_defip_age(int unit, int flags, bcm_l3_route_traverse_cb age_out, 22015 void *user_data) 22016 { 22017 _bcm_l3_trvrs_data_t trv_data; /* Travers initiator parameters. */ 22018 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 22019 22020 /* If table is empty -> there is nothing to delete. */ 22021 BCM_XGS3_L3_IF_DEFIP_CNT_ZERO_RETURN(unit, flags & BCM_L3_IP6); 22022 22023 /* Zero traverse info. */ 22024 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 22025 22026 /* Fill traverse data struct. */ 22027 trv_data.flags = flags; 22028 /* We need to set both operational & test callback since firebolt 22029 never executes test routine. */ 22030 trv_data.cmp_cb = _bcm_xgs3_defip_age_test_cb; 22031 trv_data.op_cb = _bcm_xgs3_defip_age_delete_cb; 22032 trv_data.defip_cb = age_out; 22033 trv_data.cookie = user_data; 22034 22035 /* Age routes matching the pattern from hw. */ 22036 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) { 22037 BCM_XGS3_L3_MODULE_LOCK(unit); 22038 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data); 22039 BCM_XGS3_L3_MODULE_UNLOCK(unit); 22040 } 22041 /* Clear hit bit for the rest of the routes. */ 22042 trv_data.cmp_cb = _bcm_xgs3_defip_age_clear_hit_cb; 22043 trv_data.op_cb = _bcm_xgs3_defip_age_clear_hit_cb; 22044 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) { 22045 BCM_XGS3_L3_MODULE_LOCK(unit); 22046 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data); 22047 BCM_XGS3_L3_MODULE_UNLOCK(unit); 22048 } 22049 return rv; 22050 } 22051 22052 /* 22053 * Function: 22054 * bcm_xgs3_defip_age 22055 * Purpose: 22056 * Age out DEFIP table 22057 * Parameters: 22058 * unit - (IN)SOC unit number. 22059 * age_out - (IN)age_out Notification callback. 22060 * user_data - (IN)User provided cookie for callback. 22061 * Returns: 22062 * BCM_E_XXX 22063 */ 22064 int 22065 bcm_xgs3_defip_age(int unit, bcm_l3_route_traverse_cb age_out, void *user_data) 22066 { 22067 int rv; /* Operation return status. */ 22068 int tmp_rv; /* First error occured. */ 22069 22070 /* Make sure module was initialized. */ 22071 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 22072 return (BCM_E_INIT); 22073 } 22074 22075 /* Age all ipv4 entries. */ 22076 tmp_rv = _bcm_xgs3_defip_age(unit, 0, age_out, user_data); 22077 22078 /* Age all ipv6 entries. */ 22079 rv = _bcm_xgs3_defip_age(unit, BCM_L3_IP6, age_out, user_data); 22080 22081 return (tmp_rv < 0) ? tmp_rv : rv; 22082 } 22083 22084 #ifdef BCM_WARM_BOOT_SUPPORT 22085 22086 /* 22087 * Function: 22088 * _bcm_xgs3_l3_ecmp_group_hash_calc 22089 * Purpose: 22090 * Calculate ecmp group next hops hash(signature). 22091 * Parameters: 22092 * unit - (IN)SOC unit number. 22093 * ecmp_group_index - (IN)Ecmp group index 22094 * ecmp_group - (IN)Ecmp group. 22095 * ecmp_count - (IN)Ecmp group next hops count. 22096 * hash - (OUT) Hash(signature) calculated value. 22097 * Returns: 22098 * BCM_X_XXX 22099 */ 22100 STATIC int 22101 _bcm_xgs3_l3_ecmp_group_hash_calc(int unit, int ecmp_group_index, 22102 int *ecmp_group, int ecmp_count, uint16 *hash) 22103 { 22104 int rv = BCM_E_NONE; 22105 int *dlb_ecmp_group = NULL; 22106 _bcm_l3_ecmp_group_buffer_t ecmp_buffer; 22107 22108 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 22109 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 22110 bcm_l3_egress_ecmp_t ecmp; 22111 int location_offset = 0; 22112 int primary_count = 0; 22113 int i = 0, j = 0; 22114 int ecmp_max_paths = 0; 22115 SHR_BITDCL *group_bitmap_ptr = NULL; 22116 22117 bcm_l3_egress_ecmp_t_init(&ecmp); 22118 ecmp.ecmp_intf = ecmp_group_index + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 22119 rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, &ecmp); 22120 if (BCM_FAILURE(rv)) { 22121 return rv; 22122 } 22123 22124 if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp.dynamic_mode)) { 22125 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_index, 22126 &ecmp_max_paths); 22127 if (BCM_FAILURE(rv)) { 22128 return rv; 22129 } 22130 22131 group_bitmap_ptr = 22132 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_index); 22133 22134 if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 22135 SHR_BITCOUNT_RANGE(group_bitmap_ptr, primary_count, 22136 0, ecmp_max_paths / 2); 22137 /* Only alternate members exist */ 22138 if (0 == primary_count) { 22139 location_offset = ecmp_max_paths / 2; 22140 } 22141 } 22142 /* Allocate DLB ecmp group buffer. */ 22143 rv = _bcm_xgs3_l3_ecmp_group_alloc(unit, &dlb_ecmp_group); 22144 if (BCM_FAILURE(rv)) { 22145 return rv; 22146 } 22147 22148 /* Exclude filler members from expanded DLB group */ 22149 for (i = 0; i < ecmp_count; i++) { 22150 if (SHR_BITGET(group_bitmap_ptr, i + location_offset)) { 22151 dlb_ecmp_group[j++] = ecmp_group[i]; 22152 } 22153 } 22154 ecmp_buffer.dlb_group_buffer = dlb_ecmp_group; 22155 } else { 22156 ecmp_buffer.dlb_group_buffer = NULL; 22157 } 22158 }else 22159 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */ 22160 { 22161 ecmp_buffer.dlb_group_buffer = NULL; 22162 } 22163 22164 ecmp_buffer.group_buffer = ecmp_group; 22165 22166 /* Compute signature and reference count for ECMP group */ 22167 _bcm_xgs3_ecmp_grp_hash_calc(unit, (void *)&ecmp_buffer, hash); 22168 22169 if (dlb_ecmp_group) { 22170 sal_free(dlb_ecmp_group); 22171 } 22172 22173 return rv; 22174 } 22175 22176 /* 22177 * Function: 22178 * _bcm_xgs3_defip_state_recover 22179 * Purpose: 22180 * Recover route table references & usage counters 22181 * after warm reboot. 22182 * Parameters: 22183 * unit - (IN)SOC unit number. 22184 * lpm_cfg - (IN)Route info. 22185 * nh_ecmp_idx - (IN)Next hop /Ecmp group index. 22186 * Returns: 22187 * BCM_E_XXX 22188 */ 22189 STATIC int 22190 _bcm_xgs3_defip_state_recover(int unit, _bcm_defip_cfg_t *lpm_cfg, int 22191 nh_ecmp_idx) 22192 22193 { 22194 int *ecmp_group; /* Ecmp group from hw. */ 22195 int ecmp_count; /* Ecmp group size. */ 22196 _bcm_l3_tbl_t *nh_tbl_ptr; /* Next hop table ptr. */ 22197 _bcm_l3_tbl_t *ecmp_tbl_ptr; /* ECMP table ptr. */ 22198 int rv; /* Operation return status. */ 22199 22200 /* Get table pointers */ 22201 nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 22202 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 22203 22204 #ifdef BCM_TOMAHAWK3_SUPPORT 22205 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical) 22206 && (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) && 22207 (nh_ecmp_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) { 22208 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 22209 } 22210 #endif 22211 22212 /* Allocate ecmp group buffer. */ 22213 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group)); 22214 22215 /* Update defip book-keeping info */ 22216 if ((lpm_cfg->defip_flags & BCM_L3_IP6) == BCM_L3_IP6) { 22217 BCM_XGS3_L3_DEFIP_IP6_CNT(unit)++; 22218 } else { 22219 BCM_XGS3_L3_DEFIP_IP4_CNT(unit)++; 22220 } 22221 22222 if (lpm_cfg->defip_ecmp) { 22223 /* Translate ecmp index to ecmp group id. */ 22224 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 22225 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 22226 } 22227 22228 /* Increment ecmp group reference count. */ 22229 BCM_XGS3_L3_ENT_REF_CNT_INC(ecmp_tbl_ptr, nh_ecmp_idx, 22230 BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 22231 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE); 22232 22233 /* If route is multipath get next hops from ecmp group. */ 22234 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 22235 ecmp_group, &ecmp_count); 22236 if (BCM_FAILURE(rv)) { 22237 sal_free(ecmp_group); 22238 return (rv); 22239 } 22240 22241 /* Set ecmp in use flag if needed. */ 22242 if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) { 22243 BCM_XGS3_L3_ECMP_IN_USE(unit) = TRUE; 22244 } 22245 22246 rv = _bcm_xgs3_l3_ecmp_group_hash_calc( 22247 unit, nh_ecmp_idx, ecmp_group, ecmp_count, 22248 &BCM_XGS3_L3_ENT_HASH(ecmp_tbl_ptr, nh_ecmp_idx)); 22249 if (BCM_FAILURE(rv)) { 22250 sal_free(ecmp_group); 22251 return (rv); 22252 } 22253 } else { /* Unipath route. */ 22254 /* Set reference count to nh_hop table entry */ 22255 BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, nh_ecmp_idx, 22256 _BCM_SINGLE_WIDE); 22257 } 22258 sal_free(ecmp_group); 22259 return (BCM_E_NONE); 22260 } 22261 22262 /* 22263 * Function: 22264 * _bcm_xgs3_l3_ecmp_reinit 22265 * Purpose: 22266 * Recover basic ECMP groups table info 22267 * Parameters: 22268 * unit - SOC unit number 22269 * Returns: 22270 * BCM_E_XXX 22271 */ 22272 STATIC int 22273 _bcm_xgs3_l3_ecmp_reinit(int unit, int ecmp_max_paths, int *ecmp_refcnt) 22274 { 22275 int index_min; /* First entry index. */ 22276 int index_max; /* Last entry index. */ 22277 int idx; 22278 uint32 entry[SOC_MAX_MEM_WORDS]; /* Buffer. */ 22279 _bcm_l3_tbl_t *nh_tbl_ptr; /* Next hop table ptr. */ 22280 _bcm_l3_tbl_t *ecmp_tbl_ptr; /* ECMP table ptr. */ 22281 int *ecmp_group; 22282 int rv=0, ecmp_count=0; 22283 int nh_idx=0, grp_idx=0, grp_max_idx=0, grp_min_idx=0; 22284 int ecmp_grp_idx = 0; 22285 int ecmp_grp_record_width = _BCM_SINGLE_WIDE; 22286 uint16 entry_hash = 0; 22287 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 22288 _bcm_l3_cfg_t l3_cfg; /* Extracted L3 entry */ 22289 22290 sal_memset(entry , 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 22291 22292 #if defined(BCM_HAWKEYE_SUPPORT) 22293 if (SOC_IS_HAWKEYE(unit)) { 22294 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0; 22295 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = 0; 22296 return BCM_E_NONE; 22297 } 22298 #endif 22299 if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) { 22300 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0; 22301 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = 0; 22302 return BCM_E_NONE; 22303 } 22304 22305 if (soc_feature(unit, soc_feature_l3_no_ecmp)) { 22306 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0; 22307 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = 0; 22308 return BCM_E_NONE; 22309 } 22310 /* Get table pointers */ 22311 nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 22312 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 22313 22314 /* Get ECMP table start & end index. */ 22315 ecmp_tbl_ptr->idx_min = index_min = 22316 soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, ecmp)); 22317 ecmp_tbl_ptr->idx_max = index_max = 22318 soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ecmp)); 22319 BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = index_max - index_min + 1; 22320 ecmp_tbl_ptr->idx_maxused = ecmp_tbl_ptr->idx_min; 22321 22322 #ifdef BCM_TRIUMPH2_SUPPORT 22323 BCM_XGS3_L3_MAX_ECMP_MODE(unit) = (SOC_IS_TRIUMPH3(unit)) ? TRUE : 22324 soc_property_get(unit, spn_L3_MAX_ECMP_MODE, 0); 22325 #endif /* BCM_TRIUMPH2_SUPPORT */ 22326 22327 /* Restore ECMP max paths info (from level 2 recovery) */ 22328 /* For level-1 warmboot, leave the value at its default */ 22329 if (ecmp_max_paths != 0) { 22330 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = ecmp_max_paths; 22331 } 22332 22333 /* Initialize the number of ECMP groups */ 22334 ecmp_tbl_ptr->idx_max = BCM_XGS3_L3_ECMP_TBL_SIZE(unit) / 22335 BCM_XGS3_L3_ECMP_MAX_PATHS(unit) - 1; 22336 22337 grp_max_idx = ecmp_tbl_ptr->idx_max; 22338 22339 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 22340 if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 22341 /* Here, the max possible groups (and max group index) is limited by 22342 * the size of L3_ECMP_COUNTm table. To support dynamic 22343 * per-ecmp-group size, two entries are added to the L3_ECMP_COUNTm 22344 * table per group: 22345 * 22346 * L3_ECMP_COUNTm Table: 22347 * Group # Entry idx COUNTf 22348 * 0 ------> 0 Current ecmp path count for group 0. 22349 * 1 Max size for group 0. 22350 * 2 ------> 2 Current ecmp path count for group 2. 22351 * 3 Max size for group 2. 22352 * ...so on... 22353 * (Tbl size - 2)-->(Tbl size-2) Current path count for this group. 22354 * (Tbl size-1) Max size for this group. 22355 */ 22356 grp_max_idx = soc_mem_index_count(unit, L3_ECMP_COUNTm) - 2; 22357 ecmp_tbl_ptr->idx_max = grp_max_idx + 1; 22358 } else { 22359 grp_max_idx = soc_mem_index_count(unit, L3_ECMP_COUNTm) - 1; 22360 ecmp_tbl_ptr->idx_max = grp_max_idx; 22361 } 22362 } 22363 22364 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 22365 /* if there is split in table then set split range */ 22366 bcmi_xgs3_l3_ecmp_tbl_split_range_init(unit, ecmp_tbl_ptr); 22367 #endif 22368 22369 /* 22370 * Determine the group entry-width. 22371 * This logic should be in sync with that in _bcm_xgs3_ecmp_group_add 22372 */ 22373 #ifdef BCM_TRX_SUPPORT 22374 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 22375 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 22376 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 22377 ecmp_grp_record_width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 22378 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 22379 #ifdef BCM_TRIUMPH3_SUPPORT 22380 if (SOC_IS_TRIUMPH3(unit)) { 22381 ecmp_grp_record_width = _BCM_SINGLE_WIDE; 22382 } 22383 #endif 22384 } else if (SOC_IS_TRIDENT(unit)) { 22385 ecmp_grp_record_width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 22386 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 22387 } else if (SOC_IS_SCORPION(unit)) { 22388 ecmp_grp_record_width = ecmp_max_paths; 22389 } else { 22390 ecmp_grp_record_width = ecmp_max_paths; 22391 if (SOC_IS_TRIUMPH2(unit) || 22392 SOC_IS_APOLLO(unit) || 22393 SOC_IS_VALKYRIE2(unit) || 22394 SOC_IS_KATANAX(unit) || 22395 SOC_IS_GREYHOUND(unit) || 22396 SOC_IS_HURRICANE3(unit) || 22397 SOC_IS_GREYHOUND2(unit)) { 22398 ecmp_grp_record_width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 22399 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 22400 } 22401 } 22402 } 22403 } 22404 #endif /* BCM_TRX_SUPPORT */ 22405 22406 #ifdef BCM_TRIUMPH3_SUPPORT 22407 22408 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 22409 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 22410 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 22411 BCM_IF_ERROR_RETURN(bcm_th2_ecmp_dlb_hw_recover(unit)); 22412 } else 22413 #endif /* BCM_TOMAHAWK2_SUPPORT */ 22414 { 22415 BCM_IF_ERROR_RETURN(bcm_tr3_ecmp_dlb_hw_recover(unit)); 22416 } 22417 } 22418 #endif /* BCM_TRIUMPH3_SUPPORT */ 22419 22420 /* Allocate ecmp group buffer */ 22421 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group)); 22422 22423 grp_min_idx = ecmp_tbl_ptr->idx_min; 22424 22425 #ifdef BCM_TOMAHAWK3_SUPPORT 22426 if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical) 22427 && (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) { 22428 _bcm_l3_tbl_t *hecmp_tbl_ptr; /* HECMP table ptr. */ 22429 22430 hecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp); 22431 grp_min_idx = (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2); 22432 for (grp_idx = hecmp_tbl_ptr->idx_min; grp_idx <= hecmp_tbl_ptr->idx_max;) { 22433 int ecmp_idx = 0; 22434 int max_ecmp_cnt; 22435 /* Increment ECMP group reference count. */ 22436 BCM_XGS3_L3_ENT_REF_CNT_INC(hecmp_tbl_ptr, grp_idx, 22437 ecmp_grp_record_width); 22438 22439 /* Get next hops from ECMP group */ 22440 sal_memset(ecmp_group, 0, sizeof(int) * BCM_XGS3_L3_ECMP_MAX(unit)); 22441 rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, ecmp_group, &ecmp_count); 22442 if (BCM_FAILURE(rv)) { 22443 sal_free(ecmp_group); 22444 return (rv); 22445 } 22446 22447 if ((ecmp_refcnt[grp_idx] < 1)) { 22448 BCM_XGS3_L3_ENT_REF_CNT_DEC(hecmp_tbl_ptr, grp_idx, 22449 ecmp_grp_record_width); 22450 22451 /* 22452 * There maybe entries starting at any index when added 22453 * with specific ID. Look for the immediate next index. 22454 */ 22455 grp_idx+=1; 22456 continue; 22457 } 22458 22459 /* Set ecmp in use flag if needed. */ 22460 if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) { 22461 BCM_XGS3_L3_ECMP_IN_USE(unit) = TRUE; 22462 } 22463 22464 /* Compute signature and reference count for ECMP group */ 22465 rv = _bcm_xgs3_l3_ecmp_group_hash_calc(unit, grp_idx, ecmp_group, 22466 ecmp_count, &entry_hash); 22467 if (BCM_FAILURE(rv)) { 22468 sal_free(ecmp_group); 22469 return (rv); 22470 } 22471 22472 BCM_XGS3_L3_ENT_HASH_UPDATE(hecmp_tbl_ptr, grp_idx, 22473 ecmp_grp_record_width, entry_hash); 22474 22475 /* Loop over all ecmp group members and increment nh reference count.*/ 22476 for (nh_idx = 0; nh_idx < ecmp_count; nh_idx++) { 22477 /* Skip over members that are not NH indices */ 22478 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 22479 ecmp_group[nh_idx])) { 22480 continue; 22481 } 22482 BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, ecmp_group[nh_idx], 22483 _BCM_SINGLE_WIDE); 22484 } 22485 /* Update max table index used */ 22486 if (hecmp_tbl_ptr->idx_maxused < grp_idx) { 22487 hecmp_tbl_ptr->idx_maxused = grp_idx; 22488 } 22489 22490 BCM_IF_ERROR_RETURN( 22491 _bcm_xgs3_l3_ecmp_grp_info_get(unit, grp_idx, 22492 NULL, &ecmp_idx)); 22493 22494 max_ecmp_cnt = 0; 22495 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, grp_idx, &max_ecmp_cnt); 22496 if (BCM_FAILURE(rv)) { 22497 return rv; 22498 } 22499 22500 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 22501 ecmp_idx, max_ecmp_cnt); 22502 22503 BCM_XGS3_L3_ECMP_GRP_CNT(unit)++; 22504 22505 /* 22506 * Record was found. Next index will be after this 22507 * record's width. 22508 */ 22509 grp_idx+=ecmp_grp_record_width; 22510 } 22511 } 22512 #endif 22513 22514 for (grp_idx = grp_min_idx; grp_idx <= grp_max_idx;) { 22515 #ifdef BCM_TRIDENT2_SUPPORT 22516 /* In Trident2, VP LAGs share the same table as ECMP group table. 22517 * The first N entries are reserved for VP LAGs, where N is the 22518 * value of the config property max_vp_lags. 22519 */ 22520 if (soc_feature(unit, soc_feature_vp_lag)) { 22521 int max_vp_lags; 22522 22523 max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS, 22524 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 22525 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 22526 /* 22527 * TD2P has split indexes for overlay and underlay. 22528 * vp lags are in second range for underlay domain. 22529 * therefore skip indexes which are reserved for vp lag. 22530 */ 22531 if ((ecmp_tbl_ptr->split_idx > 0)) { 22532 22533 if ((grp_idx >= ecmp_tbl_ptr->split_idx) && 22534 (grp_idx <= ecmp_tbl_ptr->split_idx + max_vp_lags - 1)) { 22535 grp_idx = ecmp_tbl_ptr->split_idx + max_vp_lags; 22536 continue; 22537 } 22538 } else 22539 #endif 22540 { 22541 if (grp_idx < max_vp_lags) { 22542 grp_idx = max_vp_lags; 22543 continue; 22544 } 22545 22546 } 22547 } 22548 #endif /* BCM_TRIDENT2_SUPPORT */ 22549 22550 22551 /* Increment ECMP group reference count. */ 22552 BCM_XGS3_L3_ENT_REF_CNT_INC(ecmp_tbl_ptr, grp_idx, 22553 ecmp_grp_record_width); 22554 22555 /* Get next hops from ECMP group */ 22556 sal_memset(ecmp_group, 0, sizeof(int) * BCM_XGS3_L3_ECMP_MAX(unit)); 22557 rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, ecmp_group, &ecmp_count); 22558 if (BCM_FAILURE(rv)) { 22559 sal_free(ecmp_group); 22560 return (rv); 22561 } 22562 22563 if ((ecmp_refcnt[grp_idx] < 1)) { 22564 BCM_XGS3_L3_ENT_REF_CNT_DEC(ecmp_tbl_ptr, grp_idx, 22565 ecmp_grp_record_width); 22566 22567 /* 22568 * There maybe entries starting at any index when added 22569 * with specific ID. Look for the immediate next index. 22570 */ 22571 grp_idx+=1; 22572 continue; 22573 } 22574 22575 /* Set ecmp in use flag if needed. */ 22576 if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) { 22577 BCM_XGS3_L3_ECMP_IN_USE(unit) = TRUE; 22578 } 22579 22580 /* Compute signature and reference count for ECMP group */ 22581 rv = _bcm_xgs3_l3_ecmp_group_hash_calc(unit, grp_idx, ecmp_group, 22582 ecmp_count, &entry_hash); 22583 if (BCM_FAILURE(rv)) { 22584 sal_free(ecmp_group); 22585 return (rv); 22586 } 22587 22588 BCM_XGS3_L3_ENT_HASH_UPDATE(ecmp_tbl_ptr, grp_idx, 22589 ecmp_grp_record_width, entry_hash); 22590 22591 /* Loop over all ecmp group members and increment nh reference count.*/ 22592 for (nh_idx = 0; nh_idx < ecmp_count; nh_idx++) { 22593 /* Skip over members that are not NH indices */ 22594 if (soc_feature(unit, soc_feature_hierarchical_ecmp) || 22595 soc_feature(unit, soc_feature_multi_level_ecmp)) { 22596 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 22597 ecmp_group[nh_idx])) { 22598 continue; 22599 } 22600 } 22601 BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, ecmp_group[nh_idx], 22602 _BCM_SINGLE_WIDE); 22603 } 22604 /* Update max table index used */ 22605 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 22606 if ((BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) && 22607 (ecmp_tbl_ptr->split_idx > grp_idx))) { 22608 if (grp_idx > ecmp_tbl_ptr->split_maxused) { 22609 ecmp_tbl_ptr->split_maxused = grp_idx; 22610 } 22611 } else 22612 #endif 22613 { 22614 if (ecmp_tbl_ptr->idx_maxused < grp_idx) { 22615 ecmp_tbl_ptr->idx_maxused = grp_idx; 22616 } 22617 } 22618 if (SOC_IS_TD_TT(unit)) { 22619 int ecmp_idx = 0; 22620 int max_ecmp_cnt; 22621 22622 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 22623 BCM_IF_ERROR_RETURN( 22624 _bcm_xgs3_l3_ecmp_grp_info_get(unit, grp_idx, 22625 NULL, &ecmp_idx)); 22626 22627 max_ecmp_cnt = 0; 22628 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, grp_idx, &max_ecmp_cnt); 22629 if (BCM_FAILURE(rv)) { 22630 return rv; 22631 } 22632 22633 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 22634 ecmp_idx, max_ecmp_cnt); 22635 } 22636 } 22637 22638 BCM_XGS3_L3_ECMP_GRP_CNT(unit)++; 22639 22640 /* 22641 * Record was found. Next index will be after this 22642 * record's width. 22643 */ 22644 grp_idx+=ecmp_grp_record_width; 22645 } 22646 22647 sal_free(ecmp_group); 22648 22649 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4))) { 22650 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v4)); 22651 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v4)); 22652 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v4), 22653 BCM_XGS3_L3_ENT_SZ(unit, v4), 22654 "l3_tbl", &l3_tbl_ptr, NULL); 22655 if (BCM_FAILURE(rv)) { 22656 l3_tbl_ptr = NULL; 22657 } 22658 /* Loop over all valid IPV4 unicast entries to get ECMP group use count. */ 22659 for (idx = index_min; idx <= index_max; idx++) { 22660 sal_memset(&l3_cfg, 0, sizeof(_bcm_l3_cfg_t)); 22661 BCM_XGS3_L3_MODULE_LOCK(unit); 22662 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)( 22663 unit, l3_tbl_ptr, idx, 22664 &l3_cfg, &ecmp_grp_idx); 22665 BCM_XGS3_L3_MODULE_UNLOCK(unit); 22666 if (rv == BCM_E_NOT_FOUND) { 22667 continue; 22668 } else if (BCM_FAILURE(rv)) { 22669 goto cleanup; 22670 } 22671 if ((l3_cfg.l3c_flags & BCM_L3_IP6) == BCM_L3_IP6) { 22672 continue; 22673 } 22674 if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) { 22675 continue; 22676 } 22677 22678 if(l3_cfg.l3c_flags & BCM_L3_MULTIPATH){ 22679 /* Increment ecmp group reference count. */ 22680 BCM_XGS3_L3_ENT_REF_CNT_INC 22681 (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), ecmp_grp_idx, ecmp_grp_record_width); 22682 } 22683 } 22684 if (l3_tbl_ptr) { 22685 soc_cm_sfree(unit, l3_tbl_ptr); 22686 l3_tbl_ptr = NULL; 22687 } 22688 } 22689 22690 if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v6))) { 22691 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v6)); 22692 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v6)); 22693 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v6), 22694 BCM_XGS3_L3_ENT_SZ(unit, v6), 22695 "l3_tbl", &l3_tbl_ptr, NULL); 22696 if (BCM_FAILURE(rv)) { 22697 l3_tbl_ptr = NULL; 22698 } 22699 /* 22700 * Loop over all valid IPV6 unicast entries to get ECMP group use count. 22701 */ 22702 for (idx = index_min; idx <= index_max; idx++) { 22703 l3_cfg.l3c_flags = BCM_L3_IP6; 22704 BCM_XGS3_L3_MODULE_LOCK(unit); 22705 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)( 22706 unit, l3_tbl_ptr, idx, &l3_cfg, &ecmp_grp_idx); 22707 BCM_XGS3_L3_MODULE_UNLOCK(unit); 22708 if (rv == BCM_E_NOT_FOUND) { 22709 continue; 22710 } else if (BCM_FAILURE(rv)) { 22711 goto cleanup; 22712 } 22713 if ((l3_cfg.l3c_flags & BCM_L3_IP6) != BCM_L3_IP6) { 22714 continue; 22715 } 22716 if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) { 22717 continue; 22718 } 22719 22720 if(l3_cfg.l3c_flags & BCM_L3_MULTIPATH){ 22721 /* Increment ecmp group reference count. */ 22722 BCM_XGS3_L3_ENT_REF_CNT_INC 22723 (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), ecmp_grp_idx, ecmp_grp_record_width); 22724 } 22725 } 22726 if (l3_tbl_ptr) { 22727 soc_cm_sfree(unit, l3_tbl_ptr); 22728 l3_tbl_ptr = NULL; 22729 } 22730 } 22731 22732 #ifdef BCM_TRIDENT2_SUPPORT 22733 if (SOC_IS_TRIDENT2X(unit) && 22734 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 22735 BCM_IF_ERROR_RETURN(bcm_td2_ecmp_rh_hw_recover(unit)); 22736 } 22737 #endif /* BCM_TRIDENT2_SUPPORT */ 22738 22739 rv = BCM_E_NONE; 22740 cleanup: 22741 if (l3_tbl_ptr) { 22742 soc_cm_sfree(unit, l3_tbl_ptr); 22743 } 22744 22745 return rv; 22746 } 22747 #endif /* BCM_WARM_BOOT_SUPPORT */ 22748 22749 /* 22750 * Function: 22751 * _bcm_xgs3_defip_traverse_cb 22752 * Purpose: 22753 * Walk entries in DEFIP table. 22754 * Parameters: 22755 * unit - (IN)SOC unit number. 22756 * pattern - (IN)Match pattern. 22757 * data1 - (IN)Route info. 22758 * data2 - (IN)Next hop info. 22759 * cmp_result- (OUT)Comparison result (Always negative). 22760 * Returns: 22761 * BCM_E_XXX 22762 */ 22763 STATIC int 22764 _bcm_xgs3_defip_traverse_cb(int unit, void *pattern, 22765 void *data1, void *data2, int *cmp_result) 22766 { 22767 _bcm_l3_trvrs_data_t *trv_data; /* Traverse data. */ 22768 _bcm_trvs_range_t *range_info; /* Travers start/end/count info.*/ 22769 _bcm_defip_cfg_t *lpm_cfg; /* Route information. */ 22770 int nh_ecmp_idx; /* Next hop/ecmp group index. */ 22771 int ecmp_count = 0; /* Ecmp group size. */ 22772 int *ecmp_group; /* Ecmp group from hw. */ 22773 int idx; /* Iteration index. */ 22774 int rv; /* Operation return status. */ 22775 22776 /* Cast input parameters. */ 22777 trv_data = (_bcm_l3_trvrs_data_t *) pattern; 22778 range_info = (_bcm_trvs_range_t *) trv_data->pattern; 22779 lpm_cfg = (_bcm_defip_cfg_t *) data1; 22780 nh_ecmp_idx = *(int *)data2; 22781 22782 /* We never need to call operational callback. */ 22783 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 22784 22785 #ifdef BCM_WARM_BOOT_SUPPORT 22786 if (SOC_WARM_BOOT(unit)) { 22787 rv = _bcm_xgs3_defip_state_recover(unit, lpm_cfg, nh_ecmp_idx); 22788 if (BCM_FAILURE(rv)) { 22789 return (rv); 22790 } 22791 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 22792 if (soc_feature(unit, soc_feature_ipmc_defip)) { 22793 rv = bcm_td2p_defip_mc_route_check(unit, lpm_cfg); 22794 } 22795 #endif 22796 return rv; 22797 } 22798 #endif /* BCM_WARM_BOOT_SUPPORT */ 22799 22800 22801 if ((lpm_cfg->defip_ecmp) && 22802 (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))) { 22803 /* Allocate ecmp group buffer. */ 22804 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group)); 22805 22806 /* If route is multipath get next hops from ecmp group. */ 22807 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 22808 ecmp_group, &ecmp_count); 22809 if (BCM_FAILURE(rv)) { 22810 sal_free(ecmp_group); 22811 return (rv); 22812 } 22813 22814 /* Set number of ecmp paths. */ 22815 lpm_cfg->defip_ecmp_count = ecmp_count; 22816 22817 /* Loop over all ecmp group members and check outgoing interface. */ 22818 for (idx = 0; idx < ecmp_count; idx++) { 22819 /* Check number of routes reported. */ 22820 if (range_info->start > range_info->current_count) { 22821 range_info->current_count++; 22822 continue; 22823 } 22824 if (range_info->end < range_info->current_count) { 22825 sal_free(ecmp_group); 22826 return (BCM_E_FULL); 22827 } 22828 range_info->current_count++; 22829 22830 /* Notify caller regarding entry path. */ 22831 _bcm_xgs3_lpm_call_user_cb(unit, trv_data, 22832 lpm_cfg, ecmp_group[idx]); 22833 22834 } /* Loop over ecmp group next hops. */ 22835 sal_free(ecmp_group); 22836 } else { 22837 if (range_info->start > range_info->current_count) { 22838 range_info->current_count++; 22839 return (BCM_E_NONE); 22840 } 22841 22842 if (range_info->end < range_info->current_count) { 22843 return (BCM_E_FULL); 22844 } 22845 range_info->current_count++; 22846 22847 /* Notify caller regarding unused entry. */ 22848 _bcm_xgs3_lpm_call_user_cb(unit, trv_data, lpm_cfg, nh_ecmp_idx); 22849 } 22850 return (BCM_E_NONE); 22851 } 22852 22853 /* 22854 * Function: 22855 * bcm_xgs3_defip_traverse 22856 * Purpose: 22857 * Traverse entries in the DEF_IP table 22858 * Parameters: 22859 * unit - (IN)SOC unit number. 22860 * flags - (IN)IPv4/IPv6. 22861 * start - (IN)Start index of interest. 22862 * end - (IN)End index of interest. 22863 * trav_fn - (IN)Callback function for every entry. 22864 * user_data - (IN)User callback data. 22865 * Returns: 22866 * BCM_E_XXX 22867 */ 22868 int 22869 bcm_xgs3_defip_traverse(int unit, int flags, uint32 start, uint32 end, 22870 bcm_l3_route_traverse_cb trav_fn, void *user_data) 22871 { 22872 _bcm_l3_trvrs_data_t trv_data; /* Traverse information. */ 22873 _bcm_trvs_range_t range_info; /* Start/End/Count information. */ 22874 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 22875 22876 /* Input indexes sanity */ 22877 if (start > end) { 22878 return BCM_E_NOT_FOUND; 22879 } 22880 22881 if (!SOC_WARM_BOOT(unit)) { 22882 /* If table is empty -> there is nothing to delete. */ 22883 BCM_XGS3_L3_IF_DEFIP_CNT_ZERO_RETURN(unit, flags & BCM_L3_IP6); 22884 } 22885 22886 /* Zero traverse info. */ 22887 sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t)); 22888 sal_memset(&range_info, 0, sizeof(_bcm_trvs_range_t)); 22889 22890 range_info.start = start; 22891 range_info.end = end; 22892 /* Fill traverse data struct. */ 22893 trv_data.flags = flags; 22894 trv_data.pattern = &range_info; 22895 /* We need to set both operational & test callback since firebolt 22896 never executes test routine. */ 22897 trv_data.cmp_cb = _bcm_xgs3_defip_traverse_cb; 22898 trv_data.op_cb = _bcm_xgs3_defip_traverse_cb; 22899 trv_data.defip_cb = trav_fn; 22900 trv_data.cookie = user_data; 22901 22902 /* Update/show routes matching the pattern from hw. */ 22903 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) { 22904 BCM_XGS3_L3_MODULE_LOCK(unit); 22905 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data); 22906 BCM_XGS3_L3_MODULE_UNLOCK(unit); 22907 } 22908 /* Handle case we got to the last requested index (end) callback 22909 will return table full, no error in this case. 22910 */ 22911 rv = (rv == BCM_E_FULL) ? BCM_E_NONE : rv; 22912 return rv; 22913 } 22914 22915 /* 22916 * Function: 22917 * bcm_xgs3_defip_ip4_traverse 22918 * Purpose: 22919 * Traverse IPv4 entries in the DEF_IP table 22920 * Parameters: 22921 * unit - (IN)SOC unit number. 22922 * start - (IN)Start index of interest. 22923 * end - (IN)End index of interest. 22924 * trav_fn - (IN)Callback function for every entry. 22925 * user_data - (IN)User callback data. 22926 * Returns: 22927 * BCM_E_XXX 22928 */ 22929 int 22930 bcm_xgs3_defip_ip4_traverse(int unit, uint32 start, uint32 end, 22931 bcm_l3_route_traverse_cb trav_fn, void *user_data) 22932 { 22933 return bcm_xgs3_defip_traverse(unit, 0, start, end, trav_fn, user_data); 22934 } 22935 22936 /* 22937 * Function: 22938 * bcm_xgs3_defip_ip6_traverse 22939 * Purpose: 22940 * Traverse IPv6 entries in the DEF_IP table 22941 * Parameters: 22942 * unit - (IN)SOC unit number. 22943 * start - (IN)Start index of interest. 22944 * end - (IN)End index of interest. 22945 * trav_fn - (IN)Callback function for every entry. 22946 * user_data - (IN)User callback data. 22947 * Returns: 22948 * BCM_E_XXX 22949 */ 22950 int 22951 bcm_xgs3_defip_ip6_traverse(int unit, uint32 start, uint32 end, 22952 bcm_l3_route_traverse_cb trav_fn, void *user_data) 22953 { 22954 return bcm_xgs3_defip_traverse(unit, BCM_L3_IP6, 22955 start, end, trav_fn, user_data); 22956 } 22957 22958 /* 22959 * Function: 22960 * bcm_xgs3_defip_ecmp_get_all 22961 * Purpose: 22962 * Get all paths for a route, useful for ECMP route 22963 * Parameters: 22964 * unit - (IN) SOC device unit number 22965 * the_route - (IN) route's net/mask 22966 * path_array - (OUT) Array of all ECMP paths 22967 * max_path - (IN) Max number of ECMP paths 22968 * path_count - (OUT) Actual number of ECMP paths 22969 * Returns: 22970 * BCM_E_XXX 22971 */ 22972 int 22973 bcm_xgs3_defip_ecmp_get_all(int unit, _bcm_defip_cfg_t *lpm_cfg, 22974 bcm_l3_route_t *path_array, int max_path, 22975 int *path_count) 22976 { 22977 int *ecmp_group; /* Next hop index. */ 22978 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 22979 int ecmp_count = 0; /* Ecmp group size. */ 22980 int idx; /* Iteration index. */ 22981 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 22982 22983 /* Input parameters checks. */ 22984 BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg); 22985 22986 22987 /* Get lpm entry. */ 22988 if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) { 22989 BCM_XGS3_L3_MODULE_LOCK(unit); 22990 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, lpm_cfg, 22991 &nh_ecmp_idx); 22992 BCM_XGS3_L3_MODULE_UNLOCK(unit); 22993 } 22994 BCM_IF_ERROR_RETURN(rv); 22995 22996 if (lpm_cfg->defip_ecmp) { 22997 /* Trunslate next hop index to ecmp group id. */ 22998 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 22999 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 23000 } 23001 /* Allocate ecmp group buffer. */ 23002 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group)); 23003 23004 /* Get ecmp group next hop indexes. */ 23005 rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx, 23006 ecmp_group, &ecmp_count); 23007 if (BCM_FAILURE(rv)) { 23008 sal_free(ecmp_group); 23009 return (rv); 23010 } 23011 23012 /* Set route information. */ 23013 for (idx = 0; ((idx < ecmp_count) && (idx < max_path)); idx++) { 23014 rv = _bcm_xgs3_defip_set_route_info(unit, lpm_cfg, path_array + idx, 23015 ecmp_group[idx]); 23016 if (BCM_FAILURE(rv)) { 23017 sal_free(ecmp_group); 23018 return (rv); 23019 } 23020 } 23021 sal_free(ecmp_group); 23022 /* Fill number of ecmp paths. */ 23023 *path_count = idx; 23024 } else { 23025 BCM_IF_ERROR_RETURN 23026 (_bcm_xgs3_defip_set_route_info(unit, lpm_cfg, path_array, 23027 nh_ecmp_idx)); 23028 *path_count = 1; 23029 } 23030 return (BCM_E_NONE); 23031 } 23032 /* 23033 * Function: 23034 * bcm_xgs3_l3_ip6_prefix_map_get 23035 * Purpose: 23036 * Get a list of IPv6 96 bit prefixes which are mapped to ipv4 lookup 23037 * space. 23038 * Parameters: 23039 * unit - (IN) bcm device. 23040 * map_size - (IN) Size of allocated entries in ip6_array. 23041 * ip6_array - (OUT) Array of mapped prefixes. 23042 * ip6_count - (OUT) Number of entries of ip6_array actually filled in. 23043 * This will be a value less than or equal to the value. 23044 * passed in as map_size unless map_size is 0. If 23045 * map_size is 0 then ip6_array is ignored and 23046 * ip6_count is filled in with the number of entries 23047 * that would have been filled into ip6_array if 23048 * map_size was arbitrarily large. 23049 * Returns: 23050 * BCM_E_XXX 23051 */ 23052 int 23053 bcm_xgs3_l3_ip6_prefix_map_get(int unit, int map_size, 23054 bcm_ip6_t *ip6_array, int *ip6_count) 23055 { 23056 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT) 23057 soc_mem_t mem; /* IPv4 in IPv6 table memory. */ 23058 int tbl_sz; /* IPv4 in IPv6 table size. */ 23059 char *tbl_ptr; /* Dma table pointer. */ 23060 uint32 *buf_p; /* Table entry pointer. */ 23061 int idx; /* Table iterator. */ 23062 int valid_entry_count;/* Table valid entry count. */ 23063 23064 mem = BCM_XGS3_L3_MEM(unit, v6_prefix_map); 23065 23066 /* Check feature support. */ 23067 if (INVALIDm == mem) { 23068 return (BCM_E_UNAVAIL); 23069 } 23070 23071 /* Input parameters sanity check. */ 23072 if ((NULL == ip6_count) || ((NULL == ip6_array) && (0 != map_size))) { 23073 return (BCM_E_PARAM); 23074 } 23075 23076 /* Table DMA the ipv4 in ipv6 table to software copy */ 23077 BCM_IF_ERROR_RETURN 23078 (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map), 23079 "v6_prefix_tbl", &tbl_ptr, &tbl_sz)); 23080 23081 /* Reset destination buffer. */ 23082 valid_entry_count = 0; 23083 if (NULL != ip6_array) { 23084 sal_memset (ip6_array, 0, map_size * sizeof(bcm_ip6_t)); 23085 } 23086 23087 for (idx = 0; idx < tbl_sz; idx++) { 23088 buf_p = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, tbl_ptr, idx); 23089 /* Skip if entry is invalid. */ 23090 if (!soc_mem_field32_get(unit, mem, buf_p, ENABLEf)) { 23091 continue; 23092 } 23093 23094 if (NULL != ip6_array) { 23095 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6_PREFIXf, 23096 ip6_array[valid_entry_count], 23097 SOC_MEM_IP6_UPPER_96BIT); 23098 /* Update number of read entries . */ 23099 if (++valid_entry_count >= map_size) { 23100 break; 23101 } 23102 } else { 23103 valid_entry_count++; 23104 } 23105 } 23106 23107 /* Assign number of valid entries read. */ 23108 *ip6_count = valid_entry_count; 23109 /* Free resources. */ 23110 soc_cm_sfree(unit,tbl_ptr); 23111 23112 return (BCM_E_NONE); 23113 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */ 23114 return (BCM_E_UNAVAIL); 23115 } 23116 23117 /* 23118 * Function: 23119 * bcm_xgs3_l3_ip6_prefix_map_add 23120 * Purpose: 23121 * Create an IPv6 prefix map into IPv4 entry. In case Ipv6 traffic 23122 * destination or source IP address matches upper 96 bits of 23123 * translation entry. traffic will be routed/switched based on 23124 * lower 32 bits of destination/source IP address treated as IPv4 address. 23125 * Parameters: 23126 * unit - (IN) bcm device. 23127 * ip6_addr - (IN) New IPv6 translation address. 23128 * Returns: 23129 * BCM_E_XXX 23130 */ 23131 int 23132 bcm_xgs3_l3_ip6_prefix_map_add(int unit, bcm_ip6_t ip6_addr) 23133 { 23134 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT) 23135 soc_mem_t mem; /* IPv4 in IPv6 table memory. */ 23136 int tbl_sz; /* IPv4 in IPv6 table size. */ 23137 char *tbl_ptr; /* Dma table pointer. */ 23138 uint32 *buf_p; /* Table entry pointer. */ 23139 bcm_ip6_t addr; /* IPv6 prefix map. */ 23140 int rv; /* Operation status. */ 23141 int idx; /* Table iterator. */ 23142 23143 mem = BCM_XGS3_L3_MEM(unit, v6_prefix_map); 23144 23145 /* Check feature support. */ 23146 if (INVALIDm == mem) { 23147 return (BCM_E_UNAVAIL); 23148 } 23149 23150 /* Reset lower 32 bit of ip6 address. */ 23151 sal_memset(((char *)ip6_addr) + 12,0, 4); 23152 23153 /* Table DMA the ipv4 in ipv6 table to software copy */ 23154 rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map), 23155 "v6_prefix_tbl", &tbl_ptr, &tbl_sz); 23156 BCM_IF_ERROR_RETURN(rv); 23157 23158 rv = BCM_E_RESOURCE; /* Assuming there is no room for new entry. */ 23159 for (idx = 0; idx < tbl_sz; idx++) { 23160 buf_p = soc_mem_table_idx_to_pointer (unit, mem, uint32 *, tbl_ptr, idx); 23161 23162 /* Skip if entry is disabled. */ 23163 if (!soc_mem_field32_get(unit, mem, buf_p, ENABLEf)) { 23164 if (BCM_E_RESOURCE == rv) { 23165 soc_mem_field32_set(unit, mem, buf_p, ENABLEf, 1); 23166 23167 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6_PREFIXf, 23168 ip6_addr, SOC_MEM_IP6_UPPER_96BIT); 23169 rv = BCM_E_NONE; 23170 } 23171 continue; 23172 } 23173 23174 /* Extract entry prefix. */ 23175 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6_PREFIXf, addr, 23176 SOC_MEM_IP6_UPPER_96BIT); 23177 23178 /* Compare 12 most significant bytes of address. */ 23179 if (0 == sal_memcmp(addr, ip6_addr, 12)) { 23180 rv = BCM_E_EXISTS; 23181 break; 23182 } 23183 } 23184 23185 /* Write the modified buffer back. */ 23186 if (BCM_SUCCESS(rv)) { 23187 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 23188 soc_mem_index_min(unit, mem), 23189 soc_mem_index_max(unit, mem), tbl_ptr); 23190 } 23191 23192 /* Free resources. */ 23193 soc_cm_sfree(unit,tbl_ptr); 23194 return (rv); 23195 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */ 23196 return (BCM_E_UNAVAIL); 23197 } 23198 23199 /* 23200 * Function: 23201 * bcm_xgs3_l3_ip6_prefix_map_delete 23202 * Purpose: 23203 * Destroy an IPv6 prefix map entry. 23204 * Parameters: 23205 * unit - (IN) bcm device. 23206 * ip6_addr - (IN) IPv6 translation address. 23207 * Returns: 23208 * BCM_E_XXX 23209 */ 23210 int 23211 bcm_xgs3_l3_ip6_prefix_map_delete(int unit, bcm_ip6_t ip6_addr) 23212 { 23213 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT) 23214 soc_mem_t mem; /* IPv4 in IPv6 table memory. */ 23215 int tbl_sz; /* IPv4 in IPv6 table size. */ 23216 char *tbl_ptr; /* Dma table pointer. */ 23217 uint32 *buf_p; /* Table entry pointer. */ 23218 bcm_ip6_t addr; /* IPv6 prefix map. */ 23219 int rv; /* Operation status. */ 23220 int idx; /* Table iterator. */ 23221 23222 mem = BCM_XGS3_L3_MEM(unit, v6_prefix_map); 23223 23224 /* Check feature support. */ 23225 if (INVALIDm == mem) { 23226 return (BCM_E_UNAVAIL); 23227 } 23228 23229 /* Table DMA the ipv4 in ipv6 table to software copy */ 23230 rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map), 23231 "v6_prefix_tbl", &tbl_ptr, &tbl_sz); 23232 BCM_IF_ERROR_RETURN(rv); 23233 23234 rv = BCM_E_NOT_FOUND; 23235 for (idx = 0; idx < tbl_sz; idx++) { 23236 buf_p = soc_mem_table_idx_to_pointer (unit, mem, uint32 *, tbl_ptr, idx); 23237 23238 /* Skip if entry is disabled. */ 23239 if (!soc_mem_field32_get(unit, mem, buf_p, ENABLEf)) { 23240 continue; 23241 } 23242 23243 /* Extract entry prefix. */ 23244 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6_PREFIXf, addr, 23245 SOC_MEM_IP6_UPPER_96BIT); 23246 23247 /* Compare 12 most significant bytes of address. */ 23248 if (0 == sal_memcmp(addr, ip6_addr, 12)) { 23249 soc_mem_field32_set(unit, mem, buf_p, ENABLEf, 0); 23250 rv = BCM_E_NONE; 23251 break; 23252 } 23253 } 23254 23255 if (BCM_SUCCESS(rv)) { 23256 /* Write the buffer back. */ 23257 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 23258 soc_mem_index_min(unit, mem), 23259 soc_mem_index_max(unit, mem), tbl_ptr); 23260 } 23261 /* Free resources. */ 23262 soc_cm_sfree(unit,tbl_ptr); 23263 23264 return (rv); 23265 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */ 23266 return (BCM_E_UNAVAIL); 23267 } 23268 23269 /* 23270 * Function: 23271 * bcm_xgs3_l3_ip6_prefix_map_delete_all 23272 * Purpose: 23273 * Flush all IPv6 prefix maps. 23274 * Parameters: 23275 * unit - (IN) bcm device. 23276 * Returns: 23277 * BCM_E_XXX 23278 */ 23279 int 23280 bcm_xgs3_l3_ip6_prefix_map_delete_all(int unit) 23281 { 23282 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT) 23283 /* Check feature support. */ 23284 if (INVALIDm == BCM_XGS3_L3_MEM(unit, v6_prefix_map)) { 23285 return (BCM_E_UNAVAIL); 23286 } 23287 23288 /* Clear IPv6 prefix map table. */ 23289 BCM_IF_ERROR_RETURN 23290 (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v6_prefix_map))); 23291 23292 return (BCM_E_NONE); 23293 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */ 23294 return (BCM_E_UNAVAIL); 23295 } 23296 23297 /* 23298 * Function: 23299 * _bcm_xgs3_l3_ingress_interface_add 23300 * Purpose: 23301 * Add l3 ingress interface. 23302 * Parameters: 23303 * unit - (IN) Bcm device number. 23304 * iif - (IN/OUT) Ingress interface descriptor. 23305 * Returns: 23306 * BCM_E_XXX 23307 */ 23308 int 23309 _bcm_xgs3_l3_ingress_interface_add(int unit, _bcm_l3_ingress_intf_t *iif) 23310 { 23311 int idx; /* Allocation index */ 23312 int loop_max; /* Max number of tries. */ 23313 int rv; 23314 23315 /* Input parameters check. */ 23316 if (NULL == iif) { 23317 return (BCM_E_PARAM); 23318 } 23319 /* Vrf id range check. */ 23320 if ((iif->vrf > SOC_VRF_MAX(unit)) || 23321 (iif->vrf < BCM_L3_VRF_DEFAULT)) { 23322 if ((!soc_mem_field_valid(unit, L3_IIFm, VRF_VALIDf)) || 23323 ((soc_mem_field_valid(unit, L3_IIFm, VRF_VALIDf) && 23324 (iif->vrf != BCM_L3_VRF_INVALID)))) { 23325 return (BCM_E_PARAM); 23326 } 23327 } 23328 23329 /* Qualification class range check. */ 23330 if ((iif->if_class > SOC_INTF_CLASS_MAX(unit)) || (iif->if_class < 0)) { 23331 return (BCM_E_PARAM); 23332 } 23333 23334 if ((0 == BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_add))) { 23335 return (BCM_E_UNAVAIL); 23336 } 23337 23338 /* Allocate interface class id. */ 23339 if ((iif->flags & BCM_L3_INGRESS_WITH_ID) || (iif->flags & BCM_L3_INGRESS_REPLACE)){ 23340 if ((iif->intf_id >= (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) || 23341 (iif->intf_id < 0)) { 23342 return (BCM_E_PARAM); 23343 } 23344 /* Does entry exist? */ 23345 if (iif->flags & BCM_L3_INGRESS_WITH_ID) { 23346 if (!(iif->flags & BCM_L3_INGRESS_REPLACE) && 23347 (0 != SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), 23348 iif->intf_id))) { 23349 return (BCM_E_EXISTS); 23350 } 23351 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), iif->intf_id); 23352 } 23353 } else { 23354 L3_ING_IF_MIN(unit, idx); 23355 loop_max = BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) - idx; 23356 while (loop_max) { 23357 if (0 == SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx)) { 23358 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx); 23359 iif->intf_id = idx; 23360 break; 23361 } 23362 idx++; 23363 loop_max--; 23364 } 23365 if (0 == loop_max) { 23366 return (BCM_E_FULL); 23367 } 23368 } 23369 23370 BCM_XGS3_L3_MODULE_LOCK(unit); 23371 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_add) (unit, iif, NULL, NULL); 23372 BCM_XGS3_L3_MODULE_UNLOCK(unit); 23373 return rv; 23374 } 23375 23376 /* 23377 * Function: 23378 * _bcm_xgs3_l3_ingress_interface_delete 23379 * Purpose: 23380 * Delete l3 ingress interface. 23381 * Parameters: 23382 * unit - (IN) Bcm device number. 23383 * if_id - (IN) Ingress interface id. 23384 * Returns: 23385 * BCM_E_XXX 23386 */ 23387 int 23388 _bcm_xgs3_l3_ingress_interface_delete(int unit, int intf_id) 23389 { 23390 int rv; 23391 /* Input parameters check. */ 23392 if ((intf_id >= (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) || (intf_id < 0)) { 23393 return (BCM_E_PARAM); 23394 } 23395 23396 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_del)) { 23397 SHR_BITCLR(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_id); 23398 BCM_XGS3_L3_MODULE_LOCK(unit); 23399 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_del) (unit, intf_id); 23400 BCM_XGS3_L3_MODULE_UNLOCK(unit); 23401 return rv; 23402 } 23403 return (BCM_E_UNAVAIL); 23404 } 23405 23406 /* 23407 * Function: 23408 * _bcm_xgs3_l3_ingress_interface_get 23409 * Purpose: 23410 * Get l3 ingress interface. 23411 * Parameters: 23412 * unit - (IN) Bcm device number. 23413 * iif - (IN/OUT) Ingress interface descriptor. 23414 * Returns: 23415 * BCM_E_XXX 23416 */ 23417 int 23418 _bcm_xgs3_l3_ingress_interface_get(int unit, _bcm_l3_ingress_intf_t *iif) 23419 { 23420 int rv; 23421 /* Input parameters check. */ 23422 if (NULL == iif) { 23423 return (BCM_E_PARAM); 23424 } 23425 23426 if ((iif->intf_id >= (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) || 23427 (iif->intf_id < 0)) { 23428 return (BCM_E_PARAM); 23429 } 23430 23431 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_get)) { 23432 BCM_XGS3_L3_MODULE_LOCK(unit); 23433 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_get) (unit, NULL, iif); 23434 BCM_XGS3_L3_MODULE_UNLOCK(unit); 23435 return rv; 23436 } 23437 return (BCM_E_UNAVAIL); 23438 } 23439 23440 /* 23441 * Function: 23442 * _bcm_xgs3_tunnel_type_support_check 23443 * Purpose: 23444 * Check if tunnel type is supported on a device. 23445 * Parameters: 23446 * unit - (IN) Bcm device number. 23447 * tnl_type - (IN) Tunnel type to check. 23448 * tunnel_term - (OUT) Type supported as tunnel terminator. 23449 * tunnel_init - (OUT) Type supported as tunnel initiator. 23450 * Returns: 23451 * BCM_E_XXX 23452 */ 23453 int 23454 _bcm_xgs3_tunnel_type_support_check(int unit, bcm_tunnel_type_t tnl_type, 23455 int *tunnel_term, int *tunnel_init) 23456 { 23457 int term; /* Tunnel Terminator supported. */ 23458 int init; /* Tunnel Initiator supported. */ 23459 23460 switch (tnl_type) { 23461 case bcmTunnelTypeNone: 23462 case bcmTunnelTypeIp4In4: 23463 case bcmTunnelTypeIp6In4: 23464 case bcmTunnelType6In4Uncheck: 23465 case bcmTunnelTypeIsatap: 23466 case bcmTunnelTypePimSmDr1: 23467 case bcmTunnelTypePimSmDr2: 23468 term = init = TRUE; 23469 break; 23470 case bcmTunnelTypeIpAnyIn4: 23471 init = TRUE; 23472 if (soc_feature(unit, soc_feature_tunnel_term_hash_table) || 23473 (soc_feature(unit, soc_feature_tunnel_protocol_match) 23474 && !(soc_property_get(unit, 23475 spn_BCM_TUNNEL_TERM_COMPATIBLE_MODE, 0)))) { 23476 term = FALSE; 23477 } else { 23478 term = TRUE; 23479 } 23480 break; 23481 case bcmTunnelTypeIp4In6: 23482 case bcmTunnelTypeIp6In6: 23483 if (!soc_feature(unit, soc_feature_tunnel_any_in_6)) { 23484 term = init = FALSE; 23485 } else { 23486 term = init = TRUE; 23487 } 23488 break; 23489 case bcmTunnelTypeIpAnyIn6: 23490 if (!soc_feature(unit, soc_feature_tunnel_any_in_6)) { 23491 term = init = FALSE; 23492 } else { 23493 init = TRUE; 23494 if (soc_feature(unit, soc_feature_tunnel_term_hash_table) || 23495 (soc_feature(unit, soc_feature_tunnel_protocol_match) 23496 && !(soc_property_get(unit, 23497 spn_BCM_TUNNEL_TERM_COMPATIBLE_MODE, 0)))) { 23498 term = FALSE; 23499 } else { 23500 term = TRUE; 23501 } 23502 } 23503 break; 23504 case bcmTunnelType6In4: 23505 if (!soc_feature(unit, soc_feature_tunnel_6to4_secure)) { 23506 term = init = FALSE; 23507 } else { 23508 term = init = TRUE; 23509 } 23510 break; 23511 case bcmTunnelTypePim6SmDr1: 23512 case bcmTunnelTypePim6SmDr2: 23513 if (!soc_feature(unit, soc_feature_tunnel_any_in_6)) { 23514 term = init = FALSE; 23515 } else { 23516 init = TRUE; 23517 term = FALSE; 23518 } 23519 break; 23520 case bcmTunnelTypeGre4In4: 23521 case bcmTunnelTypeGre6In4: 23522 case bcmTunnelTypeGreAnyIn4: 23523 if (!soc_feature(unit, soc_feature_tunnel_gre)) { 23524 term = init = FALSE; 23525 } else { 23526 term = init = TRUE; 23527 } 23528 break; 23529 case bcmTunnelTypeGre4In6: 23530 case bcmTunnelTypeGre6In6: 23531 case bcmTunnelTypeGreAnyIn6: 23532 if ((!soc_feature(unit, soc_feature_tunnel_gre)) || 23533 (!soc_feature(unit, soc_feature_tunnel_any_in_6))) { 23534 term = init = FALSE; 23535 } else { 23536 term = init = TRUE; 23537 } 23538 break; 23539 case bcmTunnelTypeUdp: 23540 case bcmTunnelTypeMpls: 23541 term = init = TRUE; 23542 break; 23543 case bcmTunnelTypeWlanWtpToAc: 23544 case bcmTunnelTypeWlanWtpToAc6: 23545 case bcmTunnelTypeWlanAcToAc: 23546 case bcmTunnelTypeWlanAcToAc6: 23547 if (soc_feature(unit, soc_feature_wlan)) { 23548 term = init = TRUE; 23549 } else { 23550 term = init = FALSE; 23551 } 23552 break; 23553 case bcmTunnelTypeAutoMulticast: 23554 case bcmTunnelTypeAutoMulticast6: 23555 if (soc_feature(unit, soc_feature_auto_multicast)) { 23556 term = init = TRUE; 23557 } else { 23558 term = init = FALSE; 23559 } 23560 break; 23561 #ifdef BCM_MONTEREY_SUPPORT 23562 case bcmTunnelTypeRoeIn4: 23563 case bcmTunnelTypeRoeIn6: 23564 if (soc_feature(unit, soc_feature_roe) || 23565 soc_feature(unit, soc_feature_roe_custom)) { 23566 init = TRUE; 23567 term = FALSE; 23568 } else { 23569 term = init = FALSE; 23570 } 23571 break; 23572 #endif 23573 default: 23574 term = init = FALSE; 23575 } 23576 23577 if (NULL != tunnel_term) { 23578 *tunnel_term = term; 23579 } 23580 if (NULL != tunnel_init) { 23581 *tunnel_init = init; 23582 } 23583 return (BCM_E_NONE); 23584 } 23585 23586 /* 23587 * Function: 23588 * _bcm_xgs3_l3_set_tnl_term_type 23589 * Purpose: 23590 * Set tunnel terminator HW type & sub type. 23591 * Parameters: 23592 * unit - (IN)SOC unit number 23593 * tnl_info - (IN)tnl_info Tunnel parameters. 23594 * tnl_type - (OUT)Tunnel type. 23595 * tnl_sub_type - (OUT)Tunnel sub_type 23596 * Returns: 23597 * BCM_E_XXX 23598 */ 23599 int 23600 _bcm_xgs3_l3_set_tnl_term_type(int unit, bcm_tunnel_terminator_t *tnl_info, 23601 _bcm_tnl_term_type_t *tnl_type) 23602 { 23603 /* Input parameters check. */ 23604 if ((NULL == tnl_info) || (NULL == tnl_type)) { 23605 return (BCM_E_PARAM); 23606 } 23607 23608 /* Reset destination buffer first. */ 23609 sal_memset(tnl_type, 0, sizeof(_bcm_tnl_term_type_t)); 23610 23611 /* Set tunnel outer header IP version. */ 23612 tnl_type->tnl_outer_hdr_ipv6 =_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type); 23613 23614 switch (tnl_info->type) { 23615 case bcmTunnelType6In4Uncheck: 23616 tnl_type->tnl_auto = 1; /* automatic tunnel. */ 23617 tnl_type->tnl_sub_type = 0; 23618 tnl_type->tnl_protocol = 0x29; /* 6over4 OR 6to4 */ 23619 break; 23620 case bcmTunnelTypeIsatap: 23621 tnl_type->tnl_auto = 1; /* automatic tunnel. */ 23622 tnl_type->tnl_sub_type = 0x1; 23623 tnl_type->tnl_protocol = 0x29; /* 6over4 OR 6to4 */ 23624 break; 23625 case bcmTunnelType6In4: 23626 tnl_type->tnl_auto = 1; /* automatic tunnel. */ 23627 if (soc_feature(unit, soc_feature_tunnel_6to4_secure)) { 23628 tnl_type->tnl_sub_type = 0x2; 23629 } else { 23630 tnl_type->tnl_sub_type = 0; 23631 } 23632 tnl_type->tnl_protocol = 0x29; /* 6over4 OR 6to4 */ 23633 break; 23634 case bcmTunnelTypeIp4In4: 23635 case bcmTunnelTypeIp4In6: 23636 tnl_type->tnl_auto = 0; /* configured tunnel */ 23637 tnl_type->tnl_sub_type = 0x2; /* IPv4 payload only.*/ 23638 tnl_type->tnl_protocol = 0x04; /* IP in IP */ 23639 break; 23640 case bcmTunnelTypeIp6In4: 23641 case bcmTunnelTypeIp6In6: 23642 tnl_type->tnl_auto = 0; /* configured tunnel */ 23643 tnl_type->tnl_sub_type = 0x1; /* IPv6 payload only. */ 23644 tnl_type->tnl_protocol = 0x29; /* IPv6 */ 23645 break; 23646 case bcmTunnelTypeIpAnyIn4: 23647 case bcmTunnelTypeIpAnyIn6: 23648 tnl_type->tnl_auto = 0; /* configured tunnel */ 23649 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23650 tnl_type->tnl_protocol = 0x04; /* IP in IP */ 23651 break; 23652 case bcmTunnelTypeGre4In4: 23653 case bcmTunnelTypeGre4In6: 23654 tnl_type->tnl_auto = 0; /* configured tunnel */ 23655 tnl_type->tnl_sub_type = 0x2; /* IPv4 payload only.*/ 23656 tnl_type->tnl_gre = 0x1; /* GRE tunnel. */ 23657 tnl_type->tnl_gre_v4_payload = 0x1;/* IPv4 payload only.*/ 23658 tnl_type->tnl_protocol = 0x2F; /* Protocol GRE */ 23659 break; 23660 case bcmTunnelTypeGre6In4: 23661 case bcmTunnelTypeGre6In6: 23662 tnl_type->tnl_auto = 0; /* configured tunnel */ 23663 tnl_type->tnl_sub_type = 0x1; /* IPv6 payload only.*/ 23664 tnl_type->tnl_gre = 0x1; /* GRE tunnel. */ 23665 tnl_type->tnl_gre_v6_payload = 0x1;/* IPv4 payload only.*/ 23666 tnl_type->tnl_protocol = 0x2F; /* Protocol GRE */ 23667 break; 23668 case bcmTunnelTypeGreAnyIn4: 23669 case bcmTunnelTypeGreAnyIn6: 23670 tnl_type->tnl_auto = 0; /* configured tunnel */ 23671 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23672 tnl_type->tnl_gre = 0x1; /* GRE tunnel. */ 23673 tnl_type->tnl_gre_v4_payload = 0x1;/* IPv4 payload only. */ 23674 tnl_type->tnl_gre_v6_payload = 0x1;/* IPv4 payload only. */ 23675 tnl_type->tnl_protocol = 0x2F; /* Protocol GRE */ 23676 break; 23677 case bcmTunnelTypePimSmDr1: 23678 case bcmTunnelTypePimSmDr2: 23679 case bcmTunnelTypePim6SmDr1: 23680 case bcmTunnelTypePim6SmDr2: 23681 tnl_type->tnl_auto = 0; /* configured tunnel */ 23682 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23683 tnl_type->tnl_pim_sm = 0x1; /* PIM SM tunnel. */ 23684 tnl_type->tnl_protocol = 0x67; /* Protocol PIM */ 23685 break; 23686 case bcmTunnelTypeUdp: 23687 tnl_type->tnl_auto = 0; /* configured tunnel */ 23688 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23689 tnl_type->tnl_udp = 0x1; /* UDP tunnel. */ 23690 tnl_type->tnl_protocol = 0x11; /* Protocol UDP */ 23691 break; 23692 case bcmTunnelTypeWlanWtpToAc: 23693 tnl_type->tnl_auto = 0; /* configured tunnel */ 23694 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23695 tnl_type->tnl_udp_type = 0x1; /* UDP tunnel. */ 23696 tnl_type->tnl_protocol = 0x11; /* Protocol UDP */ 23697 break; 23698 case bcmTunnelTypeWlanAcToAc: 23699 tnl_type->tnl_auto = 0; /* configured tunnel */ 23700 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23701 tnl_type->tnl_udp_type = 0x0; /* UDP tunnel. */ 23702 tnl_type->tnl_protocol = 0x11; /* Protocol UDP */ 23703 break; 23704 case bcmTunnelTypeWlanWtpToAc6: 23705 tnl_type->tnl_auto = 0; /* configured tunnel */ 23706 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23707 tnl_type->tnl_udp_type = 0x1; /* UDP tunnel. */ 23708 tnl_type->tnl_protocol = 0x88; /* Protocol UDP lite */ 23709 break; 23710 case bcmTunnelTypeWlanAcToAc6: 23711 tnl_type->tnl_auto = 0; /* configured tunnel */ 23712 tnl_type->tnl_sub_type = 0x3; /* IPv4 & IPv6 payload. */ 23713 tnl_type->tnl_udp_type = 0x0; /* UDP tunnel. */ 23714 tnl_type->tnl_protocol = 0x88; /* Protocol UDP lite */ 23715 break; 23716 case bcmTunnelTypeAutoMulticast: 23717 case bcmTunnelTypeAutoMulticast6: 23718 tnl_type->tnl_auto = 0; /* Configured tunnel */ 23719 tnl_type->tnl_sub_type = 0x2; 23720 tnl_type->tnl_udp_type = 0x2; /* AMT tunnel. */ 23721 tnl_type->tnl_protocol = 0x11; /* Protocol UDP */ 23722 break; 23723 default: 23724 return (BCM_E_PARAM); 23725 } 23726 return (BCM_E_NONE); 23727 } 23728 23729 /* 23730 * Function: 23731 * bcm_xgs3_l3_get_tnl_term_type 23732 * Purpose: 23733 * Get tunnel terminator API type 23734 * Parameters: 23735 * unit - (IN)SOC unit number 23736 * tnl_info - (IN/OUT)tnl_info Tunnel parameters. 23737 * tnl_type - (IN)Tunnel type. 23738 * Returns: 23739 * BCM_E_XXX 23740 */ 23741 int 23742 _bcm_xgs3_l3_get_tnl_term_type(int unit, bcm_tunnel_terminator_t *tnl_info, 23743 _bcm_tnl_term_type_t *tnl_type) 23744 23745 { 23746 int v6; /* Outer header is ipv6. */ 23747 23748 /* Input parameters check. */ 23749 if ((NULL == tnl_type) || (NULL == tnl_info)) { 23750 return (BCM_E_PARAM); 23751 } 23752 23753 if (tnl_type->tnl_auto) { /* Automatic tunnel */ 23754 switch (tnl_type->tnl_sub_type) { 23755 case 0x0: 23756 tnl_info->type = bcmTunnelType6In4Uncheck; 23757 break; 23758 case 0x1: 23759 tnl_info->type = bcmTunnelTypeIsatap; 23760 break; 23761 case 0x2: 23762 tnl_info->type = bcmTunnelType6In4; 23763 break; 23764 default: 23765 return (BCM_E_PARAM); 23766 } 23767 return (BCM_E_NONE); 23768 } 23769 23770 /* Configured tunnel */ 23771 23772 /* Read outer header IP version. */ 23773 v6 = tnl_type->tnl_outer_hdr_ipv6; 23774 23775 if (tnl_type->tnl_gre) { 23776 23777 if ((tnl_type->tnl_gre_v4_payload) && 23778 (tnl_type->tnl_gre_v6_payload)) { 23779 tnl_info->type = (v6) ? bcmTunnelTypeGreAnyIn6 : 23780 bcmTunnelTypeGreAnyIn4; 23781 } else { 23782 if (tnl_type->tnl_gre_v6_payload) { 23783 tnl_info->type = (v6) ? bcmTunnelTypeGre6In6 : 23784 bcmTunnelTypeGre6In4; 23785 } else { 23786 tnl_info->type = (v6) ? bcmTunnelTypeGre4In6 : 23787 bcmTunnelTypeGre4In4; 23788 } 23789 } 23790 } else if (tnl_type->tnl_udp) { 23791 tnl_info->type = bcmTunnelTypeUdp; 23792 } else if (tnl_type->tnl_pim_sm) { 23793 tnl_info->type = (v6) ? bcmTunnelTypePim6SmDr1 : bcmTunnelTypePimSmDr1; 23794 } else if (tnl_type->tnl_protocol == 0x11) { 23795 if (tnl_type->tnl_udp_type == 1) { 23796 tnl_info->type = bcmTunnelTypeWlanWtpToAc; 23797 } else if (tnl_type->tnl_udp_type == 2) { 23798 tnl_info->type = (v6) ? bcmTunnelTypeAutoMulticast6 : bcmTunnelTypeAutoMulticast; 23799 } else { 23800 #ifdef BCM_TRIDENT3_SUPPORT 23801 if (SOC_IS_TRIDENT3X(unit)) { 23802 tnl_info->type = (v6) ? bcmTunnelTypeAutoMulticast6 : bcmTunnelTypeAutoMulticast; 23803 } else 23804 #endif 23805 tnl_info->type = bcmTunnelTypeWlanAcToAc; 23806 } 23807 } else if (tnl_type->tnl_protocol == 0x88) { 23808 if (tnl_type->tnl_udp_type == 1) { 23809 tnl_info->type = bcmTunnelTypeWlanWtpToAc6; 23810 } else { 23811 tnl_info->type = bcmTunnelTypeWlanAcToAc6; 23812 } 23813 } else { 23814 switch (tnl_type->tnl_sub_type) { 23815 case 0x3: 23816 tnl_info->type = (v6) ? bcmTunnelTypeIpAnyIn6 : 23817 bcmTunnelTypeIpAnyIn4; 23818 break; 23819 case 0x2: 23820 tnl_info->type = (v6) ? bcmTunnelTypeIp4In6 : 23821 bcmTunnelTypeIp4In4; 23822 break; 23823 case 0x1: 23824 tnl_info->type = (v6) ? bcmTunnelTypeIp6In6 : 23825 bcmTunnelTypeIp6In4; 23826 break; 23827 default: 23828 return (BCM_E_PARAM); 23829 } 23830 } 23831 return (BCM_E_NONE); 23832 } 23833 23834 /* 23835 * Function: 23836 * bcm_xgs3_tunnel_terminator_validate 23837 * Purpose: 23838 * Tunnel terminator structure sanity check routine. 23839 * Parameters: 23840 * unit - (IN) SOC unit number. 23841 * tnl_info - (IN) Tunnel terminator parameters. 23842 * Returns: 23843 * BCM_E_NONE - If data in the structure is valid. 23844 * BCM_E_PARAMS - otherwise. 23845 */ 23846 STATIC int 23847 _bcm_xgs3_tunnel_terminator_validate(int unit, 23848 bcm_tunnel_terminator_t *tnl_info) 23849 { 23850 int support; /* Tunnel type support by device. */ 23851 int masklen; /* IPv6 sip/dip mask length. */ 23852 bcm_ip6_t zero_addr; /* IPv6 sip address. */ 23853 int rv; /* Operation return status. */ 23854 23855 /* Input parameters check. */ 23856 if (NULL == tnl_info) { 23857 return (SOC_E_PARAM); 23858 } 23859 23860 /* Vrf range sanity. */ 23861 if ((tnl_info->vrf > SOC_VRF_MAX(unit)) || 23862 (tnl_info->vrf < BCM_L3_VRF_DEFAULT)) { 23863 return (BCM_E_PARAM); 23864 } 23865 23866 /* fwd_vlan range sanity. */ 23867 if (tnl_info->fwd_vlan != 0) { 23868 if (!BCM_VLAN_VALID(tnl_info->fwd_vlan)) { 23869 return BCM_E_PARAM; 23870 } 23871 } 23872 23873 if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 23874 if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type)) { 23875 sal_memset(zero_addr, 0, sizeof(bcm_ip6_t)); 23876 23877 /* Destination ip mask must be a full mask. */ 23878 masklen = bcm_ip6_mask_length(tnl_info->dip6_mask); 23879 if (masklen != BCM_XGS3_L3_IPV6_PREFIX_LEN) { 23880 return (BCM_E_PARAM); 23881 } 23882 23883 /* Apply source ip subnet mask. */ 23884 rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6); 23885 BCM_IF_ERROR_RETURN(rv); 23886 } else { 23887 /* Destination ip mask must be a full mask. */ 23888 if (tnl_info->dip_mask != BCM_XGS3_L3_IP4_FULL_MASK) { 23889 return (BCM_E_PARAM); 23890 } 23891 23892 /* Apply source ip subnet mask. */ 23893 tnl_info->sip &= tnl_info->sip_mask; 23894 } 23895 } 23896 23897 rv = _bcm_xgs3_tunnel_type_support_check(unit, tnl_info->type, 23898 &support, NULL); 23899 BCM_IF_ERROR_RETURN(rv); 23900 23901 if (FALSE == support) { 23902 return (BCM_E_UNAVAIL); 23903 } 23904 23905 return (BCM_E_NONE); 23906 } 23907 23908 /* 23909 * Function: 23910 * _bcm_xgs3_l3_tnl_term_entry_init 23911 * Purpose: 23912 * Initialize soc tunnel terminator entry key portion. 23913 * Parameters: 23914 * unit - (IN) BCM device number. 23915 * tnl_info - (IN) BCM buffer with tunnel info. 23916 * entry - (OUT) SOC buffer with key filled in. 23917 * Returns: 23918 * BCM_E_XXX 23919 */ 23920 STATIC int 23921 _bcm_xgs3_l3_tnl_term_entry_init(int unit, bcm_tunnel_terminator_t *tnl_info, 23922 soc_tunnel_term_t *entry) 23923 { 23924 int idx; /* Entry iteration index. */ 23925 int idx_max; /* Entry widht. */ 23926 uint32 *entry_ptr; /* Filled entry pointer. */ 23927 _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */ 23928 soc_field_t vrf_fld; /* VRF id field name. */ 23929 int rv; /* Operation return status. */ 23930 23931 /* Input parameters check. */ 23932 if ((NULL == tnl_info) || (NULL == entry)) { 23933 return (BCM_E_PARAM); 23934 } 23935 23936 #ifdef BCM_TOMAHAWK3_SUPPORT 23937 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 23938 return _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, entry); 23939 } 23940 #endif 23941 23942 /* Get tunnel type & sub_type. */ 23943 rv = _bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type); 23944 BCM_IF_ERROR_RETURN(rv); 23945 23946 /* Reset destination structure. */ 23947 sal_memset(entry, 0, sizeof(soc_tunnel_term_t)); 23948 23949 /* Set Destination/Source pair. */ 23950 entry_ptr = (uint32 *)&entry->entry_arr[0]; 23951 if (tnl_type.tnl_outer_hdr_ipv6) { 23952 #if defined(BCM_TRX_SUPPORT) 23953 /* Apply mask on source address. */ 23954 rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6); 23955 BCM_IF_ERROR_RETURN(rv); 23956 23957 /* SIP [0-63] */ 23958 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23959 (uint32 *)&entry->entry_arr[0], IP_ADDRf, 23960 tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY); 23961 /* SIP [64-127] */ 23962 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23963 (uint32 *)&entry->entry_arr[1], IP_ADDRf, 23964 tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY); 23965 /* DIP [0-63] */ 23966 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23967 (uint32 *)&entry->entry_arr[2], IP_ADDRf, 23968 tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY); 23969 /* DIP [64-127] */ 23970 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23971 (uint32 *)&entry->entry_arr[3], IP_ADDRf, 23972 tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY); 23973 23974 /* SIP MASK [0-63] */ 23975 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23976 (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf, 23977 tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY); 23978 /* SIP MASK [64-127] */ 23979 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23980 (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf, 23981 tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY); 23982 /* DIP MASK [0-63] */ 23983 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23984 (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf, 23985 tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY); 23986 /* DIP MASK [64-127] */ 23987 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 23988 (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf, 23989 tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY); 23990 #endif /* BCM_TRX_SUPPORT */ 23991 } else { 23992 tnl_info->sip &= tnl_info->sip_mask; 23993 23994 /* Set destination ip. */ 23995 soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIPf, tnl_info->dip); 23996 23997 /* Set source ip. */ 23998 soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIPf, tnl_info->sip); 23999 #if defined(BCM_FIREBOLT_SUPPORT) 24000 if (SOC_IS_FBX(unit)) { 24001 /* Set destination subnet mask. */ 24002 soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIP_MASKf, 24003 tnl_info->dip_mask); 24004 24005 /* Set source subnet mask. */ 24006 soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIP_MASKf, 24007 tnl_info->sip_mask); 24008 } 24009 #endif /* BCM_FIREBOLT_SUPPORT */ 24010 } 24011 24012 /* Resolve vrf field name. */ 24013 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) ||\ 24014 defined(BCM_SCORPION_SUPPORT) 24015 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_VRF_IDf)) { 24016 vrf_fld = TUNNEL_VRF_IDf; 24017 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_VRF_OVERRIDEf)) { 24018 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_VRF_OVERRIDEf, 1); 24019 } 24020 } else 24021 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT */ 24022 { 24023 vrf_fld = INVALIDf; 24024 } 24025 24026 /* Resolve number of entries hw entry occupies. */ 24027 idx_max = (tnl_type.tnl_outer_hdr_ipv6) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \ 24028 SOC_TNL_TERM_IPV4_ENTRY_WIDTH; 24029 24030 for (idx = 0; idx < idx_max; idx++) { 24031 entry_ptr = (uint32 *) &entry->entry_arr[idx]; 24032 24033 /* Set valid bit. */ 24034 soc_L3_TUNNELm_field32_set(unit, entry_ptr, VALIDf, 1); 24035 24036 /* Set tunnel subtype. */ 24037 soc_L3_TUNNELm_field32_set(unit, entry_ptr, SUB_TUNNEL_TYPEf, 24038 tnl_type.tnl_sub_type); 24039 24040 /* Set tunnel type. */ 24041 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_TYPEf, 24042 tnl_type.tnl_auto); 24043 #if defined(BCM_TRX_SUPPORT) 24044 if (SOC_IS_FBX(unit)) { 24045 /* Set entry mode. */ 24046 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, MODEf)) { 24047 soc_L3_TUNNELm_field32_set(unit, entry_ptr, MODEf, 24048 tnl_type.tnl_outer_hdr_ipv6); 24049 soc_L3_TUNNELm_field32_set(unit, entry_ptr, MODE_MASKf, 1); 24050 } else if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, KEY_TYPEf)) { 24051 soc_L3_TUNNELm_field32_set(unit, entry_ptr, KEY_TYPEf, 24052 tnl_type.tnl_outer_hdr_ipv6); 24053 } 24054 24055 24056 /* Set tunnel type is GRE bit. */ 24057 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_TUNNELf)) { 24058 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_TUNNELf, 24059 tnl_type.tnl_gre); 24060 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_TUNNEL_MASKf, 1); 24061 24062 if (tnl_type.tnl_gre) { 24063 /* GRE IPv6 payload is allowed. */ 24064 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV6f, 24065 tnl_type.tnl_gre_v6_payload); 24066 24067 /* GRE IPv6 payload is allowed. */ 24068 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV4f, 24069 tnl_type.tnl_gre_v4_payload); 24070 } 24071 } 24072 } 24073 #endif /* BCM_TRX_SUPPORT */ 24074 24075 /* Set entry vrf id. */ 24076 if (INVALIDf != vrf_fld) { 24077 soc_L3_TUNNELm_field32_set(unit, entry_ptr, vrf_fld, tnl_info->vrf); 24078 } 24079 } 24080 return (BCM_E_NONE); 24081 } 24082 24083 24084 24085 /* 24086 * Function: 24087 * bcm_xgs3_tunnel_terminator_add 24088 * Purpose: 24089 * Add a tunnel terminator for DIP-SIP 24090 * Parameters: 24091 * unit - (IN) SOC unit number. 24092 * tnl_info - (IN) Tunnel terminator parameters. 24093 * Returns: 24094 * BCM_E_XXX 24095 */ 24096 int 24097 bcm_xgs3_tunnel_terminator_add(int unit, bcm_tunnel_terminator_t *tnl_info) 24098 { 24099 bcm_tunnel_terminator_t tmp_info; /* Entry lookup buffer. */ 24100 _bcm_l3_ingress_intf_t iif; /* Ingress interface. */ 24101 int old_iif = -1; /* Original ingress interface.*/ 24102 int rv; /* Operation result. */ 24103 #ifdef BCM_TOMAHAWK_SUPPORT 24104 int ecn_map_index; 24105 int ecn_map_type; 24106 int ecn_map_num; 24107 #endif 24108 #ifdef BCM_TRIDENT3_SUPPORT 24109 uint32 vlan_profile_idx = 0; 24110 uint32 action_profile_idx = 0; 24111 #endif 24112 uint32 fwd_vlan = tnl_info->fwd_vlan; 24113 /* Make sure module was initialized. */ 24114 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 24115 return (BCM_E_INIT); 24116 } 24117 24118 /* Make sure hw call is initialized.*/ 24119 if ((!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_add)) || 24120 (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_get))) { 24121 return (BCM_E_UNAVAIL); 24122 } 24123 24124 /* Check input parameters */ 24125 BCM_IF_ERROR_RETURN 24126 (_bcm_xgs3_tunnel_terminator_validate(unit, tnl_info)); 24127 24128 /* Fill lkup buf. */ 24129 tmp_info = *tnl_info; 24130 24131 /* Check if entry already exists. */ 24132 BCM_XGS3_L3_MODULE_LOCK(unit); 24133 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_get) (unit, &tmp_info); 24134 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24135 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 24136 return (rv); 24137 } 24138 24139 /* Make sure replace flag is set if replacing existing entry. */ 24140 if (BCM_SUCCESS(rv)) { 24141 if (0 == (tnl_info->flags & BCM_TUNNEL_REPLACE)) { 24142 return (BCM_E_EXISTS); 24143 } 24144 24145 if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (tmp_info.vlan > BCM_VLAN_MAX)) { 24146 old_iif = tmp_info.vlan; 24147 } 24148 } 24149 24150 /* If SC L3IngressMode Set, then tnl_info->vlan contains the L3_IIF Idx */ 24151 if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (0 == tnl_info->vlan)) { 24152 /* Check L3 Ingress Interface mode. */ 24153 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) { 24154 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 24155 iif.vrf = tnl_info->vrf; 24156 iif.if_class = tnl_info->if_class; 24157 if ((tnl_info->flags & BCM_TUNNEL_TERM_DSCP_TRUST) 24158 && (tnl_info->qos_map_id != 0)) { 24159 iif.flags |= BCM_L3_INGRESS_DSCP_TRUST; 24160 iif.qos_map_id = tnl_info->qos_map_id; 24161 } 24162 #ifdef BCM_TOMAHAWK_SUPPORT 24163 if (SOC_IS_TOMAHAWKX(unit) && 24164 soc_feature(unit, soc_feature_ecn_wred) && 24165 (tnl_info->flags & BCM_TUNNEL_TERM_ECN_MAP)) { 24166 ecn_map_type = tnl_info->tunnel_term_ecn_map_id & 24167 _BCM_XGS5_ECN_MAP_TYPE_MASK; 24168 ecn_map_index = tnl_info->tunnel_term_ecn_map_id & 24169 _BCM_XGS5_ECN_MAP_NUM_MASK; 24170 ecn_map_num = 24171 soc_mem_index_count(unit, ING_TUNNEL_ECN_DECAPm) / 24172 _BCM_ECN_MAX_ENTRIES_PER_TUNNEL_TERM_MAP; 24173 if (ecn_map_type != _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM) { 24174 return BCM_E_PARAM; 24175 } 24176 if (ecn_map_index >= ecn_map_num) { 24177 return BCM_E_PARAM; 24178 } 24179 if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 24180 _bcmEcnmapTypeTunnelTerm)) { 24181 return BCM_E_PARAM; 24182 } 24183 iif.tunnel_term_ecn_map_id = ecn_map_index; 24184 iif.flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP; 24185 } 24186 #endif /* BCM_TOMAHAWK_SUPPORT */ 24187 rv =_bcm_xgs3_l3_ingress_interface_add (unit, &iif); 24188 if (BCM_FAILURE(rv)) { 24189 if (-1 != old_iif) { 24190 (void)_bcm_xgs3_l3_ingress_interface_delete(unit, old_iif); 24191 } 24192 return (rv); 24193 } 24194 tnl_info->vlan = iif.intf_id; 24195 } 24196 } 24197 24198 #ifdef BCM_TRIDENT3_SUPPORT 24199 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, DEFAULT_VLAN_PROFILE_INDEXf)) { 24200 void *entries[1]; 24201 tunnel_default_vlan_profile_entry_t tunnel_default_vlan_profile_entry; 24202 24203 if (tnl_info->flags & BCM_TUNNEL_REPLACE) { 24204 soc_tunnel_term_t key; 24205 soc_tunnel_term_t entry; 24206 uint32 *entry_ptr; 24207 int index; 24208 24209 rv = _bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &key); 24210 24211 /* Find existing tunnel terminator */ 24212 if (BCM_SUCCESS(rv)) { 24213 rv = soc_tunnel_term_match(unit, &key, &entry, &index); 24214 } 24215 entry_ptr = (uint32 *)&entry.entry_arr[0]; 24216 24217 if (BCM_SUCCESS(rv)) { 24218 uint32 old_vlan_profile_idx = soc_mem_field32_get(unit, L3_TUNNELm, entry_ptr, 24219 DEFAULT_VLAN_PROFILE_INDEXf); 24220 24221 if (old_vlan_profile_idx) { 24222 /* valid existing vlan profile index; get it */ 24223 BCM_IF_ERROR_RETURN( 24224 soc_mem_read(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, MEM_BLOCK_ANY, 24225 old_vlan_profile_idx, &tunnel_default_vlan_profile_entry)); 24226 24227 /* get existing action profile */ 24228 action_profile_idx = soc_mem_field32_get(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, 24229 (uint32 *) &tunnel_default_vlan_profile_entry, 24230 TAG_ACTION_PROFILE_PTRf); 24231 24232 /* delete action profile */ 24233 (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx)); 24234 24235 /* delete existing vlan profile */ 24236 soc_profile_mem_delete(unit, _bcm_td3_tunnel_default_vlan_profile[unit], old_vlan_profile_idx); 24237 } 24238 } 24239 } 24240 24241 if (fwd_vlan != 0) { 24242 bcm_vlan_action_set_t action; 24243 bcm_vlan_action_set_t_init(&action); 24244 action.ut_outer = bcmVlanActionAdd; 24245 24246 /* add new action profile */ 24247 BCM_IF_ERROR_RETURN 24248 (_bcm_trx_vlan_action_profile_entry_add(unit, &action, &action_profile_idx)); 24249 24250 sal_memset(&tunnel_default_vlan_profile_entry, 0, sizeof(tunnel_default_vlan_profile_entry)); 24251 24252 /* add new vlan profile */ 24253 soc_L3_TUNNEL_DEFAULT_VLAN_PROFILEm_field_set(unit, &tunnel_default_vlan_profile_entry, 24254 OUTER_VLAN_TAGf, (uint32 *)&fwd_vlan); 24255 24256 soc_L3_TUNNEL_DEFAULT_VLAN_PROFILEm_field_set(unit, &tunnel_default_vlan_profile_entry, 24257 TAG_ACTION_PROFILE_PTRf, (uint32 *)&action_profile_idx); 24258 24259 entries[0] = &tunnel_default_vlan_profile_entry; 24260 24261 rv = soc_profile_mem_add(unit, 24262 _bcm_td3_tunnel_default_vlan_profile[unit], 24263 entries, 1, &vlan_profile_idx); 24264 24265 if (BCM_FAILURE(rv)) { 24266 (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx)); 24267 return rv; 24268 } 24269 24270 /* carry the profile idx for L3_TUNNEL soc_mem insert */ 24271 tnl_info->fwd_vlan = vlan_profile_idx; 24272 } 24273 } 24274 #endif 24275 24276 /* Insert new/updated entry. */ 24277 BCM_XGS3_L3_MODULE_LOCK(unit); 24278 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_add) (unit, tnl_info); 24279 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24280 if (BCM_FAILURE(rv)) { 24281 if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && 24282 (tnl_info->vlan > BCM_VLAN_MAX)) { 24283 (void)(_bcm_xgs3_l3_ingress_interface_delete(unit, iif.intf_id)); 24284 } 24285 #ifdef BCM_TRIDENT3_SUPPORT 24286 if (vlan_profile_idx != 0) { 24287 (void)(soc_profile_mem_delete(unit, 24288 _bcm_td3_tunnel_default_vlan_profile[unit], vlan_profile_idx)); 24289 24290 (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx)); 24291 } 24292 #endif 24293 } 24294 24295 if (fwd_vlan != 0) { 24296 tnl_info->fwd_vlan = fwd_vlan; 24297 } 24298 24299 /* Remove original ingress interface. */ 24300 if (-1 != old_iif) { 24301 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))){ 24302 (void)_bcm_xgs3_l3_ingress_interface_delete(unit, old_iif); 24303 } 24304 } 24305 24306 return (rv); 24307 } 24308 24309 /* 24310 * Function: 24311 * bcm_xgs3_tunnel_terminator_delete 24312 * Purpose: 24313 * Delete a tunnel terminator for DIP-SIP + 24314 * Parameters: 24315 * unit - (IN) SOC unit number. 24316 * tnl_info - (IN) Tunnel terminator parameters. 24317 * Returns: 24318 * BCM_E_XXX 24319 */ 24320 24321 int 24322 bcm_xgs3_tunnel_terminator_delete(int unit, bcm_tunnel_terminator_t *tnl_info) 24323 { 24324 int rv; 24325 /* Make sure module was initialized. */ 24326 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 24327 return (BCM_E_INIT); 24328 } 24329 24330 /* Make sure hw call is initialized.*/ 24331 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_del)) { 24332 return (BCM_E_UNAVAIL); 24333 } 24334 24335 /* Check input parameters */ 24336 BCM_IF_ERROR_RETURN 24337 (_bcm_xgs3_tunnel_terminator_validate(unit, tnl_info)); 24338 24339 /* Do entry lookup. */ 24340 BCM_XGS3_L3_MODULE_LOCK(unit); 24341 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_get) (unit, tnl_info); 24342 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24343 if (BCM_FAILURE(rv)) { 24344 return rv; 24345 } 24346 24347 /* Delete ingress interface. */ 24348 if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && 24349 (tnl_info->vlan > BCM_VLAN_MAX)) { 24350 if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))){ 24351 BCM_IF_ERROR_RETURN 24352 (_bcm_xgs3_l3_ingress_interface_delete(unit, tnl_info->vlan)); 24353 } 24354 } 24355 24356 /* Delete tunnel entry. */ 24357 BCM_XGS3_L3_MODULE_LOCK(unit); 24358 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_del) (unit, tnl_info); 24359 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24360 return rv; 24361 } 24362 24363 /* 24364 * Function: 24365 * bcm_xgs3_tunnel_terminator_update 24366 * Purpose: 24367 * Update a tunnel terminator for DIP-SIP + 24368 * on ER (DST_UDP_PORT/SRC_UDP_PORT) 24369 * Parameters: 24370 * unit - (IN) SOC unit number. 24371 * tnl_info - (IN) Tunnel terminator parameters. 24372 * Returns: 24373 * BCM_E_XXX 24374 */ 24375 int 24376 bcm_xgs3_tunnel_terminator_update(int unit, bcm_tunnel_terminator_t *tnl_info) 24377 { 24378 if (NULL == tnl_info) { 24379 return (BCM_E_PARAM); 24380 } 24381 tnl_info->flags |= BCM_TUNNEL_REPLACE; 24382 24383 return bcm_xgs3_tunnel_terminator_add(unit,tnl_info); 24384 } 24385 24386 /* 24387 * Function: 24388 * bcm_xgs3_tunnel_terminator_get 24389 * Purpose: 24390 * Get a tunnel terminator for DIP-SIP + 24391 * on ER (DST_UDP_PORT/SRC_UDP_PORT) 24392 * Parameters: 24393 * unit - (IN) SOC unit number. 24394 * tnl_info - (IN) Tunnel terminator parameters. 24395 * Returns: 24396 * BCM_E_XXX 24397 */ 24398 int 24399 bcm_xgs3_tunnel_terminator_get(int unit, bcm_tunnel_terminator_t *tnl_info) 24400 { 24401 24402 int rv; 24403 /* Make sure module was initialized. */ 24404 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 24405 return (BCM_E_INIT); 24406 } 24407 24408 /* Make sure hw call is initialized.*/ 24409 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_get)) { 24410 return (BCM_E_UNAVAIL); 24411 } 24412 24413 /* Check input parameters */ 24414 BCM_IF_ERROR_RETURN 24415 (_bcm_xgs3_tunnel_terminator_validate(unit, tnl_info)); 24416 24417 24418 /* Do entry lookup. */ 24419 BCM_XGS3_L3_MODULE_LOCK(unit); 24420 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_get) (unit, tnl_info); 24421 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24422 return rv; 24423 } 24424 24425 /* 24426 * Function: 24427 * bcm_xgs3_tunnel_terminator_traverse 24428 * Purpose: 24429 * Traverse all tunnel terminator entries 24430 * Parameters: 24431 * unit - SOC unit number 24432 * cb - User callback function, called once per entry 24433 * user_data - User supplied cookie used in parameter in callback function 24434 * Returns: 24435 * BCM_E_XXX 24436 */ 24437 int 24438 bcm_xgs3_tunnel_terminator_traverse(int unit, 24439 bcm_tunnel_terminator_traverse_cb cb, 24440 void *user_data) 24441 { 24442 int rv; 24443 /* Make sure module was initialized. */ 24444 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 24445 return (BCM_E_INIT); 24446 } 24447 24448 BCM_XGS3_L3_MODULE_LOCK(unit); 24449 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_traverse) 24450 (unit, cb, user_data); 24451 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24452 24453 return rv; 24454 } 24455 24456 /* 24457 * Function: 24458 * _bcm_xgs3_tnl_type_to_hw_code 24459 * Purpose: 24460 * Translate tunnel type into value used in hardware 24461 * 0: None 24462 * 1: Config 24463 * 2: Automatic 6to4 24464 * 3: Automatic ISATAP 24465 * 4: PIM_DR1 24466 * 5: PIM_DR2 24467 * 6: Firebolt - RESERVED/ER - GRE 24468 * 7: Firebolt - RESERVED/ER - UDP 24469 * 8: Firebolt - RESERVED/ER - MPLS 24470 * Parameters: 24471 * unit - (IN) SOC unit number. 24472 * tnl_type - (IN) Tunnel type. 24473 * hw_code - (OUT) HW code for tunnel type. 24474 * entry_type - (OUT) Entry type. 24475 * Returns: 24476 * BCM_E_XXX 24477 */ 24478 STATIC INLINE int 24479 _bcm_xgs3_tnl_type_to_hw_code(int unit, bcm_tunnel_type_t tnl_type, 24480 int *hw_code, int *entry_type) 24481 { 24482 /* Input parameters check. */ 24483 if ((NULL == hw_code) || (NULL == entry_type)) { 24484 return (BCM_E_PARAM); 24485 } 24486 24487 #if defined(BCM_TRX_SUPPORT) 24488 if (soc_feature(unit, soc_feature_tunnel_any_in_6)) { 24489 return _bcm_trx_tnl_type_to_hw_code(unit, tnl_type, hw_code, entry_type); 24490 } else 24491 #endif /* BCM_TRX_SUPPORT */ 24492 { 24493 *entry_type = BCM_XGS3_TUNNEL_INIT_V4; 24494 } 24495 24496 switch (tnl_type) { 24497 case bcmTunnelTypeNone: 24498 *hw_code = 0; 24499 break; 24500 24501 case bcmTunnelTypeIp4In4: 24502 case bcmTunnelTypeIp6In4: 24503 case bcmTunnelTypeIpAnyIn4: 24504 *hw_code = 0x1; 24505 break; 24506 24507 case bcmTunnelTypeIp4In6: 24508 case bcmTunnelTypeIp6In6: 24509 case bcmTunnelTypeIpAnyIn6: 24510 *hw_code = 0x1; 24511 break; 24512 24513 case bcmTunnelType6In4Uncheck: 24514 *hw_code = 0x2; 24515 break; 24516 24517 case bcmTunnelType6In4: 24518 *hw_code = 0x6; 24519 break; 24520 24521 case bcmTunnelTypeIsatap: 24522 *hw_code = 0x3; 24523 break; 24524 24525 case bcmTunnelTypePimSmDr1: 24526 *hw_code = 0x4; 24527 break; 24528 24529 case bcmTunnelTypePimSmDr2: 24530 *hw_code = 0x5; 24531 break; 24532 24533 case bcmTunnelTypePim6SmDr1: 24534 *hw_code = 0x4; 24535 break; 24536 24537 case bcmTunnelTypePim6SmDr2: 24538 *hw_code = 0x5; 24539 break; 24540 24541 24542 case bcmTunnelTypeGre4In4: 24543 case bcmTunnelTypeGre6In4: 24544 case bcmTunnelTypeGreAnyIn4: 24545 *hw_code = 0x6; 24546 break; 24547 case bcmTunnelTypeUdp: 24548 *hw_code = 0x7; 24549 break; 24550 24551 case bcmTunnelTypeMpls: 24552 *hw_code = 0x8; 24553 break; 24554 24555 default: 24556 break; 24557 } 24558 24559 return (BCM_E_NONE); 24560 } 24561 24562 24563 /* 24564 * Function: 24565 * _bcm_xgs3_tnl_hw_code_to_type 24566 * Purpose: 24567 * Translate hw code for tunnel type into api value 24568 * 0: None 24569 * 1: Config 24570 * 2: Automatic 6to4 24571 * 3: Automatic ISATAP 24572 * 4: PIM_DR1 24573 * 5: PIM_DR2 24574 * 6: Firebolt - RESERVED/ER - GRE 24575 * 7: Firebolt - RESERVED/ER - UDP 24576 * 8: Firebolt - RESERVED/ER - MPLS 24577 * Parameters: 24578 * unit - (IN) SOC unit number. 24579 * hw_tnl_type - (IN) HW tunnel code. 24580 * entry_type - (IN) Tunnel entry type. 24581 * tunnel_type - (OUT) Tunnel type. 24582 * Returns: 24583 * BCM_E_XXX 24584 */ 24585 STATIC INLINE int 24586 _bcm_xgs3_tnl_hw_code_to_type(int unit, int hw_tnl_type, 24587 int entry_type, bcm_tunnel_type_t *tunnel_type) 24588 { 24589 /* Input parameters check. */ 24590 if (NULL == tunnel_type) { 24591 return (BCM_E_PARAM); 24592 } 24593 24594 if ((entry_type == BCM_XGS3_TUNNEL_INIT_MPLS) 24595 #ifdef BCM_TRIDENT3_SUPPORT 24596 || (SOC_IS_TRIDENT3X(unit) && (entry_type == BCM_XGS3_TUNNEL_INIT_MPLS_TD3)) 24597 #endif /* BCM_TRIDENT3_SUPPORT */ 24598 ) { 24599 *tunnel_type = bcmTunnelTypeMpls; 24600 return BCM_E_NONE; 24601 } 24602 24603 #if defined(BCM_TRX_SUPPORT) 24604 if (soc_feature(unit, soc_feature_tunnel_any_in_6)) { 24605 return _bcm_trx_tnl_hw_code_to_type(unit, hw_tnl_type, entry_type, tunnel_type); 24606 } 24607 #if defined(BCM_TOMAHAWK_SUPPORT) 24608 /* L2GRE and VxLAN need to be supported on Ranger3+ 24609 which has disabled soc_feature_tunnel_any_in_6*/ 24610 if (SOC_IS_TOMAHAWK(unit)) { 24611 if (hw_tnl_type == 0x7) { 24612 *tunnel_type = bcmTunnelTypeL2Gre; 24613 return BCM_E_NONE; 24614 } else if (hw_tnl_type == 0xB) { 24615 *tunnel_type = bcmTunnelTypeVxlan; 24616 return BCM_E_NONE; 24617 } else { 24618 return (BCM_E_PARAM); 24619 } 24620 } 24621 #endif /* BCM_TOMAHAWK_SUPPORT */ 24622 #endif /* BCM_TRX_SUPPORT*/ 24623 24624 switch (hw_tnl_type) { 24625 case 0: 24626 *tunnel_type = bcmTunnelTypeNone; 24627 break; 24628 case 1: 24629 *tunnel_type = bcmTunnelTypeIpAnyIn4; 24630 break; 24631 case 2: 24632 *tunnel_type = bcmTunnelType6In4Uncheck; 24633 break; 24634 case 3: 24635 *tunnel_type = bcmTunnelTypeIsatap; 24636 break; 24637 case 4: 24638 *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \ 24639 bcmTunnelTypePimSmDr1 : bcmTunnelTypePim6SmDr1; 24640 break; 24641 case 5: 24642 *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \ 24643 bcmTunnelTypePimSmDr2 : bcmTunnelTypePim6SmDr2; 24644 break; 24645 case 6: 24646 *tunnel_type = bcmTunnelTypeGreAnyIn4; 24647 break; 24648 case 7: 24649 *tunnel_type = bcmTunnelTypeUdp; 24650 break; 24651 case 8: 24652 *tunnel_type = bcmTunnelTypeMpls; 24653 break; 24654 default: 24655 return (BCM_E_PARAM); 24656 } 24657 return (BCM_E_NONE); 24658 } 24659 24660 /* 24661 * Function: 24662 * _bcm_xgs3_tnl_init_hash_calc 24663 * Purpose: 24664 * Calculate tunnel initiator entry hash(signature). 24665 * Parameters: 24666 * unit - (IN)SOC unit number. 24667 * buf - (IN)Tunnel initiator entry information. 24668 * hash - (OUT) Hash(signature) calculated value. 24669 * Returns: 24670 * BCM_X_XXX 24671 */ 24672 STATIC int 24673 _bcm_xgs3_tnl_init_hash_calc(int unit, void *buf, uint16 *hash) 24674 { 24675 24676 bcm_tunnel_initiator_t tnl_entry; 24677 24678 if ((NULL == buf) || (NULL == hash)) { 24679 return (BCM_E_PARAM); 24680 } 24681 24682 #ifdef BCM_TRIDENT2_SUPPORT 24683 if (soc_feature(unit, soc_feature_vxlan)) { 24684 if (bcmTunnelTypeVxlan == ((bcm_tunnel_initiator_t *)buf)->type) { 24685 BCM_IF_ERROR_RETURN( 24686 _bcm_td2_vxlan_tunnel_initiator_hash_calc( 24687 unit, buf, hash)); 24688 return (BCM_E_NONE); 24689 } 24690 } 24691 #endif /* BCM_TRIDENT2_SUPPORT */ 24692 #if defined(BCM_GREYHOUND2_SUPPORT) 24693 if (soc_feature(unit, soc_feature_vxlan_lite)) { 24694 if ((((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan) || 24695 (((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan6)) { 24696 BCM_IF_ERROR_RETURN( 24697 bcmi_gh2_vxlan_tunnel_initiator_hash_calc(unit, 24698 buf, hash)); 24699 return BCM_E_NONE; 24700 } 24701 } 24702 #endif /* BCM_GREYHOUND2_SUPPORT */ 24703 24704 /* Copy buffer to structure. */ 24705 sal_memcpy(&tnl_entry, buf, sizeof(bcm_tunnel_initiator_t)); 24706 24707 /* Ignore flow label for not V6 tunnels. */ 24708 if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_entry.type)) { 24709 tnl_entry.flow_label = 0; 24710 } 24711 24712 /* Mask fields we don't want to include in hash. */ 24713 tnl_entry.flags = 0; 24714 24715 if (SOC_IS_FBX(unit)) { 24716 switch (tnl_entry.type) { 24717 case bcmTunnelTypeIp4In4: 24718 case bcmTunnelTypeIp6In4: 24719 tnl_entry.type = bcmTunnelTypeIpAnyIn4; 24720 break; 24721 case bcmTunnelTypeIp4In6: 24722 case bcmTunnelTypeIp6In6: 24723 tnl_entry.type = bcmTunnelTypeIpAnyIn6; 24724 break; 24725 case bcmTunnelTypeGre4In4: 24726 case bcmTunnelTypeGre6In4: 24727 tnl_entry.type = bcmTunnelTypeGreAnyIn4; 24728 break; 24729 case bcmTunnelTypeGre4In6: 24730 case bcmTunnelTypeGre6In6: 24731 tnl_entry.type = bcmTunnelTypeGreAnyIn6; 24732 break; 24733 default: 24734 break; 24735 } 24736 } 24737 24738 /* Calculate mac address hash. */ 24739 *hash = _shr_crc16(0, (uint8 *)&tnl_entry, 24740 sizeof(bcm_tunnel_initiator_t)); 24741 return (BCM_E_NONE); 24742 } 24743 24744 /* 24745 * Function: 24746 * _bcm_xgs3_tnl_init_cmp 24747 * Purpose: 24748 * Routine compares tunnel initiator entry with entry in the chip 24749 * with specified index. 24750 * Parameters: 24751 * unit - (IN) SOC unit number. 24752 * buf - (IN) Tunnel initiator entry to compare. 24753 * index - (IN) Entry index in the chip to compare. 24754 * cmp_result - (OUT)Compare result. 24755 * Returns: 24756 * BCM_E_XXX 24757 */ 24758 STATIC int 24759 _bcm_xgs3_tnl_init_cmp(int unit, void *buf, int index, int *cmp_result) 24760 { 24761 24762 bcm_tunnel_initiator_t hw_entry; /* Entry read from hw. */ 24763 bcm_tunnel_initiator_t *tnl_entry; /* Api passed buffer. */ 24764 int rv; 24765 24766 if ((NULL == buf) || (NULL == cmp_result)) { 24767 return (BCM_E_PARAM); 24768 } 24769 24770 #ifdef BCM_TRIDENT2_SUPPORT 24771 if (soc_feature(unit, soc_feature_vxlan)) { 24772 if (bcmTunnelTypeVxlan == ((bcm_tunnel_initiator_t *) buf)->type) { 24773 BCM_IF_ERROR_RETURN ( 24774 _bcm_td2_vxlan_tunnel_initiator_cmp( 24775 unit, buf, index, cmp_result)); 24776 return (BCM_E_NONE); 24777 } 24778 } 24779 #endif /* BCM_TRIDENT2_SUPPORT */ 24780 #if defined(BCM_GREYHOUND2_SUPPORT) 24781 if (soc_feature(unit, soc_feature_vxlan_lite)) { 24782 if ((((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan) || 24783 (((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan6)) { 24784 BCM_IF_ERROR_RETURN ( 24785 bcmi_gh2_vxlan_tunnel_initiator_cmp(unit, 24786 buf, index, cmp_result)); 24787 return BCM_E_NONE; 24788 } 24789 } 24790 #endif /* BCM_GREYHOUND2_SUPPORT */ 24791 24792 /* Initialization. */ 24793 bcm_tunnel_initiator_t_init(&hw_entry); 24794 24795 /* Copy buffer to structure. */ 24796 tnl_entry = (bcm_tunnel_initiator_t *) buf; 24797 24798 /* Get tunnel initiator entry from hw. */ 24799 if (BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get)) { 24800 BCM_XGS3_L3_MODULE_LOCK(unit); 24801 rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, index, 24802 &hw_entry)); 24803 BCM_XGS3_L3_MODULE_UNLOCK(unit); 24804 BCM_IF_ERROR_RETURN(rv); 24805 } else { 24806 return (BCM_E_UNAVAIL); 24807 } 24808 24809 /* Compare source & destination ip. */ 24810 if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_entry->type)) { 24811 if((sal_memcmp(tnl_entry->dip6, hw_entry.dip6, sizeof(bcm_ip6_t))) || 24812 (sal_memcmp(tnl_entry->sip6, hw_entry.sip6, sizeof(bcm_ip6_t))) || 24813 (tnl_entry->flow_label != hw_entry.flow_label)) { 24814 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24815 return (BCM_E_NONE); 24816 } 24817 } else { 24818 if ((tnl_entry->dip != hw_entry.dip) || 24819 (tnl_entry->sip != hw_entry.sip)) { 24820 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24821 return (BCM_E_NONE); 24822 } 24823 24824 /* For all boards except FB A0 compare DSCP DF SEL v4/v6 */ 24825 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, tnl_init_v4), 24826 IPV4_DF_SELf)) { 24827 if ((tnl_entry->flags & BCM_TUNNEL_INIT_SET_DF) != 24828 (hw_entry.flags & BCM_TUNNEL_INIT_SET_DF)) { 24829 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24830 return (BCM_E_NONE); 24831 } 24832 } 24833 } 24834 24835 /* Compare hw entry with passed one. */ 24836 if ((tnl_entry->dscp_sel != hw_entry.dscp_sel) || 24837 (tnl_entry->dscp != hw_entry.dscp)) { 24838 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24839 return (BCM_E_NONE); 24840 } 24841 24842 /* Compare tunnel type / ttl */ 24843 if (SOC_IS_FBX(unit)) { 24844 /* Tunnel type comparison. */ 24845 /* Note: Only outer header matters in tunnel initialization */ 24846 if (tnl_entry->type != hw_entry.type) { 24847 switch (tnl_entry->type) { 24848 case bcmTunnelTypeIp4In4: 24849 case bcmTunnelTypeIp6In4: 24850 if (bcmTunnelTypeIpAnyIn4 != hw_entry.type) { 24851 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24852 return (BCM_E_NONE); 24853 } 24854 break; 24855 case bcmTunnelTypeIp4In6: 24856 case bcmTunnelTypeIp6In6: 24857 if (bcmTunnelTypeIpAnyIn6 != hw_entry.type) { 24858 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24859 return (BCM_E_NONE); 24860 } 24861 break; 24862 case bcmTunnelTypeGre4In4: 24863 case bcmTunnelTypeGre6In4: 24864 if (bcmTunnelTypeGreAnyIn4 != hw_entry.type) { 24865 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24866 return (BCM_E_NONE); 24867 } 24868 break; 24869 case bcmTunnelTypeGre4In6: 24870 case bcmTunnelTypeGre6In6: 24871 if (bcmTunnelTypeGreAnyIn6 != hw_entry.type) { 24872 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24873 return (BCM_E_NONE); 24874 } 24875 break; 24876 default: 24877 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24878 return (BCM_E_NONE); 24879 } 24880 } 24881 if (tnl_entry->ttl != hw_entry.ttl) { 24882 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24883 return (BCM_E_NONE); 24884 } 24885 /* Compare destination mac. */ 24886 if (sal_memcmp(tnl_entry->dmac, hw_entry.dmac, 24887 sizeof(bcm_mac_t))) { 24888 *cmp_result = BCM_L3_CMP_NOT_EQUAL; 24889 return (BCM_E_NONE); 24890 } 24891 } 24892 *cmp_result = BCM_L3_CMP_EQUAL; 24893 return (BCM_E_NONE); 24894 } 24895 24896 /* Only be called when IPV6 tunnel insertion is full*/ 24897 int 24898 bcm_xgs3_tnl_init_defrag(int unit) 24899 { 24900 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 24901 int lkup_idx; /* Iteration index. */ 24902 int idx_to, idx_from; 24903 int idx_min, idx_max; 24904 int half_ent_cnt = 0; 24905 int ent_idx[2] = {0, 0}; 24906 int ifindex; 24907 int rv = BCM_E_FULL; 24908 _bcm_tnl_init_data_t tnl_info; 24909 uint8 *egr_ip_tunnel_buf = NULL; /* EGR_IP_TUNNEL DMA buffer */ 24910 egr_ip_tunnel_entry_t *egr_ip_tunnel; 24911 uint32 entry_type, tunnel_type; 24912 bcm_tunnel_initiator_t hw_entry; 24913 24914 soc_mem_t mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4); 24915 24916 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_set) || 24917 !BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get) || 24918 !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get) || 24919 !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_add) || 24920 !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_del)) { 24921 rv = BCM_E_UNAVAIL; 24922 goto clean_up; 24923 } 24924 24925 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 24926 /* get range for min and max indexes */ 24927 idx_min = tbl_ptr->idx_min; 24928 idx_max = tbl_ptr->idx_max; 24929 24930 egr_ip_tunnel_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES 24931 (unit, mem), 24932 "EGR_IP_TUNNEL buffer"); 24933 if (NULL == egr_ip_tunnel_buf) { 24934 rv = BCM_E_MEMORY; 24935 goto clean_up; 24936 } 24937 if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 24938 idx_min, idx_max, 24939 egr_ip_tunnel_buf)) < 0) { 24940 goto clean_up; 24941 } 24942 /* 24943 * Find two half EGR_IP_TUNNEL_IPV6 entries, 24944 * skip EGR_IP_TUNNEL entry 0 and 1, since entry 0 is reserved. 24945 */ 24946 for (lkup_idx = idx_min + 2; 24947 lkup_idx <= idx_max; lkup_idx += 2) { 24948 egr_ip_tunnel = soc_mem_table_idx_to_pointer 24949 (unit, mem, egr_ip_tunnel_entry_t *, 24950 egr_ip_tunnel_buf, lkup_idx); 24951 #ifdef BCM_TRIDENT3_SUPPORT 24952 if (SOC_IS_TRIDENT3X(unit)) { 24953 entry_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 24954 DATA_TYPEf); 24955 } else 24956 #endif 24957 { 24958 entry_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 24959 ENTRY_TYPEf); 24960 } 24961 tunnel_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel, 24962 TUNNEL_TYPEf); 24963 /* Only find IPV4 tunnel */ 24964 if (!(entry_type == 1 && tunnel_type == 0)) { 24965 continue; 24966 } 24967 /* If this entry and the next entry are occupied, skip, else there is an empty entry */ 24968 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx) && 24969 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx + 1)) { 24970 continue; 24971 } 24972 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) { 24973 ent_idx[half_ent_cnt] = lkup_idx; 24974 } else { 24975 ent_idx[half_ent_cnt] = lkup_idx + 1; 24976 } 24977 24978 half_ent_cnt++; 24979 if (half_ent_cnt == 2) { 24980 break; 24981 } 24982 } 24983 24984 if (half_ent_cnt != 2) { 24985 goto clean_up; 24986 } 24987 sal_memset(&hw_entry, 0, sizeof(hw_entry)); 24988 idx_from = ent_idx[1]; 24989 /* Read the entry will be moved from. */ 24990 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, idx_from, &hw_entry); 24991 if (rv < 0) { 24992 goto clean_up; 24993 } 24994 /* Find the free idx of the entry will be moved to. */ 24995 idx_to = (ent_idx[0] % 2) ? (ent_idx[0] - 1) : (ent_idx[0] + 1); 24996 /* Move entry to free entry. */ 24997 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_add) (unit, idx_to, &hw_entry, NULL); 24998 if (rv < 0) { 24999 goto clean_up; 25000 } 25001 25002 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf); 25003 /* get range for min and max indexes. */ 25004 idx_min = tbl_ptr->idx_min; 25005 idx_max = tbl_ptr->idx_max; 25006 25007 /* trvaverse L3_INTF to modify tnl_idx. */ 25008 for (ifindex = idx_min; ifindex <= idx_max; ifindex++) { 25009 if (!BCM_L3_INTF_USED_GET(unit, ifindex)) { 25010 continue; 25011 } 25012 sal_memset(&tnl_info, 0, sizeof(tnl_info)); 25013 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex, &tnl_info); 25014 if (rv < 0) { 25015 goto clean_up; 25016 } 25017 if (tnl_info.tnl_idx == idx_from) { 25018 tnl_info.tnl_idx = idx_to; 25019 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_set) (unit, ifindex, &tnl_info); 25020 if (rv < 0) { 25021 goto clean_up; 25022 } 25023 } 25024 } 25025 25026 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_del) (unit, idx_from, NULL); 25027 if (rv < 0) { 25028 goto clean_up; 25029 } 25030 25031 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 25032 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx_to) = 25033 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx_from); 25034 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx_from) = 0; 25035 25036 clean_up: 25037 if (egr_ip_tunnel_buf) { 25038 soc_cm_sfree(unit, egr_ip_tunnel_buf); 25039 } 25040 return (rv); 25041 } 25042 25043 /* 25044 * Function: 25045 * bcm_xgs3_tnl_init_add 25046 * Purpose: 25047 * Allocate tunnel initiator table index & Write tunnel initiator entry. 25048 * Routine trying to match new entry to an existing one, 25049 * if match found reference cound is incremented, otherwise 25050 * new index allocated & entry added to hw. 25051 * Parameters: 25052 * unit - (IN)StrataSwitch unit number. 25053 * flags - (IN)Table shared flags. 25054 * tnl_entry - (IN)Tunnel initiator entry. 25055 * index - (OUT)next hop index. 25056 * Returns: 25057 * BCM_E_XXX 25058 */ 25059 int 25060 bcm_xgs3_tnl_init_add(int unit, uint32 flags, bcm_tunnel_initiator_t *tnl_entry, 25061 int *index) 25062 { 25063 _bcm_l3_tbl_op_t data; /* Operation data. */ 25064 int rv = BCM_E_NONE; 25065 if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) { 25066 /* Make sure hw call is defined. */ 25067 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_add)) { 25068 return (BCM_E_UNAVAIL); 25069 } 25070 } 25071 25072 /* Initialization */ 25073 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 25074 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 25075 data.width = _BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, tnl_entry->type) ?\ 25076 _BCM_DOUBLE_WIDE: _BCM_SINGLE_WIDE; 25077 data.oper_flags = flags; 25078 data.entry_buffer = (void *)tnl_entry; 25079 data.hash_func = _bcm_xgs3_tnl_init_hash_calc; 25080 data.cmp_func = _bcm_xgs3_tnl_init_cmp; 25081 data.add_func = BCM_XGS3_L3_HWCALL(unit, tnl_init_add); 25082 if (flags & _BCM_L3_SHR_WITH_ID) { 25083 data.entry_index = *index; 25084 } 25085 25086 /* Add next hop table entry. */ 25087 rv = _bcm_xgs3_tbl_add(unit, &data); 25088 if ((BCM_E_FULL == rv) && (data.width == _BCM_DOUBLE_WIDE)) { 25089 if (BCM_E_NONE == bcm_xgs3_tnl_init_defrag(unit)) { 25090 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_add(unit, &data)); 25091 } 25092 } else if (rv < 0) { 25093 return rv; 25094 } 25095 *index = data.entry_index; 25096 25097 return (BCM_E_NONE); 25098 } 25099 25100 25101 /* 25102 * Function: 25103 * bcm_xgs3_tnl_init_del 25104 * Purpose: 25105 * Delete tunnels initiator entry. 25106 * Entry kept if reference counter not equals to 1(Other tunnels 25107 * reference the same entry). 25108 * 25109 * Parameters: 25110 * unit - (IN)StrataSwitch unit number. 25111 * flags - (IN)Table shared flags. 25112 * ent_index - (IN)Entry index. 25113 * Returns: 25114 * BCM_E_XXX 25115 */ 25116 int 25117 bcm_xgs3_tnl_init_del(int unit, uint32 flags, int ent_index) 25118 { 25119 bcm_tunnel_initiator_t hw_entry; /* Entry read from hw. */ 25120 _bcm_l3_tbl_op_t data; /* Delete operation info. */ 25121 int rv; 25122 25123 /* Initialization */ 25124 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 25125 25126 /* Default is single table entry operation.*/ 25127 data.width = _BCM_SINGLE_WIDE; 25128 25129 25130 /* Check hw call is defined. */ 25131 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_del)) { 25132 return (BCM_E_UNAVAIL); 25133 } 25134 25135 if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) { 25136 /* Get tunnel initiator entry from hw. */ 25137 if (BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get)) { 25138 BCM_XGS3_L3_MODULE_LOCK(unit); 25139 rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, ent_index, 25140 &hw_entry)); 25141 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25142 BCM_IF_ERROR_RETURN(rv); 25143 25144 /* IPv6 tunnels occupy 2 slots. */ 25145 if(_BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, hw_entry.type)) { 25146 data.width = _BCM_DOUBLE_WIDE; 25147 } 25148 } else { 25149 return (BCM_E_UNAVAIL); 25150 } 25151 } 25152 25153 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 25154 data.entry_index = ent_index; 25155 data.oper_flags = flags; 25156 data.delete_func = BCM_XGS3_L3_HWCALL(unit, tnl_init_del); 25157 25158 /* Delete tunnel initiator table entry. */ 25159 return _bcm_xgs3_tbl_del(unit, &data); 25160 } 25161 25162 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 25163 /* 25164 * Function: 25165 * _bcm_xgs3_l3_tnl_init_find 25166 * Purpose: 25167 * Find a matched tunnel initiator. 25168 * Parameters: 25169 * unit - (IN)StrataSwitch unit number. 25170 * info - (IN)Tunnel initiator information. 25171 * index - (OUT)HW Tunnel index. 25172 * Returns: 25173 * BCM_E_XXX 25174 */ 25175 int 25176 _bcm_xgs3_l3_tnl_init_find(int unit, bcm_tunnel_initiator_t *info, 25177 int *tnl_idx) 25178 { 25179 _bcm_l3_tbl_op_t data; /* Operation data */ 25180 25181 /* Input parameters check. */ 25182 if ((NULL == info) || (NULL == tnl_idx)) { 25183 return (BCM_E_PARAM); 25184 } 25185 25186 /* Initialization */ 25187 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 25188 25189 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 25190 data.width = _BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, info->type) ? 25191 _BCM_DOUBLE_WIDE: _BCM_SINGLE_WIDE; 25192 data.oper_flags = info->flags; 25193 data.entry_buffer = (void *)info; 25194 data.hash_func = _bcm_xgs3_tnl_init_hash_calc; 25195 data.cmp_func = _bcm_xgs3_tnl_init_cmp; 25196 25197 /* Find entry */ 25198 BCM_IF_ERROR_RETURN (_bcm_xgs3_tbl_match(unit, &data)); 25199 25200 *tnl_idx = data.entry_index; 25201 25202 return (BCM_E_NONE); 25203 } 25204 #endif /* BCM_TRIDENT2_SUPPORT | BCM_GREYHOUND2_SUPPORT */ 25205 25206 /* 25207 * Function: 25208 * bcm_xgs3_tunnel_initiator_set 25209 * Purpose: 25210 * Set the tunnel initiator property for the given L3 interface 25211 * Parameters: 25212 * unit - (IN)SOC unit number. 25213 * intf - (IN)L3 interface. 25214 * tnl_info - (IN)Tunnel initiator information. 25215 * Returns: 25216 * BCM_E_XXX 25217 */ 25218 int 25219 bcm_xgs3_tunnel_initiator_set(int unit, bcm_l3_intf_t *intf, 25220 bcm_tunnel_initiator_t *tnl_info) 25221 { 25222 _bcm_tnl_init_data_t cfg_ent; /* Tunnel configuration entry. */ 25223 int ifindex; /* Interface index. */ 25224 int support; /* Tunnel type is supported flag.*/ 25225 int rv; /* Operation return status. */ 25226 uint32 shr_flags; /* Table shared flags. */ 25227 int tnl_dscp_tbl_sz, max_num_maps; 25228 25229 /* Make sure module was initialized. */ 25230 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25231 return (BCM_E_INIT); 25232 } 25233 25234 /* Input parameters check. */ 25235 if ((NULL == intf) || (NULL == tnl_info)) { 25236 return (BCM_E_PARAM); 25237 } 25238 25239 ifindex = intf->l3a_intf_id; 25240 /* Validate interface index. */ 25241 if (ifindex >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 25242 return (BCM_E_PARAM); 25243 } 25244 25245 if (!BCM_L3_INTF_USED_GET(unit, ifindex)) { 25246 return (BCM_E_NOT_FOUND); 25247 } 25248 25249 /* Validate ttl for firebolt based boards. */ 25250 if (!BCM_TTL_VALID(tnl_info->ttl)) { 25251 return (BCM_E_PARAM); 25252 } 25253 25254 /* Validate IP tunnel DSCP SEL. */ 25255 if (tnl_info->dscp_sel > 2 || tnl_info->dscp_sel < 0) { 25256 return (BCM_E_PARAM); 25257 } 25258 25259 /* Validate IP tunnel DSCP value. */ 25260 if (tnl_info->dscp > 63 || tnl_info->dscp < 0) { 25261 return (BCM_E_PARAM); 25262 } 25263 25264 tnl_dscp_tbl_sz = soc_mem_index_count 25265 (unit, BCM_XGS3_L3_MEM(unit, tnl_dscp)); 25266 max_num_maps = tnl_dscp_tbl_sz/_BCM_TNL_DSCP_MAP_TBL_SIZE; 25267 /* Validate DSCP map */ 25268 if ((tnl_info->dscp_map < 0) || (tnl_info->dscp_map > max_num_maps)) { 25269 return (BCM_E_PARAM); 25270 } 25271 25272 /* Validate flow label value. */ 25273 if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type)) { 25274 if (tnl_info->flow_label > (1 << 20)) { 25275 return (BCM_E_PARAM); 25276 } 25277 } 25278 25279 BCM_IF_ERROR_RETURN 25280 (_bcm_xgs3_tunnel_type_support_check(unit, tnl_info->type, 25281 NULL, &support)); 25282 if (FALSE == support) { 25283 return (BCM_E_UNAVAIL); 25284 } 25285 25286 25287 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_set) || 25288 !BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get)) { 25289 return (BCM_E_UNAVAIL); 25290 } 25291 25292 /* Reset tunnel configuration buffer. */ 25293 sal_memset(&cfg_ent, 0, sizeof(_bcm_tnl_init_data_t)); 25294 25295 /* Check if interface already has tunnel attached. */ 25296 BCM_XGS3_L3_MODULE_LOCK(unit); 25297 rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex, 25298 &cfg_ent)); 25299 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25300 BCM_IF_ERROR_RETURN(rv); 25301 25302 /* Check for tunnel replacement. */ 25303 if (cfg_ent.tnl_idx) { 25304 if (!(tnl_info->flags & BCM_TUNNEL_REPLACE)) { 25305 return (BCM_E_EXISTS); 25306 } 25307 /* Destroy original tunnel initiator. */ 25308 BCM_IF_ERROR_RETURN (bcm_xgs3_tunnel_initiator_clear(unit, intf)); 25309 } 25310 25311 /* Convert tunnel specific flags to table management flags. */ 25312 BCM_IF_ERROR_RETURN 25313 (_bcm_xgs3_tunnel_flags_to_shr(tnl_info->flags, &shr_flags)); 25314 25315 /* Add tunnel initiator entry to hw. */ 25316 BCM_IF_ERROR_RETURN(bcm_xgs3_tnl_init_add(unit, shr_flags, tnl_info, 25317 &cfg_ent.tnl_idx)); 25318 25319 BCM_XGS3_L3_MODULE_LOCK(unit); 25320 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_set) (unit, ifindex, 25321 &cfg_ent); 25322 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25323 25324 /* Do best effort clean up if needed. */ 25325 if (rv < 0) { 25326 bcm_xgs3_tnl_init_del(unit, 0, cfg_ent.tnl_idx); 25327 } 25328 return rv; 25329 } 25330 25331 /* 25332 * Function: 25333 * bcm_xgs3_tunnel_initiator_clear 25334 * Purpose: 25335 * Delete the tunnel association for the given L3 interface 25336 * Parameters: 25337 * unit - SOC unit number 25338 * intf - the given L3 interface 25339 * Returns: 25340 * BCM_E_XXX 25341 */ 25342 25343 int 25344 bcm_xgs3_tunnel_initiator_clear(int unit, bcm_l3_intf_t *intf) 25345 { 25346 _bcm_tnl_init_data_t cfg_ent; /* Tunnel configuration entry. */ 25347 int ifindex; /* Interface index. */ 25348 int rv; 25349 25350 /* Make sure module was initialized. */ 25351 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25352 return (BCM_E_INIT); 25353 } 25354 25355 /* Input parameters check. */ 25356 if (NULL == intf) { 25357 return (BCM_E_PARAM); 25358 } 25359 25360 ifindex = intf->l3a_intf_id; 25361 /* Validate interface index. */ 25362 if (ifindex >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 25363 return (BCM_E_PARAM); 25364 } 25365 25366 if (!BCM_L3_INTF_USED_GET(unit, ifindex)) { 25367 return (BCM_E_NOT_FOUND); 25368 } 25369 25370 /* Make sure required hw call is defined. */ 25371 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_reset) || 25372 !BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get)) { 25373 return (BCM_E_UNAVAIL); 25374 } 25375 25376 /* Reset tunnel configuration buffer. */ 25377 sal_memset(&cfg_ent, 0, sizeof(_bcm_tnl_init_data_t)); 25378 25379 /* Read tunnel info from hw. */ 25380 BCM_XGS3_L3_MODULE_LOCK(unit); 25381 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex, 25382 &cfg_ent); 25383 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25384 BCM_IF_ERROR_RETURN(rv); 25385 25386 /* Make sure tunnel index is valid. */ 25387 if (!cfg_ent.tnl_idx) { 25388 return (BCM_E_NOT_FOUND); 25389 } 25390 25391 /* Remove tunnel initiator entry to hw. */ 25392 BCM_IF_ERROR_RETURN(bcm_xgs3_tnl_init_del(unit, 0, cfg_ent.tnl_idx)); 25393 25394 BCM_XGS3_L3_MODULE_LOCK(unit); 25395 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_reset) (unit, ifindex); 25396 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25397 return rv; 25398 } 25399 25400 /* 25401 * Function: 25402 * bcm_xgs3_tunnel_initiator_get 25403 * Purpose: 25404 * Get the tunnel initiator property for the given L3 interface 25405 * Parameters: 25406 * unit - SOC unit number 25407 * intf - the given L3 interface 25408 * tunnel - (OUT) the tunnel header information 25409 * Returns: 25410 * BCM_E_XXX 25411 */ 25412 int 25413 bcm_xgs3_tunnel_initiator_get(int unit, bcm_l3_intf_t *intf, 25414 bcm_tunnel_initiator_t *tnl_info) 25415 { 25416 _bcm_tnl_init_data_t cfg_ent; /* Tunnel configuration entry. */ 25417 int ifindex; /* Interface index. */ 25418 int rv; 25419 25420 /* Make sure module was initialized. */ 25421 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25422 return (BCM_E_INIT); 25423 } 25424 25425 /* Input parameters check. */ 25426 if ((NULL == intf) || (NULL == tnl_info)) { 25427 return (BCM_E_PARAM); 25428 } 25429 25430 ifindex = intf->l3a_intf_id; 25431 /* Validate interface index. */ 25432 if (ifindex >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 25433 return (BCM_E_PARAM); 25434 } 25435 25436 if (!BCM_L3_INTF_USED_GET(unit, ifindex)) { 25437 return (BCM_E_NOT_FOUND); 25438 } 25439 25440 /* Make sure required hw call is defined. */ 25441 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get) || 25442 !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get)) { 25443 return (BCM_E_UNAVAIL); 25444 } 25445 25446 /* Reset tunnel configuration buffer. */ 25447 sal_memset(&cfg_ent, 0, sizeof(_bcm_tnl_init_data_t)); 25448 25449 /* Read tunnel index/ (ER adj_mac_idx, ttl,type) from interface table. */ 25450 BCM_XGS3_L3_MODULE_LOCK(unit); 25451 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex, 25452 &cfg_ent); 25453 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25454 BCM_IF_ERROR_RETURN(rv); 25455 25456 /* Make sure tunnel index is valid. */ 25457 if (!cfg_ent.tnl_idx) { 25458 return (BCM_E_NOT_FOUND); 25459 } 25460 25461 /* Get tunnel initiator entry info from hw. */ 25462 BCM_XGS3_L3_MODULE_LOCK(unit); 25463 rv =BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, cfg_ent.tnl_idx, 25464 tnl_info); 25465 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25466 BCM_IF_ERROR_RETURN(rv); 25467 return (BCM_E_NONE); 25468 } 25469 25470 /* 25471 * Function: 25472 * bcm_xgs3_tunnel_initiator_traverse 25473 * Purpose: 25474 * Traverse all tunnel initiator entries 25475 * Parameters: 25476 * unit - SOC unit number 25477 * cb - User callback function, called once per entry 25478 * user_data - User supplied cookie used in parameter in callback function 25479 * Returns: 25480 * BCM_E_XXX 25481 */ 25482 int 25483 bcm_xgs3_tunnel_initiator_traverse(int unit, 25484 bcm_tunnel_initiator_traverse_cb cb, 25485 void *user_data) 25486 { 25487 int num_intf, idx; 25488 bcm_l3_intf_t intf; 25489 bcm_tunnel_initiator_t info; 25490 int rv = BCM_E_NONE; 25491 25492 /* Make sure module was initialized. */ 25493 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25494 return (BCM_E_INIT); 25495 } 25496 25497 /* Get interface table size. */ 25498 num_intf = BCM_XGS3_L3_IF_TBL_SIZE(unit); 25499 25500 sal_memset(&intf, 0, sizeof(bcm_l3_intf_t)); 25501 25502 for(idx = 0; idx < num_intf; idx++) { 25503 /* Reset buffer before read. */ 25504 bcm_tunnel_initiator_t_init(&info); 25505 25506 /* Get tunnel initiator through interface Id */ 25507 intf.l3a_intf_id = idx; 25508 rv = bcm_xgs3_tunnel_initiator_get(unit, &intf, &info); 25509 25510 /* Check for read errors & invalid entries. */ 25511 if (rv < 0) { 25512 if (rv != BCM_E_NOT_FOUND) { 25513 break; 25514 } 25515 continue; 25516 } 25517 25518 if (cb) { 25519 rv = (*cb) (unit, &info, user_data); 25520 #ifdef BCM_CB_ABORT_ON_ERR 25521 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 25522 break; 25523 } 25524 #endif 25525 } 25526 } 25527 25528 /* Reset last read status. */ 25529 if (BCM_E_NOT_FOUND == rv) { 25530 rv = BCM_E_NONE; 25531 } 25532 25533 return rv; 25534 } 25535 25536 /* 25537 * Function: 25538 * bcm_xgs3_tunnel_dscp_map_create 25539 * Purpose: 25540 * Create a tunnel DSCP map instance. 25541 * Parameters: 25542 * unit - (IN) SOC unit # 25543 * flags - (IN) BCM_L3_XXX 25544 * dscp_map_id - (OUT) Allocated DSCP map ID 25545 * Returns: 25546 * BCM_E_XXX 25547 */ 25548 int 25549 bcm_xgs3_tunnel_dscp_map_create(int unit, uint32 flags, int *dscp_map_id) 25550 { 25551 int idx; /* Iteration index. */ 25552 int idx_max; /* Iteration index max value. */ 25553 25554 /* Make sure module was initialized. */ 25555 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25556 return (BCM_E_INIT); 25557 } 25558 25559 /* Input parameters check. */ 25560 if (NULL == dscp_map_id) { 25561 return (BCM_E_PARAM); 25562 } 25563 25564 if (flags & BCM_L3_WITH_ID) { 25565 if (BCM_L3_DSCP_MAP_USED_GET(unit, *dscp_map_id) && 25566 !(flags & BCM_L3_REPLACE)) { 25567 return (BCM_E_EXISTS); 25568 } 25569 BCM_L3_DSCP_MAP_USED_SET(unit, *dscp_map_id); 25570 return (BCM_E_NONE); 25571 } 25572 25573 idx_max = BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit); 25574 25575 for (idx = 0; idx < idx_max; idx++) { 25576 if (!BCM_L3_DSCP_MAP_USED_GET(unit, idx)) { 25577 BCM_L3_DSCP_MAP_USED_SET(unit, idx); 25578 *dscp_map_id = idx; 25579 return (BCM_E_NONE); 25580 } 25581 } 25582 return (BCM_E_FULL); 25583 } 25584 25585 /* 25586 * Function: 25587 * bcm_xgs3_tunnel_dscp_map_destroy 25588 * Purpose: 25589 * Destroy an existing tunnel DSCP map instance. 25590 * Parameters: 25591 * unit - (IN) SOC unit # 25592 * dscp_map_id - (IN) DSCP map ID 25593 * Returns: 25594 * BCM_E_XXX 25595 */ 25596 int 25597 bcm_xgs3_tunnel_dscp_map_destroy(int unit, int dscp_map_id) 25598 { 25599 int idx_max; /* Maximum dscp map index. */ 25600 25601 /* Make sure module was initialized. */ 25602 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25603 return (BCM_E_INIT); 25604 } 25605 25606 idx_max = SOC_IS_TRX(unit) ? 1 : BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit); 25607 if ((dscp_map_id < 0) || (dscp_map_id >= idx_max)) { 25608 return (BCM_E_PARAM); 25609 } 25610 25611 BCM_L3_DSCP_MAP_USED_CLR(unit, dscp_map_id); 25612 25613 return (BCM_E_NONE); 25614 } 25615 25616 /* 25617 * Function: 25618 * bcm_xgs3_tunnel_dscp_map_set 25619 * Purpose: 25620 * Set the mapping of { internal priority, color } 25621 * to a DSCP value for outer tunnel headers 25622 * in the specified DSCP map instance. 25623 * Parameters: 25624 * unit - (IN) BCM device number. 25625 * dscp_map_id - (IN) DSCP map ID 25626 * dscp_map - (IN) DSCP map structure. 25627 * Returns: 25628 * BCM_E_XXX 25629 */ 25630 int 25631 bcm_xgs3_tunnel_dscp_map_set(int unit, int dscp_map_id, 25632 bcm_tunnel_dscp_map_t *dscp_map) 25633 { 25634 int cng, index, rv; 25635 25636 /* Make sure module was initialized. */ 25637 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25638 return (BCM_E_INIT); 25639 } 25640 25641 /* Make sure required hw call is defined. */ 25642 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_set)) { 25643 return (BCM_E_UNAVAIL); 25644 } 25645 25646 cng = _BCM_COLOR_ENCODING(unit, dscp_map->color); 25647 25648 /* Get the base index for this DSCP map */ 25649 index = (dscp_map_id * 32); 25650 25651 /* Add the offset based on priority and color values */ 25652 index += ((dscp_map->priority << 2) | (cng & 3)); 25653 25654 /* Set tunnel dscp entry info in hw. */ 25655 BCM_XGS3_L3_MODULE_LOCK(unit); 25656 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_set)(unit, index, dscp_map); 25657 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25658 return rv; 25659 } 25660 25661 /* 25662 * Function: 25663 * bcm_xgs3_tunnel_dscp_map_get 25664 * Purpose: 25665 * Get the mapping of { internal priority, color } 25666 * to a DSCP value for outer tunnel headers 25667 * in the specified DSCP map instance. 25668 * Parameters: 25669 * unit - (IN) BCM device number.# 25670 * dscp_map_id - (IN) DSCP map ID 25671 * dscp_map - (OUT) DSCP map structure. 25672 * Returns: 25673 * BCM_E_XXX 25674 */ 25675 int 25676 bcm_xgs3_tunnel_dscp_map_get(int unit, int dscp_map_id, 25677 bcm_tunnel_dscp_map_t *dscp_map) 25678 { 25679 int cng, index, rv; 25680 25681 /* Make sure module was initialized. */ 25682 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25683 return (BCM_E_INIT); 25684 } 25685 25686 /* Make sure required hw call is defined. */ 25687 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_get)) { 25688 return (BCM_E_UNAVAIL); 25689 } 25690 25691 cng = _BCM_COLOR_ENCODING(unit, dscp_map->color); 25692 25693 /* Get the base index for this DSCP map in EGR_DSCP_TABLEm */ 25694 index = (dscp_map_id * 32); 25695 25696 /* Add the offset based on priority and color values */ 25697 index += ((dscp_map->priority << 2) | (cng & 3)); 25698 25699 /* Get tunnel dscp entry info from hw. */ 25700 BCM_XGS3_L3_MODULE_LOCK(unit); 25701 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_get) (unit, index, dscp_map); 25702 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25703 return rv; 25704 } 25705 25706 #if defined(BCM_TRX_SUPPORT) 25707 /* 25708 * Function: 25709 * _bcm_trx_tunnel_dscp_map_port_set 25710 * Purpose: 25711 * Set the mapping of { internal priority, color } 25712 * to a DSCP value for outer tunnel headers 25713 * in the specified egress port/ports. 25714 * Parameters: 25715 * unit - (IN) BCM device number. 25716 * port - (IN) Egress port number. 25717 * dscp_map - (IN) DSCP map structure. 25718 * Returns: 25719 * BCM_E_XXX 25720 */ 25721 int 25722 _bcm_trx_tunnel_dscp_map_port_set(int unit, bcm_port_t port, 25723 bcm_tunnel_dscp_map_t *dscp_map) 25724 { 25725 int cng, index, rv; 25726 bcm_module_t mod_out; 25727 bcm_port_t port_out; 25728 bcm_trunk_t tgid_out; 25729 int id_out; 25730 int is_local; 25731 /* Make sure module was initialized. */ 25732 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25733 return (BCM_E_INIT); 25734 } 25735 25736 if ((dscp_map == NULL) || 25737 (dscp_map->priority < BCM_PRIO_MIN) || 25738 (dscp_map->priority > BCM_PRIO_MAX) || 25739 (dscp_map->dscp < 0) || 25740 (dscp_map->dscp > 63)) { 25741 return (BCM_E_PARAM); 25742 } 25743 25744 /* Make sure required hw call is defined. */ 25745 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_set)) { 25746 return (BCM_E_UNAVAIL); 25747 } 25748 25749 cng = _BCM_COLOR_ENCODING(unit, dscp_map->color); 25750 25751 /* Add the offset based on priority and color values */ 25752 if (BCM_GPORT_IS_SET(port)) { 25753 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, 25754 &mod_out, &port_out, &tgid_out, &id_out)); 25755 if (BCM_GPORT_IS_SUBPORT_PORT(port)) { 25756 25757 #if defined(BCM_HGPROXY_COE_SUPPORT) 25758 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 25759 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) { 25760 BCM_IF_ERROR_RETURN( 25761 _bcmi_coe_subport_physical_port_get(unit, 25762 port, 25763 &port)); 25764 } else 25765 #endif 25766 25767 #if defined(BCM_KATANA2_SUPPORT) 25768 if ((soc_feature(unit, soc_feature_linkphy_coe) || 25769 soc_feature(unit, soc_feature_subtag_coe)) && 25770 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, 25771 port)) { 25772 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(unit, 25773 mod_out, port_out, &port)); 25774 if (((port < SOC_INFO(unit).pp_port_index_min) || 25775 (port > SOC_INFO(unit).pp_port_index_max))) { 25776 return BCM_E_PORT; 25777 } 25778 } else 25779 #endif 25780 { 25781 return BCM_E_PORT; 25782 } 25783 } else { 25784 if ((-1 != tgid_out) || (-1 != id_out)) { 25785 return BCM_E_PORT; 25786 } 25787 25788 BCM_IF_ERROR_RETURN 25789 (_bcm_esw_modid_is_local(unit, mod_out, &is_local)); 25790 if (!is_local) { 25791 return BCM_E_PORT; 25792 } else { 25793 BCM_IF_ERROR_RETURN( 25794 bcm_esw_port_local_get(unit, port, &port)); 25795 } 25796 } 25797 } else if (!SOC_PORT_VALID(unit, port)) { 25798 return BCM_E_PORT; 25799 } 25800 25801 /* KT2 supports 170 ports * 64 entries */ 25802 index = ((port & SOC_PORT_ADDR_MAX(unit)) << 6) | \ 25803 ((dscp_map->priority & 0xF) << 2) | \ 25804 (cng & 0x3); 25805 25806 /* Set tunnel dscp entry info in hw. */ 25807 BCM_XGS3_L3_MODULE_LOCK(unit); 25808 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_set)(unit, index, dscp_map); 25809 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25810 return rv; 25811 } 25812 25813 /* 25814 * Function: 25815 * _bcm_trx_tunnel_dscp_map_port_get 25816 * Purpose: 25817 * Get the mapping of { internal priority, color } 25818 * to a DSCP value for outer tunnel headers 25819 * in the specified egress port/ports. 25820 * Parameters: 25821 * unit - (IN) BCM device number.# 25822 * port - (IN) Egress port number. 25823 * dscp_map - (OUT) DSCP map structure. 25824 * Returns: 25825 * BCM_E_XXX 25826 */ 25827 int 25828 _bcm_trx_tunnel_dscp_map_port_get(int unit, bcm_port_t port, 25829 bcm_tunnel_dscp_map_t *dscp_map) 25830 { 25831 int cng, index, rv; 25832 bcm_module_t mod_out; 25833 bcm_port_t port_out; 25834 bcm_trunk_t tgid_out; 25835 int id_out; 25836 int is_local; 25837 25838 /* Make sure module was initialized. */ 25839 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25840 return (BCM_E_INIT); 25841 } 25842 25843 if ((dscp_map == NULL) || 25844 (dscp_map->priority < BCM_PRIO_MIN) || 25845 (dscp_map->priority > BCM_PRIO_MAX)) { 25846 return (BCM_E_PARAM); 25847 } 25848 25849 /* Make sure required hw call is defined. */ 25850 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_get)) { 25851 return (BCM_E_UNAVAIL); 25852 } 25853 25854 cng = _BCM_COLOR_ENCODING(unit, dscp_map->color); 25855 25856 /* Add the offset based on port, priority and color values */ 25857 if (BCM_GPORT_IS_SET(port)) { 25858 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, 25859 &mod_out, &port_out, &tgid_out, &id_out)); 25860 if (BCM_GPORT_IS_SUBPORT_PORT(port)) { 25861 25862 #if defined(BCM_HGPROXY_COE_SUPPORT) 25863 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 25864 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) { 25865 BCM_IF_ERROR_RETURN( 25866 _bcmi_coe_subport_physical_port_get(unit, 25867 port, 25868 &port)); 25869 } else 25870 #endif 25871 25872 #if defined(BCM_KATANA2_SUPPORT) 25873 if ((soc_feature(unit, soc_feature_linkphy_coe) || 25874 soc_feature(unit, soc_feature_subtag_coe)) && 25875 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, 25876 port)) { 25877 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(unit, 25878 mod_out, port_out, &port)); 25879 if (((port < SOC_INFO(unit).pp_port_index_min) || 25880 (port > SOC_INFO(unit).pp_port_index_max))) { 25881 return BCM_E_PORT; 25882 } 25883 } else 25884 #endif 25885 { 25886 return BCM_E_PORT; 25887 } 25888 } else { 25889 if ((-1 != tgid_out) || (-1 != id_out)) { 25890 return BCM_E_PORT; 25891 } 25892 25893 BCM_IF_ERROR_RETURN 25894 (_bcm_esw_modid_is_local(unit, mod_out, &is_local)); 25895 if (!is_local) { 25896 return BCM_E_PORT; 25897 } else { 25898 BCM_IF_ERROR_RETURN( 25899 bcm_esw_port_local_get(unit, port, &port)); 25900 } 25901 } 25902 } else if (!SOC_PORT_VALID(unit, port)) { 25903 return BCM_E_PORT; 25904 } 25905 25906 /* KT2 supports 170 ports * 64 entries */ 25907 index = ((port & SOC_PORT_ADDR_MAX(unit)) << 6) | \ 25908 ((dscp_map->priority & 0xF) << 2) | \ 25909 (cng & 0x3); 25910 25911 /* Get tunnel dscp entry info from hw. */ 25912 BCM_XGS3_L3_MODULE_LOCK(unit); 25913 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_get) (unit, index, dscp_map); 25914 BCM_XGS3_L3_MODULE_UNLOCK(unit); 25915 return rv; 25916 } 25917 #endif /* BCM_TRX_SUPPORT */ 25918 25919 /* 25920 * Function: 25921 * bcm_xgs3_tunnel_config_set 25922 * Purpose: 25923 * Set the global tunnel initiator property 25924 * Parameters: 25925 * unit - (IN)SOC unit number. 25926 * tconfig - (IN)L3 tunneling configuration 25927 * Returns: 25928 * BCM_E_XXX 25929 */ 25930 25931 int 25932 bcm_xgs3_tunnel_config_set(int unit, bcm_tunnel_config_t *tconfig) 25933 { 25934 soc_reg_t reg; 25935 /* Make sure module was initialized. */ 25936 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 25937 return (BCM_E_INIT); 25938 } 25939 25940 /* Input parameters check.*/ 25941 if ((NULL == tconfig) || (tconfig->ip4_id > 0xffff) || 25942 (tconfig->ip4_id < 0)) { 25943 return (BCM_E_PARAM); 25944 } 25945 25946 /* Check if IPv4 ID space is global */ 25947 #if defined BCM_TRIUMPH2_SUPPORT 25948 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 25949 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 25950 SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || 25951 SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit)) { 25952 int val; 25953 egr_fragment_id_table_entry_t entry; 25954 BCM_IF_ERROR_RETURN 25955 (bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val)); 25956 if (val) { 25957 sal_memset(&entry, 0, sizeof(egr_fragment_id_table_entry_t)); 25958 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry, FRAGMENT_IDf, 25959 tconfig->ip4_id); 25960 BCM_IF_ERROR_RETURN 25961 (soc_mem_write(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ALL, 25962 0, &entry)); 25963 } 25964 } 25965 #endif 25966 25967 /* 25968 * IPv4 ID for non-triumph2 devices 25969 */ 25970 if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_CONTROLr)) { 25971 BCM_IF_ERROR_RETURN 25972 (soc_reg_field32_modify(unit, EGR_TUNNEL_CONTROLr, REG_PORT_ANY, 25973 IPV4_IDf, tconfig->ip4_id)); 25974 } 25975 25976 /* 25977 * PIM Sparse Mode DR1 Header 25978 */ 25979 reg = EGR_TUNNEL_PIMDR1_CFG0r; 25980 #ifdef BCM_TRIDENT3_SUPPORT 25981 if (SOC_IS_TRIDENT3X(unit)) { 25982 reg = FLEX_EDITOR_TUNNEL_PIMDR1_CFG0r; 25983 } 25984 #endif 25985 if (SOC_REG_IS_VALID(unit, reg)) { 25986 BCM_IF_ERROR_RETURN 25987 (soc_reg_field32_modify(unit, reg, REG_PORT_ANY, 25988 MS_PIMSM_HDRf, tconfig->ms_pimsm_hdr1)); 25989 } 25990 25991 reg = EGR_TUNNEL_PIMDR1_CFG1r; 25992 #ifdef BCM_TRIDENT3_SUPPORT 25993 if (SOC_IS_TRIDENT3X(unit)) { 25994 reg = FLEX_EDITOR_TUNNEL_PIMDR1_CFG1r; 25995 } 25996 #endif 25997 if (SOC_REG_IS_VALID(unit, reg)) { 25998 BCM_IF_ERROR_RETURN 25999 (soc_reg_field32_modify(unit, reg, REG_PORT_ANY, 26000 LS_PIMSM_HDRf, tconfig->ls_pimsm_hdr1)); 26001 } 26002 26003 /* 26004 * PIM Sparse Mode DR2 Header 26005 */ 26006 reg = EGR_TUNNEL_PIMDR2_CFG0r; 26007 #ifdef BCM_TRIDENT3_SUPPORT 26008 if (SOC_IS_TRIDENT3X(unit)) { 26009 reg = FLEX_EDITOR_TUNNEL_PIMDR2_CFG0r; 26010 } 26011 #endif 26012 if (SOC_REG_IS_VALID(unit, reg)) { 26013 BCM_IF_ERROR_RETURN 26014 (soc_reg_field32_modify(unit, reg, REG_PORT_ANY, 26015 MS_PIMSM_HDRf, tconfig->ms_pimsm_hdr2)); 26016 } 26017 26018 reg = EGR_TUNNEL_PIMDR2_CFG1r; 26019 #ifdef BCM_TRIDENT3_SUPPORT 26020 if (SOC_IS_TRIDENT3X(unit)) { 26021 reg = FLEX_EDITOR_TUNNEL_PIMDR2_CFG1r; 26022 } 26023 #endif 26024 if (SOC_REG_IS_VALID(unit, reg)) { 26025 BCM_IF_ERROR_RETURN 26026 (soc_reg_field32_modify(unit, reg, REG_PORT_ANY, 26027 LS_PIMSM_HDRf, tconfig->ls_pimsm_hdr2)); 26028 } 26029 26030 return (BCM_E_NONE); 26031 } 26032 26033 /* 26034 * Function: 26035 * bcm_xgs3_tunnel_config_get 26036 * Purpose: 26037 * Get the global tunnel initiator property 26038 * Parameters: 26039 * unit - SOC unit number 26040 * tconfig - Global information about the L3 tunneling configuration 26041 * Returns: 26042 * BCM_E_XXX 26043 */ 26044 26045 int 26046 bcm_xgs3_tunnel_config_get(int unit, bcm_tunnel_config_t *tconfig) 26047 { 26048 uint32 reg_val; /* Register value */ 26049 26050 /* Make sure module was initialized. */ 26051 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 26052 return (BCM_E_INIT); 26053 } 26054 26055 /* Input parameters check.*/ 26056 if (NULL == tconfig) { 26057 return (BCM_E_PARAM); 26058 } 26059 26060 /* Check if IPv4 ID space is global */ 26061 #if defined BCM_TRIUMPH2_SUPPORT 26062 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 26063 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 26064 SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || 26065 SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit)) { 26066 int val; 26067 egr_fragment_id_table_entry_t entry; 26068 BCM_IF_ERROR_RETURN 26069 (bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val)); 26070 if (val) { 26071 BCM_IF_ERROR_RETURN 26072 (soc_mem_read(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ANY, 26073 0, &entry)); 26074 tconfig->ip4_id = soc_EGR_FRAGMENT_ID_TABLEm_field32_get 26075 (unit, &entry, FRAGMENT_IDf); 26076 } 26077 } 26078 #endif 26079 26080 /* 26081 * IPv4 ID for non-triumph2 devices 26082 */ 26083 if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_CONTROLr)) { 26084 BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_CONTROLr(unit, ®_val)); 26085 tconfig->ip4_id = 26086 soc_reg_field_get(unit, EGR_TUNNEL_CONTROLr, reg_val, IPV4_IDf); 26087 } 26088 26089 /* 26090 * PIM Sparse Mode DR1 Header 26091 */ 26092 if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR1_CFG0r)) { 26093 BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR1_CFG0r(unit, ®_val)); 26094 tconfig->ms_pimsm_hdr1 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR1_CFG0r, 26095 reg_val, MS_PIMSM_HDRf); 26096 } 26097 26098 if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR1_CFG1r)) { 26099 BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR1_CFG1r(unit, ®_val)); 26100 tconfig->ls_pimsm_hdr1 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR1_CFG1r, 26101 reg_val, LS_PIMSM_HDRf); 26102 } 26103 26104 /* 26105 * PIM Sparse Mode DR2 Header 26106 */ 26107 if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR2_CFG0r)) { 26108 BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR2_CFG0r(unit, ®_val)); 26109 tconfig->ms_pimsm_hdr2 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR2_CFG0r, 26110 reg_val, MS_PIMSM_HDRf); 26111 } 26112 26113 if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR2_CFG1r)) { 26114 BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR2_CFG1r(unit, ®_val)); 26115 tconfig->ls_pimsm_hdr2 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR2_CFG1r, 26116 reg_val, LS_PIMSM_HDRf); 26117 } 26118 26119 return (BCM_E_NONE); 26120 } 26121 26122 26123 int 26124 bcm_xgs3_ip6_defip_find_index(int unit, int index, bcm_l3_route_t *lpm_cfg) 26125 { 26126 return (BCM_E_UNAVAIL); 26127 } 26128 26129 26130 /* 26131 * Function: 26132 * _bcm_xgs3_ecmp_grp_get 26133 * Purpose: 26134 * Get ecmp group next hop members by index. 26135 * Parameters: 26136 * unit - (IN)SOC unit number. 26137 * ecmp_index - (IN)Ecmp group id to read. 26138 * ecmp_count - (IN)Maximum number of entries to read. 26139 * nh_idx - (OUT)Next hop indexes. 26140 * Returns: 26141 * BCM_E_XXX 26142 */ 26143 STATIC int 26144 _bcm_xgs3_ecmp_grp_get(int unit, int ecmp_idx, int ecmp_count, int *nh_idx) 26145 { 26146 int idx; /* Iteration index. */ 26147 int max_ent_count; /* Number of entries to read. */ 26148 uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry. */ 26149 int one_entry_grp = TRUE; /* Single next hop entry group. */ 26150 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 26151 #ifdef BCM_TOMAHAWK3_SUPPORT 26152 int lb_mode; 26153 #endif 26154 26155 /* Input parameters sanity check. */ 26156 if ((NULL == nh_idx) || (ecmp_count < 1)) { 26157 return (BCM_E_PARAM); 26158 } 26159 26160 /* Zero all next hop indexes first. */ 26161 sal_memset(nh_idx, 0, ecmp_count * sizeof(int)); 26162 sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26163 26164 #ifdef BCM_TRX_SUPPORT 26165 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 26166 /* Get group base pointer. */ 26167 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 26168 idx = ecmp_idx; 26169 } else { 26170 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 26171 idx = ecmp_idx; 26172 } else { 26173 idx = ecmp_idx * BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26174 } 26175 } 26176 26177 /* Read zero based ecmp count. */ 26178 rv = soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, idx, hw_buf); 26179 if (BCM_FAILURE(rv)) { 26180 return rv; 26181 } 26182 26183 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_COUNTm)) { 26184 rv = soc_mem_read(unit, INITIAL_L3_ECMP_COUNTm, MEM_BLOCK_ANY, idx, hw_buf); 26185 BCM_IF_ERROR_RETURN(rv); 26186 } 26187 else if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_GROUPm)) { 26188 rv = soc_mem_read(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ANY, idx, hw_buf); 26189 BCM_IF_ERROR_RETURN(rv); 26190 } 26191 26192 max_ent_count = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, COUNTf); 26193 if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 26194 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) == 0) { 26195 ecmp_idx *= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26196 } 26197 } 26198 if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 26199 SOC_IS_GREYHOUND2(unit)) { 26200 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, BASE_PTRf); 26201 } 26202 max_ent_count++; /* Count is zero based. */ 26203 #ifdef BCM_TOMAHAWK3_SUPPORT 26204 if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) { 26205 lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit, 26206 hw_buf, LB_MODEf); 26207 switch(lb_mode) { 26208 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_256: 26209 max_ent_count = 256; 26210 break; 26211 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_512: 26212 max_ent_count = 512; 26213 break; 26214 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_1024: 26215 max_ent_count = 1024; 26216 break; 26217 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_2048: 26218 max_ent_count = 2048; 26219 break; 26220 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_4096: 26221 max_ent_count = 4096; 26222 break; 26223 default: 26224 break; 26225 } 26226 } 26227 #endif 26228 } else 26229 #endif /* BCM_TRX_SUPPORT */ 26230 { 26231 ecmp_idx *= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26232 /* Check number of entries to read. */ 26233 max_ent_count = (ecmp_count < BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) ? \ 26234 ecmp_count : BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26235 } 26236 26237 /* Read all the indexes from hw. */ 26238 for (idx = 0; idx < max_ent_count; idx++) { 26239 26240 /* Read next hop index. */ 26241 rv = soc_mem_read(unit, L3_ECMPm, MEM_BLOCK_ANY, 26242 (ecmp_idx + idx), hw_buf); 26243 if (rv < 0) { 26244 break; 26245 } 26246 nh_idx[idx] = soc_mem_field32_get(unit, L3_ECMPm, 26247 hw_buf, NEXT_HOP_INDEXf); 26248 /* Check if group contains . */ 26249 if (idx && (nh_idx[idx] != nh_idx[0])) { 26250 one_entry_grp = FALSE; 26251 } 26252 26253 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 26254 /* Next hops popuplated in cycle,stop once you read first entry again */ 26255 if (idx && (FALSE == one_entry_grp) && (nh_idx[idx] == nh_idx[0])) { 26256 nh_idx[idx] = 0; 26257 break; 26258 } 26259 } else { 26260 one_entry_grp = FALSE; 26261 } 26262 } 26263 /* Reset rest of the group if only 1 next hop is present. */ 26264 if (one_entry_grp) { 26265 sal_memset(nh_idx + 1, 0, (ecmp_count - 1) * sizeof(int)); 26266 } 26267 return rv; 26268 } 26269 26270 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT) 26271 /* 26272 * Function: 26273 * _bcm_xgs3_ecmp_grp_mem_set 26274 * Purpose: 26275 * helper function to write mem field for multi memory format 26276 */ 26277 STATIC void 26278 _bcm_xgs3_ecmp_grp_mem_set(int unit, const soc_mem_t* mem_array, int count, 26279 uint32** entry_array, 26280 soc_field_t field, uint32 value) 26281 { 26282 int i; 26283 26284 for (i = 0; i < count; i++) { 26285 if (SOC_MEM_IS_VALID(unit, mem_array[i]) && 26286 SOC_MEM_FIELD_VALID(unit, mem_array[i], field)) { 26287 soc_mem_field32_set(unit, mem_array[i], entry_array[i], 26288 field , value); 26289 } 26290 } 26291 } 26292 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT */ 26293 26294 #ifdef BCM_TRX_SUPPORT 26295 /* 26296 * Function: 26297 * _bcm_xgs3_ecmp_grp_mem_write 26298 * Purpose: 26299 * helper function to write entry into mem for multi memory format 26300 */ 26301 STATIC int 26302 _bcm_xgs3_ecmp_grp_mem_write(int unit, const soc_mem_t* mem_array, int count, 26303 uint32** entry_array, int index) 26304 { 26305 int i; 26306 26307 for (i = 0; i < count; i++) { 26308 if (SOC_MEM_IS_VALID(unit, mem_array[i])) { 26309 BCM_IF_ERROR_RETURN( 26310 soc_mem_write(unit, mem_array[i], MEM_BLOCK_ALL, 26311 index, entry_array[i])); 26312 } 26313 } 26314 26315 return BCM_E_NONE; 26316 } 26317 #endif /* BCM_TRX_SUPPORT */ 26318 26319 /* 26320 * Function: 26321 * _bcm_xgs3_ecmp_grp_add 26322 * Purpose: 26323 * Add ecmp group next hop members, or reset ecmp group entry. 26324 * NOTE: Function always writes all the entries in ecmp group. 26325 * If there is not enough nh indexes - next hops written 26326 * in cycle. 26327 * Parameters: 26328 * unit - (IN)SOC unit number. 26329 * ecmp_grp - (IN)ecmp group id to write. 26330 * buf - (IN)Next hop indexes or NULL for entry reset. 26331 * info - (IN)ECMP additional info 26332 * Returns: 26333 * BCM_E_XXX 26334 */ 26335 STATIC int 26336 _bcm_xgs3_ecmp_grp_add(int unit, int ecmp_grp, void *buf, void *info) 26337 { 26338 #ifdef BCM_TRX_SUPPORT 26339 uint32 l3_ecmp_count[SOC_MAX_MEM_FIELD_WORDS]; /* l3_ecmp_count buf */ 26340 #endif 26341 uint32 l3_ecmp[SOC_MAX_MEM_FIELD_WORDS]; /* l3_ecmp buf */ 26342 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT) ||\ 26343 defined(BCM_GREYHOUND_SUPPORT) 26344 uint32 hw_buf[3][SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry.*/ 26345 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT || BCM_GREYHOUND_SUPPORT */ 26346 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT) 26347 uint32* hw_buf_ptr[3]; 26348 const soc_mem_t l3_ecmp_count_mem[3] = {L3_ECMP_COUNTm, 26349 INITIAL_L3_ECMP_COUNTm, 26350 INITIAL_L3_ECMP_GROUPm}; 26351 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT */ 26352 int max_grp_size=0; /* Maximum ecmp group size.*/ 26353 int ecmp_idx; /* Ecmp table entry index. */ 26354 int *nh_idx; /* Ecmp group nh indexes. */ 26355 int nh_cycle_idx; /* NH cycle index. */ 26356 int idx=0; /* Iteration index. */ 26357 int rv = BCM_E_NONE; /* Operation return value. */ 26358 _bcm_l3_ecmp_group_info_t *ecmp_info = info; 26359 _bcm_l3_ecmp_group_buffer_t *ecmp_buffer = buf; 26360 #if defined(BCM_GREYHOUND_SUPPORT) 26361 _bcm_l3_tbl_op_t data; 26362 #endif 26363 #if defined(BCM_HURRICANE3_SUPPORT) 26364 uint32 reg_val, value; 26365 ing_l3_next_hop_entry_t ing_nh; 26366 int l3_ecmp_oif_flds[8] = { L3_OIF_0f, 26367 L3_OIF_1f, 26368 L3_OIF_2f, 26369 L3_OIF_3f, 26370 L3_OIF_4f, 26371 L3_OIF_5f, 26372 L3_OIF_6f, 26373 L3_OIF_7f }; 26374 #endif 26375 26376 /* Input parameters check. */ 26377 if (ecmp_buffer == NULL || ecmp_info == NULL || 26378 ecmp_buffer->group_buffer == NULL) { 26379 return (BCM_E_PARAM); 26380 } 26381 26382 /* Cast input buffer. */ 26383 nh_idx = ecmp_buffer->group_buffer; 26384 #ifdef BCM_TRX_SUPPORT 26385 if ((SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) && (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 26386 max_grp_size = ecmp_info->max_paths; 26387 ecmp_idx = ecmp_grp; 26388 } else 26389 #endif /* BCM_TRX_SUPPORT */ 26390 { 26391 max_grp_size = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26392 /* Calculate table index. */ 26393 ecmp_idx = ecmp_grp * BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26394 } 26395 26396 #if defined(BCM_GREYHOUND_SUPPORT) 26397 if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 26398 SOC_IS_GREYHOUND2(unit)) { 26399 max_grp_size = ecmp_info->max_paths; 26400 if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit,ecmp_grp), \ 26401 ecmp_grp)) { 26402 /* Group has already exists, get base ptr from group table */ 26403 sal_memset (hw_buf[0], 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26404 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 26405 MEM_BLOCK_ANY, ecmp_grp, hw_buf[0])); 26406 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 26407 hw_buf[0], BASE_PTRf); 26408 } else { 26409 /* Get index to the first slot in the ECMP table 26410 * that can accomodate max_grp_size */ 26411 data.width = ecmp_info->max_paths; 26412 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 26413 data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 26414 data.entry_index = -1; 26415 rv = _bcm_xgs3_tbl_free_idx_get(unit, &data); 26416 if (BCM_FAILURE(rv)) { 26417 return rv; 26418 } 26419 ecmp_idx = data.entry_index; 26420 BCM_XGS3_L3_ENT_REF_CNT_INC(data.tbl_ptr, data.entry_index, max_grp_size); 26421 } 26422 26423 if (ecmp_idx >= BCM_XGS3_L3_ECMP_TBL_SIZE(unit)) { 26424 return BCM_E_FULL; 26425 } 26426 } 26427 #endif /* BCM_GREYHOUND_SUPPORT */ 26428 26429 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT) 26430 sal_memset (hw_buf[0], 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26431 sal_memset (hw_buf[1], 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26432 sal_memset (hw_buf[2], 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26433 hw_buf_ptr[0] = hw_buf[0]; 26434 hw_buf_ptr[1] = hw_buf[1]; 26435 hw_buf_ptr[2] = hw_buf[2]; 26436 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT */ 26437 26438 /* Write all the indexes to hw. */ 26439 for (idx = 0, nh_cycle_idx = 0; idx < max_grp_size; idx++, nh_cycle_idx++) { 26440 26441 /* Set next hop index. */ 26442 sal_memset (l3_ecmp, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 26443 26444 /* If this is the last nhop then program black-hole. */ 26445 if ( (!idx) && (!nh_idx[nh_cycle_idx]) ) { 26446 nh_cycle_idx = 0; 26447 } else if (!nh_idx[nh_cycle_idx]) { 26448 /* If next hop index is not set start from the beginning. */ 26449 #ifdef BCM_TRX_SUPPORT 26450 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 26451 /* No entry replication is required. */ 26452 break; 26453 } 26454 #endif /* BCM_TRX_SUPPORT */ 26455 nh_cycle_idx = 0; 26456 } 26457 soc_mem_field32_set(unit, L3_ECMPm, l3_ecmp, NEXT_HOP_INDEXf, 26458 nh_idx[nh_cycle_idx]); 26459 /* Write buffer to hw. */ 26460 rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 26461 (ecmp_idx + idx), l3_ecmp); 26462 if (BCM_FAILURE(rv)) { 26463 break; 26464 } 26465 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 26466 defined(BCM_TRX_SUPPORT) 26467 /* Write initial ecmp table. */ 26468 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) { 26469 /* Write buffer to hw. */ 26470 rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 26471 (ecmp_idx + idx), l3_ecmp); 26472 if (BCM_FAILURE(rv)) { 26473 break; 26474 } 26475 } 26476 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 26477 26478 #ifdef BCM_HURRICANE3_SUPPORT 26479 if (soc_feature(unit, soc_feature_urpf)) { 26480 26481 /* Check if URPF is enabled on device */ 26482 BCM_IF_ERROR_RETURN( 26483 READ_L3_DEFIP_RPF_CONTROLr(unit, ®_val)); 26484 if (reg_val) { 26485 if (idx < 8) { 26486 BCM_IF_ERROR_RETURN (soc_mem_read(unit, 26487 ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 26488 nh_idx[idx], &ing_nh)); 26489 26490 value = soc_ING_L3_NEXT_HOPm_field32_get(unit, 26491 &ing_nh, L3_OIFf); 26492 26493 _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3, 26494 hw_buf_ptr, 26495 l3_ecmp_oif_flds[idx], value); 26496 _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3, 26497 hw_buf_ptr, 26498 URPF_COUNTf, idx); 26499 } else { 26500 /* Inorder to avoid TRAP_TO_CPU, urpf_mode on L3_IIF/PORT 26501 * must be set to STRICT_MODE / LOOSE_MODE 26502 */ 26503 _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3, 26504 hw_buf_ptr, 26505 ECMP_GT8f , 1); 26506 } 26507 } 26508 } 26509 #endif /* BCM_HURRICANE3_SUPPORT */ 26510 } 26511 26512 #ifdef BCM_TRX_SUPPORT 26513 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm) && BCM_SUCCESS(rv)) { 26514 int ecmp_count_idx; 26515 if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 26516 SOC_IS_GREYHOUND2(unit)) { 26517 ecmp_count_idx = ecmp_grp; 26518 } else { 26519 ecmp_count_idx = ecmp_idx; 26520 } 26521 26522 if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 26523 /* Set Max Group Size. */ 26524 sal_memset (l3_ecmp_count, 0, 26525 SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 26526 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, 26527 COUNTf, max_grp_size - 1); 26528 26529 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 26530 (ecmp_count_idx+1), l3_ecmp_count); 26531 BCM_IF_ERROR_RETURN(rv); 26532 } 26533 /* Set zero based ecmp count. */ 26534 if (!idx) { 26535 _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3, 26536 hw_buf_ptr, COUNTf, idx); 26537 } else { 26538 _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3, 26539 hw_buf_ptr, COUNTf, idx - 1); 26540 } 26541 26542 /* Set group base pointer. */ 26543 _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3, 26544 hw_buf_ptr, BASE_PTRf, ecmp_idx); 26545 26546 /* write memory */ 26547 BCM_IF_ERROR_RETURN( 26548 _bcm_xgs3_ecmp_grp_mem_write( 26549 unit, l3_ecmp_count_mem, 3, 26550 hw_buf_ptr, ecmp_count_idx)); 26551 26552 #ifdef BCM_TRIUMPH2_SUPPORT 26553 /* mode 1 = max possible ecmp groups */ 26554 if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 26555 /* Save the max possible paths for this ECMP group in s/w */ 26556 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = ecmp_info->max_paths; 26557 } 26558 #endif 26559 } 26560 #endif /* BCM_TRX_SUPPORT */ 26561 return rv; 26562 } 26563 26564 26565 /* 26566 * Function: 26567 * _bcm_xgs3_ecmp_grp_del 26568 * Purpose: 26569 * Reset ecmp group next hop members 26570 * Parameters: 26571 * unit - (IN)SOC unit number. 26572 * ecmp_grp - (IN)ecmp group id to write. 26573 * info - (IN)ECMP additional info 26574 * Returns: 26575 * BCM_E_XXX 26576 */ 26577 STATIC int 26578 _bcm_xgs3_ecmp_grp_del(int unit, int ecmp_grp, void *info) 26579 { 26580 uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry.*/ 26581 int ecmp_idx; /* Ecmp table entry index. */ 26582 int idx; /* Iteration index. */ 26583 int rv = BCM_E_UNAVAIL; /* Operation return value. */ 26584 int max_grp_size=0; /* Maximum ecmp group size.*/ 26585 #if defined(BCM_GREYHOUND_SUPPORT) 26586 _bcm_l3_tbl_op_t data; 26587 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 26588 #endif /* BCM_GREYHOUND_SUPPORT */ 26589 26590 /* Initialize ecmp entry. */ 26591 sal_memset (hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26592 26593 /* Calculate table index. */ 26594 #ifdef BCM_TRX_SUPPORT 26595 if ((SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) && (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))){ 26596 if (info == NULL) { 26597 return BCM_E_INTERNAL; 26598 } 26599 max_grp_size = ((_bcm_l3_ecmp_group_info_t*)info)->max_paths; 26600 ecmp_idx = ecmp_grp; 26601 } else 26602 #endif 26603 { 26604 max_grp_size = BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26605 ecmp_idx = ecmp_grp * BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 26606 } 26607 #if defined(BCM_GREYHOUND_SUPPORT) 26608 26609 if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 26610 SOC_IS_GREYHOUND2(unit)) { 26611 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 26612 MEM_BLOCK_ANY, ecmp_grp, hw_buf)); 26613 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, \ 26614 hw_buf, BASE_PTRf); 26615 26616 } 26617 /* clear the buffer */ 26618 sal_memset (hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 26619 #endif /* BCM_GREYHOUND_SUPPORT */ 26620 26621 /* Write all the indexes to hw. */ 26622 for (idx = 0; idx < max_grp_size; idx++) { 26623 /* Write buffer to hw. */ 26624 rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 26625 (ecmp_idx + idx), hw_buf); 26626 26627 if (BCM_FAILURE(rv)) { 26628 return rv; 26629 } 26630 26631 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 26632 defined(BCM_TRX_SUPPORT) 26633 /* Write initial ecmp table. */ 26634 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) { 26635 /* Write buffer to hw. */ 26636 rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 26637 (ecmp_idx + idx), hw_buf); 26638 if (BCM_FAILURE(rv)) { 26639 return rv; 26640 } 26641 } 26642 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 26643 } 26644 26645 26646 #if defined(BCM_GREYHOUND_SUPPORT) 26647 /* Decrement ref count for the entries in ecmp table 26648 * Ref count for ecmp_group table is decremented in common table del func. */ 26649 BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, ecmp_idx, max_grp_size); 26650 #endif /* BCM_GREYHOUND_SUPPORT */ 26651 26652 #ifdef BCM_TRX_SUPPORT 26653 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 26654 /* Set group base pointer. */ 26655 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 26656 ecmp_idx = ecmp_grp; 26657 } 26658 26659 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 26660 ecmp_idx, hw_buf); 26661 BCM_IF_ERROR_RETURN(rv); 26662 26663 if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 26664 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 26665 (ecmp_idx+1), hw_buf); 26666 BCM_IF_ERROR_RETURN(rv); 26667 } 26668 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_COUNTm)) { 26669 rv = soc_mem_write(unit, INITIAL_L3_ECMP_COUNTm, MEM_BLOCK_ALL, 26670 ecmp_idx, hw_buf); 26671 } 26672 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_GROUPm)) { 26673 rv = soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL, 26674 ecmp_idx, hw_buf); 26675 } 26676 26677 #ifdef BCM_TRIUMPH2_SUPPORT 26678 if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 26679 /* Reset the max paths of the deleted group */ 26680 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = 0; 26681 } 26682 #endif 26683 } 26684 #endif /* BCM_TRX_SUPPORT */ 26685 26686 return rv; 26687 } 26688 26689 /* 26690 * Function: 26691 * _bcm_xgs3_l3_tnl_term_entry_parse 26692 * Purpose: 26693 * Parse tunnel terminator entry portion. 26694 * Parameters: 26695 * unit - (IN) BCM device number. 26696 * entry - (IN) SOC buffer with tunne information. 26697 * tnl_info - (OUT) BCM buffer with tunnel info. 26698 * Returns: 26699 * BCM_E_XXX 26700 */ 26701 STATIC int 26702 _bcm_xgs3_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry, 26703 bcm_tunnel_terminator_t *tnl_info) 26704 { 26705 _bcm_tnl_term_type_t tnl_type; /* Tunnel type information. */ 26706 uint32 *entry_ptr; /* Filled entry pointer. */ 26707 soc_field_t vrf_fld = INVALIDf; /* Vrf id field if supported. */ 26708 26709 /* Input parameters check. */ 26710 if ((NULL == tnl_info) || (NULL == entry)) { 26711 return (BCM_E_PARAM); 26712 } 26713 26714 /* Reset destination structure. */ 26715 bcm_tunnel_terminator_t_init(tnl_info); 26716 sal_memset(&tnl_type, 0, sizeof(_bcm_tnl_term_type_t)); 26717 26718 entry_ptr = (uint32 *)&entry->entry_arr[0]; 26719 26720 /* Get valid bit. */ 26721 if (!soc_L3_TUNNELm_field32_get(unit, entry_ptr, VALIDf)) { 26722 return (BCM_E_NOT_FOUND); 26723 } 26724 26725 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, MODEf)) { 26726 tnl_type.tnl_outer_hdr_ipv6 = 26727 soc_L3_TUNNELm_field32_get(unit, entry_ptr, MODEf); 26728 } else if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, KEY_TYPEf)) { 26729 tnl_type.tnl_outer_hdr_ipv6 = 26730 soc_L3_TUNNELm_field32_get(unit, entry_ptr, KEY_TYPEf); 26731 } 26732 26733 26734 /* Get Destination/Source pair. */ 26735 if (tnl_type.tnl_outer_hdr_ipv6) { 26736 #if defined(BCM_TRX_SUPPORT) 26737 /* SIP [0-63] */ 26738 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26739 (uint32 *)&entry->entry_arr[0], IP_ADDRf, 26740 tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY); 26741 /* SIP [64-127] */ 26742 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26743 (uint32 *)&entry->entry_arr[1], IP_ADDRf, 26744 tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY); 26745 /* DIP [0-63] */ 26746 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26747 (uint32 *)&entry->entry_arr[2], IP_ADDRf, 26748 tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY); 26749 /* DIP [64-127] */ 26750 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26751 (uint32 *)&entry->entry_arr[3], IP_ADDRf, 26752 tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY); 26753 26754 /* SIP MASK [0-63] */ 26755 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26756 (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf, 26757 tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY); 26758 /* SIP MASK [64-127] */ 26759 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26760 (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf, 26761 tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY); 26762 /* DIP MASK [0-63] */ 26763 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26764 (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf, 26765 tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY); 26766 /* DIP MASK [64-127] */ 26767 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 26768 (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf, 26769 tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY); 26770 #endif /* BCM_TRX_SUPPORT */ 26771 26772 } else { 26773 /* Get destination ip. */ 26774 tnl_info->dip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, DIPf); 26775 26776 /* Get source ip. */ 26777 tnl_info->sip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, SIPf); 26778 26779 /* Destination subnet mask. */ 26780 tnl_info->dip_mask = BCM_XGS3_L3_IP4_FULL_MASK; 26781 26782 /* Source subnet mask. */ 26783 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, SIP_MASKf)) { 26784 tnl_info->sip_mask = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 26785 SIP_MASKf); 26786 } else { 26787 tnl_info->sip_mask = (tnl_info->sip == 0) ? 0x0 : 26788 BCM_XGS3_L3_IP4_FULL_MASK; 26789 } 26790 } 26791 26792 /* Get tunnel subtype. */ 26793 tnl_type.tnl_sub_type = 26794 soc_L3_TUNNELm_field32_get(unit, entry_ptr, SUB_TUNNEL_TYPEf); 26795 26796 /* Get tunnel type. */ 26797 tnl_type.tnl_auto = 26798 soc_L3_TUNNELm_field32_get(unit, entry_ptr, TUNNEL_TYPEf); 26799 26800 /* Copy DSCP from outer header flag. */ 26801 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_DSCPf)) { 26802 tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_DSCP; 26803 } 26804 /* Copy TTL from outer header flag. */ 26805 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_TTLf)) { 26806 tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_TTL; 26807 } 26808 /* Keep inner header DSCP flag. */ 26809 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, 26810 DONOT_CHANGE_INNER_HDR_DSCPf)) { 26811 tnl_info->flags |= BCM_TUNNEL_TERM_KEEP_INNER_DSCP; 26812 } 26813 26814 soc_mem_pbmp_field_get(unit, L3_TUNNELm, entry_ptr, ALLOWED_PORT_BITMAPf, 26815 &tnl_info->pbmp); 26816 26817 /* IPMC lokup vlan id.. */ 26818 if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, IINTFf)) { 26819 tnl_info->vlan = soc_L3_TUNNELm_field32_get(unit, entry_ptr, IINTFf); 26820 } 26821 /* Get Tunnel class id for VFP match */ 26822 if (SOC_IS_SCORPION(unit)) { 26823 if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, CLASS_IDf)) { 26824 tnl_info->tunnel_class = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 26825 CLASS_IDf); 26826 } 26827 } else { 26828 if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_CLASS_IDf)) { 26829 tnl_info->tunnel_class = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 26830 TUNNEL_CLASS_IDf); 26831 } 26832 } 26833 26834 #ifdef BCM_FIREBOLT_SUPPORT 26835 if (SOC_IS_FBX(unit)) { 26836 #if defined (BCM_RAVEN_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT) || \ 26837 defined (BCM_SCORPION_SUPPORT) 26838 /* Set vrf id field. */ 26839 vrf_fld = TUNNEL_VRF_IDf; 26840 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT */ 26841 26842 /* Get trust dscp per tunnel */ 26843 if (soc_feature(unit, soc_feature_tunnel_dscp_trust)) { 26844 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_TUNNEL_DSCPf)) { 26845 tnl_info->flags |= BCM_TUNNEL_TERM_DSCP_TRUST; 26846 } 26847 } 26848 #ifdef BCM_TRX_SUPPORT 26849 /* Get gre tunnel indicator. */ 26850 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_TUNNELf)){ 26851 tnl_type.tnl_gre = 26852 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_TUNNELf); 26853 } 26854 26855 /* Get gre IPv4 payload allowed. */ 26856 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_PAYLOAD_IPV4f)){ 26857 tnl_type.tnl_gre_v4_payload = 26858 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV4f); 26859 } 26860 26861 /* Get gre IPv6 payload allowed. */ 26862 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_PAYLOAD_IPV6f)){ 26863 tnl_type.tnl_gre_v6_payload = 26864 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV6f); 26865 } 26866 #endif /* BCM_TRX_SUPPORT */ 26867 } 26868 #endif /* BCM_FIREBOLT_SUPPORT */ 26869 /* Get tunnel type & sub_type. */ 26870 BCM_IF_ERROR_RETURN 26871 (_bcm_xgs3_l3_get_tnl_term_type(unit, tnl_info, &tnl_type)); 26872 26873 /* Get vrf id. */ 26874 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, vrf_fld)){ 26875 tnl_info->vrf = soc_L3_TUNNELm_field32_get(unit, entry_ptr, vrf_fld); 26876 } else { 26877 tnl_info->vrf = BCM_L3_VRF_DEFAULT; 26878 } 26879 26880 return (BCM_E_NONE); 26881 } 26882 26883 /* 26884 * Function: 26885 * _bcm_xgs3_l3_tnl_term_get 26886 * Purpose: 26887 * Get a tunnel terminator for DIP-SIP/ for ER UDP dst/src port. 26888 * Parameters: 26889 * unit -(IN)SOC unit number. 26890 * tnl_info -(IN)Buffer to fill tunnel info. 26891 * Returns: 26892 * BCM_E_XXX 26893 */ 26894 STATIC int 26895 _bcm_xgs3_l3_tnl_term_get(int unit, bcm_tunnel_terminator_t *tnl_info) 26896 { 26897 soc_tunnel_term_t key; /* Buffer to fill lookup key. */ 26898 soc_tunnel_term_t entry; /* Buffer to read entry from hw. */ 26899 int index; 26900 26901 /* Initialize lookup key. */ 26902 #ifdef BCM_TOMAHAWK3_SUPPORT 26903 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 26904 BCM_IF_ERROR_RETURN 26905 (_bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &key)); 26906 } else 26907 #endif 26908 #ifdef BCM_TRIUMPH2_SUPPORT 26909 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 26910 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 26911 SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) || 26912 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 26913 BCM_IF_ERROR_RETURN 26914 (_bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &key)); 26915 } else 26916 #endif /* BCM_TRIUMPH2_SUPPORT */ 26917 #if defined(BCM_TRIUMPH3_SUPPORT) 26918 if (SOC_IS_TRIUMPH3(unit)) { 26919 BCM_IF_ERROR_RETURN 26920 (_bcm_tr3_l3_tnl_term_entry_init(unit, tnl_info, &key)); 26921 } else 26922 #endif /* BCM_TRIUMPH3_SUPPORT */ 26923 if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 26924 BCM_IF_ERROR_RETURN 26925 (_bcm_xgs3_l3_tnl_term_entry_init(unit, tnl_info, &key)); 26926 } 26927 26928 /* Find tunnel terminator in TCAM. */ 26929 BCM_IF_ERROR_RETURN(soc_tunnel_term_match(unit,&key, &entry, &index)); 26930 26931 /* Parse lookup result. */ 26932 #ifdef BCM_TOMAHAWK3_SUPPORT 26933 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 26934 BCM_IF_ERROR_RETURN 26935 (_bcm_th3_l3_tnl_term_entry_parse(unit, &entry, tnl_info)); 26936 } else 26937 #endif 26938 #ifdef BCM_TRIUMPH2_SUPPORT 26939 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 26940 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 26941 SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) || 26942 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 26943 BCM_IF_ERROR_RETURN 26944 (_bcm_tr2_l3_tnl_term_entry_parse(unit, &entry, tnl_info)); 26945 } else 26946 #endif 26947 26948 #if defined(BCM_TRIUMPH3_SUPPORT) 26949 if (SOC_IS_TRIUMPH3(unit)) { 26950 BCM_IF_ERROR_RETURN 26951 (_bcm_tr3_l3_tnl_term_entry_parse(unit, &entry, tnl_info)); 26952 } else 26953 #endif 26954 26955 { 26956 BCM_IF_ERROR_RETURN 26957 (_bcm_xgs3_l3_tnl_term_entry_parse(unit, &entry, tnl_info)); 26958 } 26959 26960 return (BCM_E_NONE); 26961 } 26962 26963 26964 #ifdef BCM_TOMAHAWK3_SUPPORT 26965 STATIC int 26966 _bcm_xgs3_l3_tnl_term_hash_entry_add(int unit, bcm_tunnel_terminator_t *tnl_info, uint32 *entry_ptr) 26967 { 26968 int bit_num = 0; 26969 int tmp_val; /* Temp value to check flags. */ 26970 soc_mem_t mem = L3_TUNNEL_DOUBLEm; 26971 void *profile_entry_ptr; 26972 uint32 prof_id; 26973 allowed_port_bitmap_profile_entry_t allowed_ports_profile; 26974 _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */ 26975 26976 /* Get tunnel type & sub_type. */ 26977 BCM_IF_ERROR_RETURN 26978 (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type)); 26979 26980 if (tnl_type.tnl_outer_hdr_ipv6 == 1) { 26981 mem = L3_TUNNEL_QUADm; 26982 } 26983 26984 if (tnl_info->flags & BCM_TUNNEL_REPLACE) { 26985 int rv = BCM_E_NONE; /* Operation return status. */ 26986 soc_tunnel_term_t key; /* Buffer to read entry from hw. */ 26987 soc_tunnel_term_t entry; 26988 int index; 26989 int prof_id; 26990 uint32 *entry_ptr_existing; 26991 26992 rv = _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &key); 26993 /* Find tunnel terminator. */ 26994 if (BCM_SUCCESS(rv)) { 26995 rv = soc_tunnel_term_match(unit,&key, &entry, &index); 26996 } 26997 entry_ptr_existing = (uint32 *)&entry.entry_arr[0]; 26998 if (BCM_SUCCESS(rv)) { 26999 prof_id = soc_mem_field32_get(unit, mem, entry_ptr_existing, 27000 (mem == L3_TUNNEL_DOUBLEm) ? 27001 IPV4__ALLOWED_PORT_BITMAP_PROFILE_PTRf: 27002 IPV6__ALLOWED_PORT_BITMAP_PROFILE_PTRf); 27003 soc_profile_mem_delete(unit, _bcm_get_tnl_port_bitmap_profile(unit), prof_id); 27004 } 27005 } 27006 27007 tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_DSCP) ? 1 : 0; 27008 soc_mem_field32_set(unit, mem, entry_ptr, 27009 (mem == L3_TUNNEL_DOUBLEm) ? IPV4__USE_OUTER_HDR_DSCPf : IPV6__USE_OUTER_HDR_DSCPf, tmp_val); 27010 27011 /* Set flag to use outer header TTL value or not. */ 27012 tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_TTL) ? 1 : 0; 27013 soc_mem_field32_set(unit, mem, entry_ptr, 27014 (mem == L3_TUNNEL_DOUBLEm) ? IPV4__USE_OUTER_HDR_TTLf:IPV6__USE_OUTER_HDR_TTLf, tmp_val); 27015 27016 /* Set flag to preserve inner header DSCP value or not. */ 27017 tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_KEEP_INNER_DSCP) ? 1 : 0; 27018 soc_mem_field32_set(unit, mem, entry_ptr, 27019 (mem == L3_TUNNEL_DOUBLEm) ? IPV4__DONOT_CHANGE_INNER_HDR_DSCPf : IPV6__DONOT_CHANGE_INNER_HDR_DSCPf, 27020 tmp_val); 27021 27022 profile_entry_ptr = &allowed_ports_profile; 27023 soc_mem_pbmp_field_set(unit, ALLOWED_PORT_BITMAP_PROFILEm, profile_entry_ptr, ING_PORT_BITMAPf, 27024 &tnl_info->pbmp); 27025 BCM_IF_ERROR_RETURN( 27026 soc_profile_mem_add(unit, _bcm_get_tnl_port_bitmap_profile(unit), 27027 &profile_entry_ptr, 1, &prof_id)); 27028 soc_mem_field32_set(unit, mem, entry_ptr, (mem == L3_TUNNEL_DOUBLEm) ? 27029 IPV4__ALLOWED_PORT_BITMAP_PROFILE_PTRf: 27030 IPV6__ALLOWED_PORT_BITMAP_PROFILE_PTRf, prof_id); 27031 27032 /* Sev vlan id for ipmc lookup.*/ 27033 if(SOC_MEM_FIELD_VALID(unit, mem, IPV4__IINTFf) || 27034 SOC_MEM_FIELD_VALID(unit, mem, IPV6__IINTFf)) { 27035 soc_mem_field32_set(unit, mem, entry_ptr, (mem == L3_TUNNEL_DOUBLEm) ? IPV4__IINTFf : IPV6__IINTFf, tnl_info->vlan); 27036 } 27037 27038 /* Set Tunnel class id for VFP match. */ 27039 bit_num = soc_mem_field_length(unit, mem, (mem == L3_TUNNEL_DOUBLEm) ? IPV4__TUNNEL_CLASS_IDf : IPV6__TUNNEL_CLASS_IDf); 27040 if (bit_num) { 27041 if ((tnl_info->tunnel_class < 0) || 27042 (tnl_info->tunnel_class > (( 1 << bit_num ) - 1))) { 27043 return BCM_E_PARAM; 27044 } 27045 soc_mem_field32_set(unit, mem, entry_ptr, 27046 (mem == L3_TUNNEL_DOUBLEm) ? IPV4__TUNNEL_CLASS_IDf : IPV6__TUNNEL_CLASS_IDf, 27047 tnl_info->tunnel_class); 27048 } else { 27049 if (tnl_info->tunnel_class != 0) { 27050 return BCM_E_PARAM; 27051 } 27052 } 27053 return BCM_E_NONE; 27054 } 27055 #endif 27056 27057 /* 27058 * Function: 27059 * _bcm_xgs3_l3_tnl_term_add 27060 * Purpose: 27061 * Add tunnel termination entry to the hw. 27062 * Parameters: 27063 * unit - (IN)SOC unit number. 27064 * tnl_info - (IN)Tunnel terminator parameters. 27065 * Returns: 27066 * BCM_E_XXX 27067 */ 27068 STATIC int 27069 _bcm_xgs3_l3_tnl_term_add(int unit, bcm_tunnel_terminator_t *tnl_info) 27070 { 27071 soc_tunnel_term_t entry; /* Buffer to writh to hw. */ 27072 uint32 *entry_ptr; /* Filled entry pointer. */ 27073 int tmp_val; /* Temp value to check flags. */ 27074 uint32 index; /* HW index. */ 27075 int rv = BCM_E_NONE; /* Operation return status. */ 27076 int bit_num = 0; 27077 soc_mem_t mem = L3_TUNNELm; 27078 27079 27080 #if defined(BCM_TOMAHAWK3_SUPPORT) 27081 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27082 _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */ 27083 mem = L3_TUNNEL_DOUBLEm; 27084 if ((tnl_info->type == bcmTunnelTypeAutoMulticast) || 27085 (tnl_info->type == bcmTunnelTypeAutoMulticast6)) { 27086 /* AMT tunnels not supported */ 27087 return BCM_E_UNAVAIL; 27088 } 27089 27090 27091 /* Get tunnel type & sub_type. */ 27092 BCM_IF_ERROR_RETURN 27093 (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type)); 27094 27095 if (tnl_type.tnl_protocol == 0x11) { 27096 /*UDP not supported */ 27097 return BCM_E_UNAVAIL; 27098 } 27099 27100 if (tnl_type.tnl_outer_hdr_ipv6 == 1) { 27101 mem = L3_TUNNEL_QUADm; 27102 } 27103 27104 rv = _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &entry); 27105 } else 27106 #endif 27107 /* Initialize lookup key. */ 27108 #ifdef BCM_TRIUMPH2_SUPPORT 27109 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 27110 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 27111 SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) || 27112 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 27113 rv = _bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &entry); 27114 } else 27115 #endif /* BCM_TRIUMPH2_SUPPORT */ 27116 #if defined(BCM_TRIUMPH3_SUPPORT) 27117 if (SOC_IS_TRIUMPH3(unit)) { 27118 rv = _bcm_tr3_l3_tnl_term_entry_init(unit, tnl_info, &entry); 27119 } else 27120 #endif /* BCM_TRIUMPH3_SUPPORT */ 27121 { 27122 rv = _bcm_xgs3_l3_tnl_term_entry_init(unit, tnl_info, &entry); 27123 } 27124 BCM_IF_ERROR_RETURN(rv); 27125 27126 entry_ptr = (uint32 *)&entry.entry_arr[0]; 27127 27128 27129 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27130 #ifdef BCM_TOMAHAWK3_SUPPORT 27131 BCM_IF_ERROR_RETURN( 27132 _bcm_xgs3_l3_tnl_term_hash_entry_add(unit, tnl_info, entry_ptr)); 27133 #endif 27134 } else { 27135 /* Set flag to use outer header DSCP value or not. */ 27136 tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_DSCP) ? 1 : 0; 27137 soc_mem_field32_set(unit, mem, entry_ptr, USE_OUTER_HDR_DSCPf, tmp_val); 27138 27139 /* Set flag to use outer header TTL value or not. */ 27140 tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_TTL) ? 1 : 0; 27141 soc_mem_field32_set(unit, mem, entry_ptr, USE_OUTER_HDR_TTLf, tmp_val); 27142 27143 /* Set flag to preserve inner header DSCP value or not. */ 27144 tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_KEEP_INNER_DSCP) ? 1 : 0; 27145 soc_mem_field32_set(unit, mem, entry_ptr, 27146 DONOT_CHANGE_INNER_HDR_DSCPf, tmp_val); 27147 27148 /* Set l3 port bitmap. */ 27149 soc_mem_pbmp_field_set(unit, mem, entry_ptr, ALLOWED_PORT_BITMAPf, 27150 &tnl_info->pbmp); 27151 27152 /* Sev vlan id for ipmc lookup.*/ 27153 if(SOC_MEM_FIELD_VALID(unit, mem, IINTFf)) { 27154 soc_mem_field32_set(unit, mem, entry_ptr, IINTFf, tnl_info->vlan); 27155 } 27156 27157 /* Set profile index for default forwarding vlan.*/ 27158 if(SOC_MEM_FIELD_VALID(unit, mem, DEFAULT_VLAN_PROFILE_INDEXf)) { 27159 soc_mem_field32_set(unit, mem, entry_ptr, DEFAULT_VLAN_PROFILE_INDEXf, tnl_info->fwd_vlan); 27160 } 27161 27162 /* Set Tunnel class id for VFP match. */ 27163 if (SOC_IS_SCORPION(unit)) { 27164 bit_num = soc_mem_field_length(unit, mem, CLASS_IDf); 27165 if (bit_num) { 27166 if ((tnl_info->tunnel_class < 0) || 27167 (tnl_info->tunnel_class > (( 1 << bit_num ) - 1))) { 27168 return BCM_E_PARAM; 27169 } 27170 soc_mem_field32_set(unit, mem, entry_ptr, CLASS_IDf, 27171 tnl_info->tunnel_class); 27172 } 27173 } else { 27174 bit_num = soc_mem_field_length(unit, mem, TUNNEL_CLASS_IDf); 27175 if (bit_num) { 27176 if ((tnl_info->tunnel_class < 0) || 27177 (tnl_info->tunnel_class > (( 1 << bit_num ) - 1))) { 27178 return BCM_E_PARAM; 27179 } 27180 soc_mem_field32_set(unit, mem, entry_ptr, TUNNEL_CLASS_IDf, 27181 tnl_info->tunnel_class); 27182 } else { 27183 if (tnl_info->tunnel_class != 0) { 27184 return BCM_E_PARAM; 27185 } 27186 } 27187 } 27188 27189 #ifdef BCM_FIREBOLT_SUPPORT 27190 if (SOC_IS_FBX(unit)) { 27191 if (soc_feature(unit, soc_feature_tunnel_dscp_trust)) { 27192 if (tnl_info->flags & BCM_TUNNEL_TERM_DSCP_TRUST) { 27193 soc_mem_field32_set(unit, mem, entry_ptr, USE_TUNNEL_DSCPf, 1); 27194 } 27195 } 27196 } 27197 #endif /* BCM_FIREBOLT_SUPPORT */ 27198 } 27199 27200 #ifdef BCM_TRIUMPH2_SUPPORT 27201 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 27202 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 27203 SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) || 27204 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 27205 #ifdef BCM_TOMAHAWK3_SUPPORT 27206 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27207 rv = _bcm_th3_l3_tnl_term_add(unit, entry_ptr, tnl_info); 27208 } else 27209 #endif 27210 { 27211 rv = _bcm_tr2_l3_tnl_term_add(unit, entry_ptr, tnl_info); 27212 } 27213 BCM_IF_ERROR_RETURN(rv); 27214 } 27215 #endif 27216 27217 #if defined(BCM_TRIUMPH3_SUPPORT) 27218 if (SOC_IS_TRIUMPH3(unit)) { 27219 rv = _bcm_tr3_l3_tnl_term_add(unit, entry_ptr, tnl_info); 27220 BCM_IF_ERROR_RETURN(rv); 27221 } 27222 #endif 27223 27224 rv = soc_tunnel_term_insert(unit, &entry, &index); 27225 return rv; 27226 } 27227 27228 /* 27229 * Function: 27230 * _bcm_xgs3_l3_tnl_term_del 27231 * Purpose: 27232 * Write a singe tunnel termination entry to the hw. 27233 * Parameters: 27234 * unit - (IN)SOC unit number. 27235 * tnl_info - (IN)Tunnel terminator parameters. 27236 * Returns: 27237 * BCM_E_XXX 27238 */ 27239 STATIC int 27240 _bcm_xgs3_l3_tnl_term_del(int unit, bcm_tunnel_terminator_t *tnl_info) 27241 { 27242 soc_tunnel_term_t key; /* Buffer to read entry from hw. */ 27243 int rv = BCM_E_NONE; /* Operation return status. */ 27244 #ifdef BCM_TOMAHAWK3_SUPPORT 27245 soc_tunnel_term_t entry; 27246 uint32 *entry_ptr; /* Filled entry pointer. */ 27247 int index; 27248 int prof_id; 27249 soc_mem_t mem = L3_TUNNEL_DOUBLEm; 27250 #endif 27251 /* Initialize lookup key. */ 27252 #ifdef BCM_TRIUMPH2_SUPPORT 27253 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 27254 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 27255 SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) || 27256 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 27257 #ifdef BCM_TOMAHAWK3_SUPPORT 27258 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27259 rv = _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &key); 27260 } else 27261 #endif 27262 { 27263 rv = _bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &key); 27264 } 27265 } else 27266 #endif /* BCM_TRIUMPH2_SUPPORT */ 27267 #if defined(BCM_TRIUMPH3_SUPPORT) 27268 if (SOC_IS_TRIUMPH3(unit)) { 27269 rv = _bcm_tr3_l3_tnl_term_entry_init(unit, tnl_info, &key); 27270 } else 27271 #endif /* BCM_TRIUMPH3_SUPPORT */ 27272 { 27273 if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27274 rv = _bcm_xgs3_l3_tnl_term_entry_init(unit, tnl_info, &key); 27275 } 27276 } 27277 BCM_IF_ERROR_RETURN(rv); 27278 27279 #ifdef BCM_TOMAHAWK3_SUPPORT 27280 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27281 _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */ 27282 27283 /* Get tunnel type & sub_type. */ 27284 BCM_IF_ERROR_RETURN 27285 (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type)); 27286 27287 if (tnl_type.tnl_outer_hdr_ipv6 == 1) { 27288 mem = L3_TUNNEL_QUADm; 27289 } 27290 27291 /* Find tunnel terminator in TCAM. */ 27292 rv = soc_tunnel_term_match(unit,&key, &entry, &index); 27293 entry_ptr = (uint32 *)&entry.entry_arr[0]; 27294 if (BCM_SUCCESS(rv)) { 27295 prof_id = soc_mem_field32_get(unit, mem, entry_ptr, 27296 (mem == L3_TUNNEL_DOUBLEm) ? 27297 IPV4__ALLOWED_PORT_BITMAP_PROFILE_PTRf: 27298 IPV6__ALLOWED_PORT_BITMAP_PROFILE_PTRf); 27299 soc_profile_mem_delete(unit, _bcm_get_tnl_port_bitmap_profile(unit), prof_id); 27300 } 27301 } 27302 #endif 27303 #ifdef BCM_TRIDENT3_SUPPORT 27304 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, DEFAULT_VLAN_PROFILE_INDEXf)) { 27305 tunnel_default_vlan_profile_entry_t tunnel_default_vlan_profile_entry; 27306 soc_tunnel_term_t entry; 27307 uint32 *entry_ptr; 27308 int index; 27309 27310 rv = soc_tunnel_term_match(unit,&key, &entry, &index); 27311 entry_ptr = (uint32 *)&entry.entry_arr[0]; 27312 if (BCM_SUCCESS(rv)) { 27313 uint32 action_profile_idx; 27314 uint32 vlan_profile_idx = soc_mem_field32_get(unit, L3_TUNNELm, entry_ptr, 27315 DEFAULT_VLAN_PROFILE_INDEXf); 27316 if (vlan_profile_idx) { 27317 BCM_IF_ERROR_RETURN( 27318 soc_mem_read(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, MEM_BLOCK_ANY, 27319 vlan_profile_idx, &tunnel_default_vlan_profile_entry)); 27320 27321 action_profile_idx = soc_mem_field32_get(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, 27322 (uint32 *) &tunnel_default_vlan_profile_entry, 27323 TAG_ACTION_PROFILE_PTRf); 27324 27325 /* delete action profile */ 27326 (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx)); 27327 27328 /* delete vlan profile */ 27329 soc_profile_mem_delete(unit, _bcm_td3_tunnel_default_vlan_profile[unit], vlan_profile_idx); 27330 } 27331 } 27332 } 27333 #endif 27334 /* Find tunnel terminator in TCAM. */ 27335 return soc_tunnel_term_delete(unit, &key); 27336 } 27337 27338 /* 27339 * Function: 27340 * _bcm_xgs3_l3_tnl_term_traverse 27341 * Purpose: 27342 * Traverse L3 tunnel terminator entries. 27343 * Parameters: 27344 * unit - (IN)SOC unit number. 27345 * tnl_info - (IN)Tunnel terminator parameters. 27346 * Returns: 27347 * BCM_E_XXX 27348 */ 27349 STATIC int 27350 _bcm_xgs3_l3_tnl_term_traverse(int unit, 27351 bcm_tunnel_terminator_traverse_cb cb, 27352 void *user_data) 27353 { 27354 int num_tnl, idx; 27355 soc_tunnel_term_t entry; 27356 int entry_type; 27357 bcm_tunnel_terminator_t info; 27358 int rv = BCM_E_NONE, width; 27359 soc_mem_t mem = L3_TUNNELm; 27360 soc_field_t valid_f = VALIDf; 27361 27362 /* Make sure module was initialized. */ 27363 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 27364 return (BCM_E_INIT); 27365 } 27366 27367 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27368 mem = L3_TUNNEL_DOUBLEm; 27369 valid_f = BASE_VALID_0f; 27370 } 27371 /* Get L3 tunnel terminator table size. */ 27372 num_tnl = soc_mem_index_count(unit, mem); 27373 27374 for(idx = num_tnl - 1; idx >= 0; idx--) { 27375 SOC_IF_ERROR_RETURN 27376 (soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, 27377 (uint32 *)&entry.entry_arr[0])); 27378 27379 if (!soc_mem_field32_get(unit, mem, 27380 (uint32 *)&entry.entry_arr[0], valid_f)) { 27381 continue; 27382 } 27383 27384 #if defined(BCM_TRX_SUPPORT) 27385 /* Get tunnel termination type IPv4/IPv6 */ 27386 if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) { 27387 entry_type = soc_mem_field32_get(unit, mem, 27388 (uint32 *)&entry.entry_arr[0], MODEf); 27389 } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) { 27390 entry_type = soc_mem_field32_get(unit, mem, 27391 (uint32 *)&entry.entry_arr[0], KEY_TYPEf); 27392 } else 27393 #endif /* BCM_TRX_SUPPORT */ 27394 { 27395 entry_type = 0; /* IPV4 default type */ 27396 } 27397 27398 if (0x1 == entry_type) { /* IPV6 */ 27399 if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27400 for (width = 1; width < SOC_TNL_TERM_IPV6_ENTRY_WIDTH; width++) { 27401 SOC_IF_ERROR_RETURN 27402 (READ_L3_TUNNELm(unit, MEM_BLOCK_ANY, (idx + width), 27403 (uint32 *)&entry.entry_arr[width])); 27404 } 27405 /* Skip IPv6 entry */ 27406 idx += (SOC_TNL_TERM_IPV6_ENTRY_WIDTH - 1); 27407 } 27408 } 27409 27410 /* tunnel terminator parse*/ 27411 #ifdef BCM_TOMAHAWK3_SUPPORT 27412 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 27413 rv = _bcm_th3_l3_tnl_term_entry_parse(unit, &entry, &info); 27414 } else 27415 #endif 27416 #ifdef BCM_TRIUMPH2_SUPPORT 27417 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 27418 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 27419 SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) || 27420 SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 27421 rv = _bcm_tr2_l3_tnl_term_entry_parse(unit, &entry, &info); 27422 } else 27423 #endif 27424 #if defined(BCM_TRIUMPH3_SUPPORT) 27425 if (SOC_IS_TRIUMPH3(unit)) { 27426 rv = _bcm_tr3_l3_tnl_term_entry_parse(unit, &entry, &info); 27427 } else 27428 #endif 27429 { 27430 rv = _bcm_xgs3_l3_tnl_term_entry_parse(unit, &entry, &info); 27431 } 27432 27433 /* Check read errors. */ 27434 if BCM_FAILURE(rv) { 27435 break; 27436 } 27437 27438 if (cb) { 27439 rv = (*cb) (unit, &info, user_data); 27440 #ifdef BCM_CB_ABORT_ON_ERR 27441 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 27442 break; 27443 } 27444 #endif 27445 } 27446 } 27447 27448 /* Reset last read status. */ 27449 if (BCM_E_NOT_FOUND == rv) { 27450 rv = BCM_E_NONE; 27451 } 27452 27453 return rv; 27454 } 27455 27456 /* 27457 * Function: 27458 * _bcm_xgs3_l3_tnl_init_get 27459 * Purpose: 27460 * Get a tunnel initiator entry. 27461 * Parameters: 27462 * unit -(IN)SOC unit number. 27463 * idx -(IN)Entry index to read. 27464 * tnl_info -(IN)Buffer to fill tunnel info. 27465 * Returns: 27466 * BCM_E_XXX 27467 */ 27468 STATIC int 27469 _bcm_xgs3_l3_tnl_init_get(int unit, int idx, 27470 bcm_tunnel_initiator_t *tnl_info) 27471 { 27472 uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry. */ 27473 soc_mem_t mem; /* Tunnel initiator table memory.*/ 27474 int df_val; /* Don't fragment encoded value. */ 27475 int rv; /* Operation return status. */ 27476 #ifdef BCM_FIREBOLT_SUPPORT 27477 int tnl_type; /* Tunnel type. */ 27478 #endif /* BCM_FIREBOLT_SUPPORT */ 27479 uint32 entry_type = BCM_XGS3_TUNNEL_INIT_V4;/* Entry type (IPv4/IPv6/MPLS)*/ 27480 soc_field_t field = 0; 27481 27482 /* Get table memory. */ 27483 mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4); 27484 27485 rv = BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry); 27486 BCM_IF_ERROR_RETURN(rv); 27487 27488 27489 if (SOC_IS_TRIDENT3X(unit)) { 27490 field = DATA_TYPEf; 27491 } else { 27492 field = ENTRY_TYPEf; 27493 } 27494 #if defined(BCM_TRX_SUPPORT) 27495 if (SOC_MEM_FIELD_VALID(unit, mem, field)) { 27496 /* Get entry_type. */ 27497 entry_type = soc_mem_field32_get(unit, mem, tnl_entry, field); 27498 #ifdef BCM_TRIDENT3_SUPPORT 27499 if (SOC_IS_TRIDENT3X(unit) && 27500 (entry_type == BCM_XGS3_TUNNEL_INIT_V6_TD3)) { 27501 entry_type = BCM_XGS3_TUNNEL_INIT_V6; 27502 } 27503 #endif 27504 27505 if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) { 27506 mem = BCM_XGS3_L3_MEM(unit, tnl_init_v6); 27507 idx >>= 1; /* Each record takes two slots. */ 27508 27509 rv = BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry); 27510 BCM_IF_ERROR_RETURN(rv); 27511 } else if ((BCM_XGS3_TUNNEL_INIT_MPLS == entry_type) 27512 #ifdef BCM_TRIDENT3_SUPPORT 27513 || (SOC_IS_TRIDENT3X(unit) && 27514 (BCM_XGS3_TUNNEL_INIT_MPLS_TD3 == entry_type)) 27515 #endif /* BCM_TRIDENT3_SUPPORT */ 27516 ) { 27517 mem = BCM_XGS3_L3_MEM(unit, tnl_init_mpls); 27518 if (soc_feature(unit, soc_feature_egr_ip_tnl_mpls_double_wide)) { 27519 idx >>= 1; /* Each record takes two slots. */ 27520 } 27521 rv = BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry); 27522 BCM_IF_ERROR_RETURN(rv); 27523 } 27524 } 27525 #endif /* BCM_TRX_SUPPORT */ 27526 27527 /* Parse hw buffer. */ 27528 if (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) { 27529 /* Get destination ip. */ 27530 tnl_info->dip = soc_mem_field32_get(unit, mem, tnl_entry, DIPf); 27531 27532 /* Get source ip. */ 27533 tnl_info->sip = soc_mem_field32_get(unit, mem, tnl_entry, SIPf); 27534 } else if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) { 27535 /* Get destination ip. */ 27536 soc_mem_ip6_addr_get(unit, mem, tnl_entry, DIPf, tnl_info->dip6, 27537 SOC_MEM_IP6_FULL_ADDR); 27538 27539 /* Get source ip. */ 27540 soc_mem_ip6_addr_get(unit, mem, tnl_entry, SIPf, tnl_info->sip6, 27541 SOC_MEM_IP6_FULL_ADDR); 27542 } 27543 27544 if ((entry_type != BCM_XGS3_TUNNEL_INIT_MPLS) 27545 #ifdef BCM_TRIDENT3_SUPPORT 27546 && (entry_type != BCM_XGS3_TUNNEL_INIT_MPLS_TD3) 27547 #endif /* BCM_TRIDENT3_SUPPORT */ 27548 ) { 27549 /* Tunnel header DSCP select. */ 27550 tnl_info->dscp_sel = soc_mem_field32_get(unit, mem, tnl_entry, DSCP_SELf); 27551 27552 /* Tunnel header DSCP value. */ 27553 if (bcmTunnelDscpAssign == tnl_info->dscp_sel) { 27554 tnl_info->dscp = soc_mem_field32_get(unit, mem, tnl_entry, DSCPf); 27555 } 27556 27557 /* Tunnel DSCP map */ 27558 if ((bcmTunnelDscpMap == tnl_info->dscp_sel) && 27559 SOC_MEM_FIELD_VALID(unit, mem, DSCP_MAPPING_PTRf)) { 27560 tnl_info->dscp_map = soc_mem_field32_get(unit, mem, tnl_entry, 27561 DSCP_MAPPING_PTRf); 27562 } 27563 } 27564 27565 if (SOC_MEM_FIELD_VALID(unit, mem, IPV4_DF_SELf)) { 27566 /* IP tunnel hdr DF bit for IPv4 */ 27567 df_val = soc_mem_field32_get(unit, mem, tnl_entry, IPV4_DF_SELf); 27568 if (0x2 <= df_val) { 27569 tnl_info->flags |= BCM_TUNNEL_INIT_USE_INNER_DF; 27570 } else if (0x1 == df_val) { 27571 tnl_info->flags |= BCM_TUNNEL_INIT_IPV4_SET_DF; 27572 } 27573 } 27574 27575 if (SOC_MEM_FIELD_VALID(unit, mem, IPV6_DF_SELf)) { 27576 /* IP tunnel hdr DF bit for IPv6 */ 27577 if (soc_mem_field32_get(unit, mem, tnl_entry, IPV6_DF_SELf)) { 27578 tnl_info->flags |= BCM_TUNNEL_INIT_IPV6_SET_DF; 27579 } 27580 } 27581 27582 #ifdef BCM_FIREBOLT_SUPPORT 27583 if(SOC_IS_FBX(unit)) { 27584 if ((BCM_XGS3_TUNNEL_INIT_MPLS == entry_type) 27585 #ifdef BCM_TRIDENT3_SUPPORT 27586 || (SOC_IS_TRIDENT3X(unit) && 27587 (BCM_XGS3_TUNNEL_INIT_MPLS_TD3 == entry_type)) 27588 #endif /* BCM_TRIDENT3_SUPPORT */ 27589 ) { 27590 27591 /* Get TTL. */ 27592 27593 #ifdef BCM_TRIDENT3_SUPPORT 27594 if (SOC_IS_TRIDENT3X(unit)) { 27595 int val = 0; 27596 /*Get TTL from MPLS_ENTRY_0*/ 27597 bcm_td3_ip_tnl_mpls_label_info_get(unit, tnl_entry, 27598 bcmiMplsTtl, 0, &val); 27599 tnl_info->ttl = val; 27600 } else 27601 #endif 27602 { 27603 tnl_info->ttl = soc_mem_field32_get(unit, mem, tnl_entry, MPLS_TTL_0f); 27604 } 27605 /* Get tunnel type. */ 27606 tnl_type = soc_mem_field32_get(unit, mem, tnl_entry, field); 27607 } else { 27608 /* Get TTL. */ 27609 if (SOC_MEM_FIELD_VALID(unit, mem, TTLf)) { 27610 tnl_info->ttl = soc_mem_field32_get(unit, mem, tnl_entry, TTLf); 27611 } 27612 27613 /* Get tunnel type. */ 27614 tnl_type = soc_mem_field32_get(unit, mem, tnl_entry, TUNNEL_TYPEf); 27615 } 27616 27617 /* Translate hw tunnel type into API encoding. */ 27618 rv = _bcm_xgs3_tnl_hw_code_to_type(unit, tnl_type, entry_type, 27619 &tnl_info->type); 27620 BCM_IF_ERROR_RETURN(rv); 27621 #if defined(BCM_TRX_SUPPORT) 27622 if (SOC_MEM_FIELD_VALID(unit, mem, FLOW_LABELf)) { 27623 tnl_info->flow_label = soc_mem_field32_get(unit, mem, tnl_entry, 27624 FLOW_LABELf); 27625 } 27626 #endif /* BCM_TRX_SUPPORT*/ 27627 27628 if (tnl_info->type != bcmTunnelTypeMpls) { 27629 /* Get mac address. */ 27630 if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDR_UPPERf)) { 27631 soc_mem_mac_address_get(unit, mem, tnl_entry, DEST_ADDR_UPPERf, 27632 tnl_info->dmac, SOC_MEM_MAC_UPPER_ONLY); 27633 soc_mem_mac_address_get(unit, mem, tnl_entry, DEST_ADDR_LOWERf, 27634 tnl_info->dmac, SOC_MEM_MAC_LOWER_ONLY); 27635 27636 } else { 27637 if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDRf)) { 27638 soc_mem_mac_addr_get(unit, mem, tnl_entry, 27639 DEST_ADDRf, tnl_info->dmac); 27640 } 27641 } 27642 } 27643 } 27644 #if defined BCM_TRIUMPH2_SUPPORT 27645 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 27646 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 27647 SOC_IS_TRIDENT2X(unit) || (!SOC_IS_TOMAHAWK3(unit) && SOC_IS_TOMAHAWKX(unit)) || 27648 SOC_IS_KATANAX(unit)) { 27649 int val; 27650 egr_fragment_id_table_entry_t entry; 27651 27652 rv = bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val); 27653 BCM_IF_ERROR_RETURN(rv); 27654 if (!val) { 27655 rv = soc_mem_read(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ANY, 27656 idx, &entry); 27657 BCM_IF_ERROR_RETURN(rv); 27658 tnl_info->ip4_id = soc_EGR_FRAGMENT_ID_TABLEm_field32_get 27659 (unit, &entry, FRAGMENT_IDf); 27660 } else { 27661 return BCM_E_CONFIG; 27662 } 27663 } 27664 #endif 27665 #ifdef BCM_TRIDENT2_SUPPORT 27666 if (SOC_MEM_FIELD_VALID(unit, mem, L4_DEST_PORTf)) { 27667 tnl_info->udp_dst_port = 27668 soc_mem_field32_get(unit, mem, tnl_entry, L4_DEST_PORTf); 27669 } 27670 #endif /* BCM_TRIDENT2_SUPPORT */ 27671 27672 #ifdef BCM_GREYHOUND2_SUPPORT 27673 if (SOC_MEM_FIELD_VALID(unit, mem, L4_DST_PORTf)) { 27674 tnl_info->udp_dst_port = 27675 soc_mem_field32_get(unit, mem, tnl_entry, L4_DST_PORTf); 27676 } 27677 #endif /* BCM_GREYHOUND2_SUPPORT */ 27678 #endif /* BCM_FIREBOLT_SUPPORT */ 27679 27680 #ifdef BCM_MONTEREY_SUPPORT 27681 if (SOC_MEM_FIELD_VALID(unit, mem, L4_SRC_PORTf)) { 27682 tnl_info->udp_src_port = 27683 soc_mem_field32_get(unit, mem, tnl_entry, L4_SRC_PORTf); 27684 } 27685 #endif /* BCM_MONTEREY_SUPPORT */ 27686 27687 return (BCM_E_NONE); 27688 } 27689 27690 /* 27691 * Function: 27692 * _bcm_xgs3_l3_tnl_init_add 27693 * Purpose: 27694 * Add tunnel initiator entry to hw. 27695 * Parameters: 27696 * unit - (IN)SOC unit number. 27697 * idx - (IN)Index to insert tunnel initiator index. 27698 * buf - (IN)Tunnel initiator entry info. 27699 * Returns: 27700 * BCM_E_XXX 27701 */ 27702 STATIC int 27703 _bcm_xgs3_l3_tnl_init_add(int unit, int idx, void *buf, void *info) 27704 { 27705 uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry.*/ 27706 bcm_tunnel_initiator_t *tnl_info; /* Tunnel initiator structure. */ 27707 soc_mem_t mem; /* Tunnel initiator table memory.*/ 27708 int df_val; /* Don't fragment encoding. */ 27709 int ipv6; /* IPv6 tunnel initiator. */ 27710 #ifdef BCM_FIREBOLT_SUPPORT 27711 int entry_type = 0; /* HW entry type IPv4/IPv6/MPLS */ 27712 int hw_type_code = 0; /* Tunnel type. */ 27713 #endif /* BCM_FIREBOLT_SUPPORT */ 27714 #if defined(BCM_TRX_SUPPORT) 27715 soc_field_t field = 0; 27716 if (SOC_IS_TRIDENT3X(unit)) { 27717 field = DATA_TYPEf; 27718 } else { 27719 field = ENTRY_TYPEf; 27720 } 27721 #endif 27722 27723 /* Input parameters check. */ 27724 if (NULL == buf) { 27725 return (BCM_E_PARAM); 27726 } 27727 27728 /* Read buffer from hw. */ 27729 tnl_info = (bcm_tunnel_initiator_t *) buf; 27730 27731 ipv6 = _BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type); 27732 27733 /* Get table memory. */ 27734 if (ipv6) { 27735 idx >>= 1; 27736 mem = BCM_XGS3_L3_MEM(unit, tnl_init_v6); 27737 } else { 27738 mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4); 27739 } 27740 27741 if (!SOC_MEM_IS_VALID(unit, mem)) { 27742 return (BCM_E_UNAVAIL); 27743 } 27744 27745 /* Zero write buffer. */ 27746 sal_memset(tnl_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, tnl_init_v6)); 27747 27748 if (ipv6) { 27749 /* Set destination ipv6 address. */ 27750 soc_mem_ip6_addr_set(unit, mem, tnl_entry, DIPf, tnl_info->dip6, 27751 SOC_MEM_IP6_FULL_ADDR); 27752 27753 /* Set source ipv6 address. */ 27754 soc_mem_ip6_addr_set(unit, mem, tnl_entry, SIPf, tnl_info->sip6, 27755 SOC_MEM_IP6_FULL_ADDR); 27756 } else { 27757 /* Set destination address. */ 27758 soc_mem_field_set(unit, mem, tnl_entry, DIPf, (uint32 *)&tnl_info->dip); 27759 27760 /* Set source address. */ 27761 soc_mem_field_set(unit, mem, tnl_entry, SIPf, (uint32 *)&tnl_info->sip); 27762 } 27763 27764 if ((!ipv6) && SOC_MEM_FIELD_VALID(unit, mem, IPV4_DF_SELf)) { 27765 /* Outer IPv4 tunnel hdr DF bit for Inner IPv4 hdr. */ 27766 df_val = 0; 27767 if (tnl_info->flags & BCM_TUNNEL_INIT_USE_INNER_DF) { 27768 df_val |= 0x2; 27769 } else if (tnl_info->flags & BCM_TUNNEL_INIT_IPV4_SET_DF) { 27770 df_val |= 0x1; 27771 } 27772 soc_mem_field32_set(unit, mem, tnl_entry, IPV4_DF_SELf, df_val); 27773 } 27774 27775 if ((!ipv6) && SOC_MEM_FIELD_VALID(unit, mem, IPV6_DF_SELf)) { 27776 /* Outer IPv4 tunnel hdr DF bit for Inner IPv6 hdr. */ 27777 df_val = (tnl_info->flags & BCM_TUNNEL_INIT_IPV6_SET_DF) ? 0x1 : 0; 27778 soc_mem_field32_set(unit, mem, tnl_entry, IPV6_DF_SELf, df_val); 27779 } 27780 27781 /* Set DSCP value. */ 27782 if (SOC_MEM_FIELD_VALID(unit, mem, DSCPf)) { 27783 soc_mem_field32_set(unit, mem, tnl_entry, DSCPf, tnl_info->dscp); 27784 } 27785 27786 /* Tunnel header DSCP select. */ 27787 soc_mem_field32_set(unit, mem, tnl_entry, DSCP_SELf, tnl_info->dscp_sel); 27788 27789 /* DSCP map */ 27790 if ((bcmTunnelDscpMap == tnl_info->dscp_sel) && 27791 (SOC_MEM_FIELD_VALID(unit, mem, DSCP_MAPPING_PTRf))) { 27792 soc_mem_field32_set(unit, mem, tnl_entry, DSCP_MAPPING_PTRf, 27793 tnl_info->dscp_map); 27794 } 27795 27796 #if defined(BCM_FIREBOLT_SUPPORT) 27797 if(SOC_IS_FBX(unit)) { 27798 /* Set TTL. */ 27799 if (SOC_MEM_FIELD_VALID(unit, mem, TTLf)) { 27800 soc_mem_field32_set(unit, mem, tnl_entry, TTLf, tnl_info->ttl); 27801 } 27802 27803 /* Set tunnel type. */ 27804 BCM_IF_ERROR_RETURN (_bcm_xgs3_tnl_type_to_hw_code(unit, tnl_info->type, 27805 &hw_type_code, 27806 &entry_type)); 27807 27808 soc_mem_field32_set(unit, mem, tnl_entry, TUNNEL_TYPEf, hw_type_code); 27809 27810 #if defined(BCM_TRX_SUPPORT) 27811 /* Set flow label. */ 27812 if (ipv6 && SOC_MEM_FIELD_VALID(unit, mem, FLOW_LABELf)) { 27813 soc_mem_field32_set(unit, mem, tnl_entry, FLOW_LABELf, 27814 tnl_info->flow_label); 27815 } 27816 27817 /* Set entry type. */ 27818 if (SOC_MEM_FIELD_VALID(unit, mem, field)) { 27819 soc_mem_field32_set(unit, mem, tnl_entry, field, entry_type); 27820 } 27821 #endif /* BCM_TRX_SUPPORT */ 27822 27823 /* Set destination mac address. */ 27824 if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDRf)) { 27825 soc_mem_mac_addr_set(unit, mem, &tnl_entry, DEST_ADDRf, tnl_info->dmac); 27826 } 27827 #if defined (BCM_SCORPION_SUPPORT) 27828 /* Set lower portion of destination mac address. */ 27829 if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDR_LOWERf)) { 27830 soc_mem_mac_address_set(unit, mem, &tnl_entry, DEST_ADDR_LOWERf, 27831 tnl_info->dmac, SOC_MEM_MAC_LOWER_ONLY); 27832 } 27833 27834 /* Set upper portion of destination mac address. */ 27835 if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDR_UPPERf)) { 27836 soc_mem_mac_address_set(unit, mem, &tnl_entry, DEST_ADDR_UPPERf, 27837 tnl_info->dmac, SOC_MEM_MAC_UPPER_ONLY); 27838 } 27839 #endif /* BCM_SCORPION_SUPPORT */ 27840 } 27841 #if defined(BCM_TRIUMPH2_SUPPORT) 27842 27843 /* Program the IPv4 ID if not using global ID space */ 27844 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 27845 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 27846 SOC_IS_TRIDENT2X(unit) || (SOC_IS_TOMAHAWKX(unit) && !SOC_IS_TOMAHAWK3(unit)) || 27847 SOC_IS_KATANAX(unit)) { 27848 int val; 27849 uint16 random; 27850 egr_fragment_id_table_entry_t entry; 27851 BCM_IF_ERROR_RETURN 27852 (bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val)); 27853 if (!val) { 27854 sal_memset(&entry, 0, sizeof(egr_fragment_id_table_entry_t)); 27855 if (tnl_info->flags & BCM_TUNNEL_INIT_IP4_ID_SET_FIXED) { 27856 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry, 27857 FRAGMENT_IDf, 27858 tnl_info->ip4_id); 27859 } else if (tnl_info->flags & BCM_TUNNEL_INIT_IP4_ID_SET_RANDOM) { 27860 random = (uint16) (sal_time_usecs() & 0xFFFF); 27861 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry, 27862 FRAGMENT_IDf, 27863 random); 27864 } else { 27865 /* Default is random */ 27866 random = (uint16) (sal_time_usecs() & 0xFFFF); 27867 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry, 27868 FRAGMENT_IDf, 27869 random); 27870 } 27871 BCM_IF_ERROR_RETURN 27872 (soc_mem_write(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ALL, 27873 idx, &entry)); 27874 } else { 27875 return BCM_E_CONFIG; 27876 } 27877 } 27878 #endif 27879 #endif /* BCM_FIREBOLT_SUPPORT */ 27880 27881 #ifdef BCM_MONTEREY_SUPPORT 27882 if ((tnl_info->type == bcmTunnelTypeRoeIn4) || 27883 (tnl_info->type == bcmTunnelTypeRoeIn6)) { 27884 soc_mem_field32_set(unit, mem, tnl_entry, L4_SRC_PORTf, 27885 tnl_info->udp_src_port); 27886 soc_mem_field32_set(unit, mem, tnl_entry, L4_DEST_PORTf, 27887 tnl_info->udp_dst_port); 27888 } 27889 #endif /* BCM_MONTEREY_SUPPORT */ 27890 27891 /* Write buffer to hw. */ 27892 return BCM_XGS3_MEM_WRITE(unit, mem, idx, tnl_entry); 27893 } 27894 27895 /* 27896 * Function: 27897 * _bcm_xgs3_l3_tnl_init_del 27898 * Purpose: 27899 * Delete tunnel initiator entry from hw. 27900 * Parameters: 27901 * unit - (IN)SOC unit number. 27902 * idx - (IN)Index to insert tunnel initiator index. 27903 * Returns: 27904 * BCM_E_XXX 27905 */ 27906 STATIC int 27907 _bcm_xgs3_l3_tnl_init_del(int unit, int idx, void *info) 27908 { 27909 uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry. */ 27910 soc_mem_t mem; /* Tunnel initiator memory. */ 27911 #if defined(BCM_TRX_SUPPORT) 27912 uint32 entry_type = BCM_XGS3_TUNNEL_INIT_V4;/* Entry type (IPv4/IPv6/MPLS)*/ 27913 int field = 0; 27914 27915 if (SOC_IS_TRIDENT3X(unit)) { 27916 field = DATA_TYPEf; 27917 } else { 27918 field = ENTRY_TYPEf; 27919 } 27920 #endif /* BCM_TRX_SUPPORT*/ 27921 27922 /* Get table memory. */ 27923 mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4); 27924 27925 #if defined(BCM_TRX_SUPPORT) 27926 if (SOC_MEM_FIELD_VALID(unit, mem, field)) { 27927 /* Parse hw buffer. */ 27928 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry)); 27929 27930 /* Get entry_type. */ 27931 entry_type = soc_mem_field32_get(unit, mem, tnl_entry, field); 27932 27933 if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) { 27934 mem = BCM_XGS3_L3_MEM(unit, tnl_init_v6); 27935 idx >>= 1; /* Each record takes two slots. */ 27936 } else if ((BCM_XGS3_TUNNEL_INIT_MPLS == entry_type) 27937 #ifdef BCM_TRIDENT3_SUPPORT 27938 || (SOC_IS_TRIDENT3(unit) && 27939 (BCM_XGS3_TUNNEL_INIT_MPLS_TD3 == entry_type)) 27940 #endif /* BCM_TRIDENT3_SUPPORT */ 27941 ) { 27942 mem = BCM_XGS3_L3_MEM(unit, tnl_init_mpls); 27943 if ((soc_feature(unit, soc_feature_egr_ip_tnl_mpls_double_wide)) 27944 || (soc_feature(unit, soc_feature_th3_style_simple_mpls))) { 27945 idx >>=1; 27946 } 27947 } 27948 } 27949 #endif /* BCM_TRX_SUPPORT */ 27950 /* Zero write buffer. */ 27951 sal_memset(&tnl_entry, 0, SOC_MAX_MEM_WORDS * sizeof(uint32)); 27952 27953 /* Write buffer to hw. */ 27954 return BCM_XGS3_MEM_WRITE(unit, mem, idx, &tnl_entry); 27955 } 27956 27957 27958 /* 27959 * Function: 27960 * _bcm_xgs3_l3_tnl_dscp_get 27961 * Purpose: 27962 * Get a tunnel dscp entry. 27963 * Parameters: 27964 * unit -(IN)SOC unit number. 27965 * idx -(IN)Entry index to read. 27966 * tnl_info -(IN)Buffer to fill tunnel info. 27967 * Returns: 27968 * BCM_E_XXX 27969 */ 27970 STATIC int 27971 _bcm_xgs3_l3_tnl_dscp_get(int unit, int idx, 27972 bcm_tunnel_dscp_map_t *tnl_info) 27973 { 27974 soc_mem_t mem; /* Tunnel dscp table memory.*/ 27975 uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry. */ 27976 soc_field_t fld; /* DSCP field index. */ 27977 27978 /* Get table memory. */ 27979 mem = BCM_XGS3_L3_MEM(unit, tnl_dscp); 27980 27981 /* Read buffer from hw. */ 27982 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry)); 27983 27984 /* Get dscp field id based on unit type. */ 27985 #if defined(BCM_FIREBOLT_SUPPORT) 27986 if (SOC_IS_TRIDENT3X(unit)) { 27987 fld = QOSf; 27988 } else if (SOC_IS_FBX(unit)) { 27989 fld = DSCPf; 27990 } else 27991 #endif /* BCM_FIREBOLT_SUPPORT */ 27992 { 27993 return (BCM_E_UNAVAIL); 27994 } 27995 27996 /* Parse hw buffer. */ 27997 tnl_info->dscp = soc_mem_field32_get(unit, mem, tnl_entry, fld); 27998 27999 return (BCM_E_NONE); 28000 } 28001 28002 /* 28003 * Function: 28004 * _bcm_xgs3_l3_tnl_dscp_add 28005 * Purpose: 28006 * Add tunnel dscp entry to hw. 28007 * Parameters: 28008 * unit - (IN)SOC unit number. 28009 * idx - (IN)Index to insert tunnel initiator index. 28010 * buf - (IN)Tunnel dscp entry info. 28011 * Returns: 28012 * BCM_E_XXX 28013 */ 28014 STATIC int 28015 _bcm_xgs3_l3_tnl_dscp_set(int unit, int idx, void *buf) 28016 { 28017 soc_mem_t mem; /* Tunnel dscp table memory.*/ 28018 bcm_tunnel_dscp_map_t *tnl_info; /* Tunnel dscp information. */ 28019 28020 /* Input parameters check. */ 28021 if (NULL == buf) { 28022 return (BCM_E_PARAM); 28023 } 28024 28025 /* Get table memory. */ 28026 mem = BCM_XGS3_L3_MEM(unit, tnl_dscp); 28027 28028 tnl_info = (bcm_tunnel_dscp_map_t *) buf; 28029 28030 #ifdef BCM_FIREBOLT_SUPPORT 28031 if(SOC_IS_FBX(unit)) { 28032 soc_field_t fld; 28033 uint32 buf_p[SOC_MAX_MEM_WORDS]; /* HW buffer address. */ 28034 28035 /* Zero write buffer. */ 28036 sal_memset(buf_p, 0, sizeof(buf_p)); 28037 28038 if (SOC_IS_TRIDENT3X(unit)) { 28039 fld = QOSf; 28040 } else { 28041 fld = DSCPf; 28042 } 28043 soc_mem_field32_set(unit, mem, buf_p, fld, tnl_info->dscp); 28044 28045 /* Write buffer to hw. */ 28046 return BCM_XGS3_MEM_WRITE(unit, mem, idx, buf_p); 28047 } 28048 #endif /* BCM_FIREBOLT_SUPPORT */ 28049 28050 return (BCM_E_NONE); 28051 } 28052 28053 /* 28054 * Function: 28055 * _bcm_xgs3_l3_default_mtu_set 28056 * Purpose: 28057 * Set default L3 MTU. 28058 * Parameters: 28059 * unit - (IN)SOC unit number. 28060 * Returns: 28061 * BCM_E_XXX 28062 */ 28063 STATIC int 28064 _bcm_xgs3_l3_default_mtu_set(int unit) 28065 { 28066 uint8 *l3_mtu_val_buf = NULL; 28067 mtu_values_entry_t *l3_mtu_entry = NULL; 28068 int rv, idx, idx_min, idx_max; 28069 int max_mtu = 0; 28070 28071 /* l3_mtu_values table*/ 28072 l3_mtu_val_buf = soc_cm_salloc(unit, 28073 SOC_MEM_TABLE_BYTES(unit,L3_MTU_VALUESm), 28074 "l3_mtu_values"); 28075 28076 if (l3_mtu_val_buf == NULL) { 28077 return BCM_E_MEMORY; 28078 } 28079 28080 idx_min = soc_mem_index_min(unit, L3_MTU_VALUESm); 28081 idx_max = soc_mem_index_max(unit, L3_MTU_VALUESm); 28082 rv = soc_mem_read_range(unit, L3_MTU_VALUESm, 28083 MEM_BLOCK_ANY, idx_min, idx_max, 28084 l3_mtu_val_buf); 28085 28086 if (BCM_FAILURE(rv)) { 28087 soc_cm_sfree(unit, l3_mtu_val_buf); 28088 return rv; 28089 } 28090 28091 max_mtu = (1 << soc_mem_field_length(unit, L3_MTU_VALUESm, MTU_SIZEf)) - 1; 28092 for (idx = idx_min; idx<= idx_max; idx++) { 28093 l3_mtu_entry = 28094 soc_mem_table_idx_to_pointer(unit, L3_MTU_VALUESm, 28095 mtu_values_entry_t *, 28096 l3_mtu_val_buf, 28097 idx); 28098 28099 soc_L3_MTU_VALUESm_field32_set(unit, 28100 l3_mtu_entry, 28101 MTU_SIZEf, max_mtu); 28102 } 28103 28104 rv = soc_mem_write_range(unit, L3_MTU_VALUESm, MEM_BLOCK_ALL, 28105 idx_min, idx_max, l3_mtu_val_buf); 28106 28107 if (BCM_FAILURE(rv)) { 28108 soc_cm_sfree(unit, l3_mtu_val_buf); 28109 return rv; 28110 } 28111 28112 soc_cm_sfree(unit, l3_mtu_val_buf); 28113 return BCM_E_NONE; 28114 } 28115 28116 /* 28117 * Function: 28118 * _bcm_xgs3_l3_clear_all 28119 * Purpose: 28120 * Flush all l3 tables on the chip 28121 * Parameters: 28122 * unit - (IN)SOC unit number. 28123 * Returns: 28124 * BCM_E_XXX 28125 */ 28126 STATIC int 28127 _bcm_xgs3_l3_clear_all(int unit) 28128 { 28129 if (SOC_WARM_BOOT(unit)) { 28130 return BCM_E_NONE; 28131 } 28132 #if defined(BCM_TRIUMPH_SUPPORT) 28133 if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) { 28134 /* reset L3 mtu values. */ 28135 _bcm_xgs3_l3_default_mtu_set(unit); 28136 } 28137 #endif /* BCM_TRIUMPH_SUPPORT */ 28138 #ifdef BCM_TRIDENT2PLUS_SUPPORT 28139 if (soc_feature(unit, soc_feature_egr_modport_to_nhi)) { 28140 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_CLEAR(unit,EGR_DGPP_TO_NHI_MODBASEm)); 28141 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_CLEAR(unit,EGR_DGPP_TO_NHIm)); 28142 } 28143 #endif 28144 /* 28145 * Enabling clear all for TD2+ on bcmsim 28146 */ 28147 if (((SAL_BOOT_BCMSIM || SAL_BOOT_XGSSIM) && !SOC_IS_TRIDENT2PLUS(unit) && 28148 !SOC_IS_TOMAHAWK3(unit) && !SOC_IS_TOMAHAWK2(unit) && !SOC_IS_APACHE(unit)) 28149 || SAL_BOOT_QUICKTURN) { 28150 return BCM_E_NONE; 28151 } 28152 /* Clear next hop table. */ 28153 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, intf))); 28154 28155 /* Clear next hop table. */ 28156 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, nh))); 28157 28158 /* Clear L3 ipv4 table. */ 28159 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v4))); 28160 28161 /* Clear L3 ipv6 table. */ 28162 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v6))); 28163 28164 /* Clear tunnel terminator table. */ 28165 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, 28166 tnl_term))); 28167 28168 /* Clear IPv4 tunnel initiator table. */ 28169 BCM_IF_ERROR_RETURN 28170 (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, tnl_init_v4))); 28171 28172 /* Clear MPLS tunnel initiator table. */ 28173 BCM_IF_ERROR_RETURN 28174 (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, tnl_init_mpls))); 28175 28176 /* Clear IPv6 tunnel initiator table. */ 28177 BCM_IF_ERROR_RETURN 28178 (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, tnl_init_v6))); 28179 /* Clear tunnel dscp table. */ 28180 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, 28181 tnl_dscp))); 28182 28183 /* Clear ECMP groups table. */ 28184 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, 28185 ecmp))); 28186 28187 /* Clear route table. */ 28188 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, 28189 defip))); 28190 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_128m)) { 28191 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_128m)); 28192 } 28193 28194 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_PAIR_128m)) { 28195 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_PAIR_128m)); 28196 } 28197 28198 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_IPV4m)) { 28199 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_ALPM_IPV4m)); 28200 } 28201 28202 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_AUX_TABLEm)) { 28203 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_AUX_TABLEm)); 28204 } 28205 28206 /* Clear IPv6 prefix map table. */ 28207 BCM_IF_ERROR_RETURN 28208 (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v6_prefix_map))); 28209 28210 #if defined(BCM_FIREBOLT_SUPPORT) 28211 if (SOC_IS_FBX(unit)) { 28212 /* Clear egress next hop table. */ 28213 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EGR_L3_NEXT_HOPm)); 28214 28215 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 28216 defined(BCM_TRX_SUPPORT) 28217 /* Clear initial ecmp groups table. */ 28218 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMPm)); 28219 28220 /* Clear initial ingress next hop table. */ 28221 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, 28222 INITIAL_ING_L3_NEXT_HOPm)); 28223 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 28224 } 28225 #endif /* BCM_FIREBOLT_SUPPORT */ 28226 28227 #if defined(BCM_TRX_SUPPORT) 28228 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 28229 /* Clear ecmp groups count table. */ 28230 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_ECMP_COUNTm)); 28231 } 28232 28233 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_COUNTm)) { 28234 /* Clear initial ecmp groups count table. */ 28235 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMP_COUNTm)); 28236 } 28237 28238 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_GROUPm)) { 28239 /* Clear initial ecmp groups count table. */ 28240 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMP_GROUPm)); 28241 } 28242 28243 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) { 28244 /* Clear initial ecmp groups count table. */ 28245 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMPm)); 28246 } 28247 #endif /* BCM_TRX_SUPPORT */ 28248 28249 #if defined(BCM_TRIUMPH_SUPPORT) 28250 if (SOC_MEM_IS_VALID(unit, L3_IIFm)) { 28251 /* Clear initial ecmp groups count table. */ 28252 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_IIFm)); 28253 } 28254 28255 if (!SOC_IS_TRIUMPH3(unit)) { 28256 /* Skip clearing ESM route tables for TR3 as it results in 28257 * marking the entry as valid */ 28258 if (soc_feature(unit, soc_feature_esm_support)) { 28259 if (SOC_MEM_IS_VALID(unit, EXT_IPV4_DEFIPm)) { 28260 /* Clear External V4 table. */ 28261 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EXT_IPV4_DEFIPm)); 28262 } 28263 28264 if (SOC_MEM_IS_VALID(unit, EXT_IPV6_64_DEFIPm)) { 28265 /* Clear External V6 upper 64 table. */ 28266 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EXT_IPV6_64_DEFIPm)); 28267 } 28268 28269 if (SOC_MEM_IS_VALID(unit, EXT_IPV6_128_DEFIPm)) { 28270 /* Clear External V6 full prefix length table. */ 28271 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EXT_IPV6_128_DEFIPm)); 28272 } 28273 } 28274 } 28275 #endif /* BCM_TRIUMPH_SUPPORT */ 28276 28277 #ifdef BCM_TRIUMPH2_SUPPORT 28278 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 28279 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) || 28280 SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || 28281 SOC_IS_KATANAX(unit)) { 28282 /* Clear VRF counter index table. */ 28283 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, VRFm)); 28284 } 28285 #endif /* BCM_TRIUMPH2_SUPPORT */ 28286 28287 return (BCM_E_NONE); 28288 } 28289 28290 28291 /* 28292 * Function: 28293 * _bcm_xgs3_l3_intf_get 28294 * Purpose: 28295 * Get an entry from L3 interface table. 28296 * Parameters: 28297 * unit - (IN)SOC unit number. 28298 * intf_info - (IN/OUT)Pointer to memory for interface information. 28299 * Returns: 28300 * BCM_E_XXX 28301 */ 28302 STATIC int 28303 _bcm_xgs3_l3_intf_get(int unit, _bcm_l3_intf_cfg_t *intf_info) 28304 { 28305 l3_max_entry_t l3_if_entry; /* Buffer to read interface info. */ 28306 _bcm_l3_intf_fields_t *fld; /* Interface table common fields. */ 28307 uint32 *l3_if_entry_p; /* Interface read buffer address. */ 28308 soc_mem_t mem; /* Interface table memory. */ 28309 #ifdef BCM_TRIDENT3_SUPPORT 28310 uint8 ent_type=0; 28311 #endif 28312 #ifdef BCM_RIOT_SUPPORT 28313 egr_mac_da_profile_entry_t macda; 28314 int svp = -1; 28315 int profiled_mac = 0; 28316 int macda_index = -1; 28317 #endif 28318 28319 /* Input parameters check */ 28320 if (NULL == intf_info) { 28321 return (BCM_E_PARAM); 28322 } 28323 28324 /* Get interface table memory. */ 28325 mem = BCM_XGS3_L3_MEM(unit, intf); 28326 28327 /* Zero read buffer. */ 28328 l3_if_entry_p = (uint32 *)&l3_if_entry; 28329 sal_memset(l3_if_entry_p, 0, sizeof(l3_max_entry_t)); 28330 28331 /* Read interface table entry by index. */ 28332 BCM_IF_ERROR_RETURN 28333 (BCM_XGS3_MEM_READ (unit, mem, intf_info->l3i_index, l3_if_entry_p)); 28334 28335 #ifdef BCM_TRIDENT3_SUPPORT 28336 if (SOC_MEM_FIELD_VALID(unit, mem, DATA_TYPEf)) { 28337 ent_type = soc_mem_field32_get(unit, mem, l3_if_entry_p, DATA_TYPEf); 28338 } 28339 if (soc_feature(unit, soc_feature_flex_flow) && 28340 (ent_type > 0)) { 28341 BCM_IF_ERROR_RETURN( 28342 _bcm_td3_l3_flex_intf_get(unit, intf_info, l3_if_entry_p)); 28343 } 28344 else 28345 #endif 28346 { 28347 /* Extract interface information. */ 28348 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 28349 28350 28351 #ifdef BCM_RIOT_SUPPORT 28352 if (soc_feature(unit, soc_feature_riot)) { 28353 svp = soc_mem_field32_get(unit, mem, l3_if_entry_p, SVPf); 28354 28355 if (_bcm_vp_used_get(unit, svp, _bcmVpTypeVxlan)) { 28356 BCM_GPORT_VXLAN_PORT_ID_SET(intf_info->l3i_source_vp, svp); 28357 } else if (_bcm_vp_used_get(unit, svp, _bcmVpTypeL2Gre)) { 28358 BCM_GPORT_L2GRE_PORT_ID_SET(intf_info->l3i_source_vp, svp); 28359 } else if (_bcm_vp_used_get(unit, svp, _bcmVpTypeMim)) { 28360 BCM_GPORT_MIM_PORT_ID_SET(intf_info->l3i_source_vp, svp); 28361 } else if (_bcm_vp_used_get(unit, svp, _bcmVpTypeMpls)) { 28362 BCM_GPORT_MPLS_PORT_ID_SET(intf_info->l3i_source_vp, svp); 28363 } 28364 28365 /*VLAN_VFI_OVERLAY_TYPE is not required in TD3 */ 28366 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) { 28367 profiled_mac = soc_mem_field32_get(unit, mem, l3_if_entry_p, 28368 MAC_ADDRESS_OVERLAY_TYPEf); 28369 macda_index = soc_mem_field32_get(unit, mem, l3_if_entry_p, 28370 MAC_ADDRESS_PROFILE_IDXf); 28371 } 28372 if (profiled_mac) { 28373 /* Read entry from MAC-DA-PROFILEm */ 28374 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm, 28375 MEM_BLOCK_ANY, macda_index, &macda)); 28376 /* Get mac address from EGR_MACDA_PROFILE. */ 28377 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, &macda, 28378 MAC_ADDRESSf, intf_info->l3i_mac_addr); 28379 } else { 28380 /* Get mac address from EGR_L3_INTF. */ 28381 soc_mem_mac_addr_get(unit, mem, l3_if_entry_p, 28382 fld->mac_addr, intf_info->l3i_mac_addr); 28383 } 28384 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) { 28385 if (profiled_mac) { 28386 /* Use profiled_mac indicator to also confirm presence of VFI and read the same */ 28387 _BCM_VPN_SET(intf_info->l3i_vid, _BCM_VPN_TYPE_VFI, 28388 soc_mem_field32_get(unit, mem, l3_if_entry_p, VFIf)); 28389 } else { 28390 intf_info->l3i_vid = 28391 soc_mem_field32_get(unit, mem, l3_if_entry_p, 28392 fld->vlan_id); 28393 } 28394 } else if (soc_mem_field32_get(unit, mem, l3_if_entry_p, 28395 VLAN_VFI_OVERLAY_TYPEf)) { 28396 28397 _BCM_VPN_SET(intf_info->l3i_vid, _BCM_VPN_TYPE_VFI, 28398 soc_mem_field32_get(unit, mem, l3_if_entry_p, VFIf)); 28399 } else { 28400 intf_info->l3i_vid = 28401 soc_mem_field32_get(unit, mem, l3_if_entry_p, 28402 fld->vlan_id); 28403 } 28404 28405 } else 28406 #endif 28407 { 28408 /* Get vlan id. */ 28409 intf_info->l3i_vid = 28410 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->vlan_id); 28411 /* Get mac address. */ 28412 soc_mem_mac_addr_get(unit, mem, l3_if_entry_p, 28413 fld->mac_addr, intf_info->l3i_mac_addr); 28414 } 28415 /* Get Time To Live. */ 28416 if (SOC_MEM_FIELD_VALID(unit, mem, fld->ttl)) { 28417 intf_info->l3i_ttl = 28418 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->ttl); 28419 } 28420 28421 /* Get tunnel index. */ 28422 if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) { 28423 intf_info->l3i_tunnel_idx = 28424 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->tnl_id); 28425 } 28426 28427 /* Set L2 bridging only flag. */ 28428 if (soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->l2_switch)) { 28429 intf_info->l3i_flags |= BCM_L3_L2ONLY; 28430 } 28431 28432 #ifdef BCM_TRIDENT_SUPPORT 28433 if (SOC_MEM_FIELD_VALID(unit, mem, OPRI_OCFI_SELf)) { 28434 BCM_IF_ERROR_RETURN 28435 (_bcm_td_l3_intf_qos_get(unit, l3_if_entry_p, intf_info)); 28436 } 28437 #endif /* BCM_TRIDENT_SUPPORT */ 28438 28439 #ifdef BCM_GREYHOUND2_SUPPORT 28440 if (soc_feature(unit, soc_feature_vxlan_lite_riot)) { 28441 BCM_IF_ERROR_RETURN( 28442 bcmi_gh2_l3_intf_qos_get(unit, l3_if_entry_p, intf_info)); 28443 } 28444 #endif /* BCM_GREYHOUND2_SUPPORT */ 28445 28446 #ifdef BCM_TRX_SUPPORT 28447 if (SOC_MEM_FIELD_VALID(unit, mem, IVID_VALIDf)) { 28448 if (soc_mem_field32_get(unit, mem, l3_if_entry_p, IVID_VALIDf)) { 28449 intf_info->l3i_inner_vlan = 28450 soc_mem_field32_get(unit, mem, l3_if_entry_p, IVIDf); 28451 } 28452 } 28453 #endif /* BCM_TRX_SUPPORT */ 28454 28455 #ifdef BCM_TRIUMPH3_SUPPORT 28456 if (SOC_MEM_FIELD_VALID(unit, mem, CLASS_IDf)) { 28457 intf_info->l3i_class = 28458 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->class_id); 28459 } 28460 #endif 28461 28462 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 28463 /*Program Inner VLAN handling actions */ 28464 if (SOC_MEM_FIELD_VALID(unit, mem, IVID_PRESENT_ACTIONf)) { 28465 int action; 28466 action = soc_mem_field32_get(unit, mem, l3_if_entry_p, 28467 IVID_PRESENT_ACTIONf); 28468 switch (action) { 28469 case 0: 28470 intf_info->l3i_intf_flags |= 28471 BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY; 28472 break; 28473 case 1: 28474 #if defined(BCM_GREYHOUND2_SUPPORT) 28475 if (soc_feature(unit, soc_feature_vxlan_lite_riot)) { 28476 intf_info->l3i_intf_flags |= 28477 BCM_L3_INTF_INNER_VLAN_DELETE; 28478 } else 28479 #endif /* BCM_GREYHOUND2_SUPPORT */ 28480 { 28481 intf_info->l3i_intf_flags |= 28482 BCM_L3_INTF_INNER_VLAN_REPLACE; 28483 } 28484 break; 28485 case 2: 28486 #if defined(BCM_GREYHOUND2_SUPPORT) 28487 if (soc_feature(unit, soc_feature_vxlan_lite_riot)) { 28488 intf_info->l3i_intf_flags |= 28489 BCM_L3_INTF_INNER_VLAN_REPLACE; 28490 } else 28491 #endif /* BCM_GREYHOUND2_SUPPORT */ 28492 { 28493 intf_info->l3i_intf_flags |= 28494 BCM_L3_INTF_INNER_VLAN_DELETE; 28495 } 28496 break; 28497 default: 28498 intf_info->l3i_intf_flags |= 28499 BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY; 28500 } 28501 action = soc_mem_field32_get(unit, mem, l3_if_entry_p, 28502 IVID_ABSENT_ACTIONf); 28503 if (action == 1) { 28504 intf_info->l3i_intf_flags |= BCM_L3_INTF_INNER_VLAN_ADD; 28505 intf_info->l3i_intf_flags &= 28506 ~(BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY); 28507 } 28508 intf_info->l3i_inner_vlan = 28509 soc_mem_field32_get(unit, mem, l3_if_entry_p, IVIDf); 28510 } 28511 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 28512 } 28513 28514 #ifdef BCM_TRIDENT2_SUPPORT 28515 if (soc_feature(unit, soc_feature_nat) 28516 #ifdef BCM_RIOT_SUPPORT 28517 && (!( BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid))) 28518 #endif 28519 ) { 28520 28521 BCM_IF_ERROR_RETURN(_bcm_fb_l3_intf_nat_realm_id_get(unit, intf_info)); 28522 } 28523 28524 if (soc_feature(unit, soc_feature_l3_ip4_options_profile) 28525 #ifdef BCM_RIOT_SUPPORT 28526 && (!( BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid))) 28527 #endif 28528 ) { 28529 BCM_IF_ERROR_RETURN( 28530 _bcm_td2_l3_iif_ip4_options_profile_index_get(unit, intf_info)); 28531 } 28532 #endif /* BCM_TRIDENT2_SUPPORT */ 28533 28534 #if defined(BCM_TRIUMPH_SUPPORT) 28535 /* Read L3 mtu value for the interface. */ 28536 if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) { 28537 #if defined(BCM_HURRICANE_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 28538 if(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit)|| 28539 SOC_IS_GREYHOUND2(unit)) { 28540 BCM_IF_ERROR_RETURN(_bcm_hu_l3_intf_mtu_get(unit, intf_info)); 28541 } else 28542 #endif /* BCM_HURRICANE_SUPPORT*/ 28543 { 28544 BCM_IF_ERROR_RETURN(_bcm_tr_l3_intf_mtu_get(unit, intf_info)); 28545 } 28546 } 28547 #endif /* BCM_TRIUMPH_SUPPORT */ 28548 28549 #if defined(BCM_TRIUMPH3_SUPPORT) 28550 if (SOC_IS_TRIUMPH3(unit)) { 28551 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_intf_mtu_get(unit, intf_info)); 28552 } 28553 #endif /* BCM_TRIUMPH3_SUPPORT */ 28554 28555 return (BCM_E_NONE); 28556 } 28557 /* 28558 * Function: 28559 * _bcm_xgs3_l3_intf_add 28560 * Purpose: 28561 * Add an entry to L3 interface table. 28562 * Parameters: 28563 * unit - (IN)SOC unit number. 28564 * intf_info - (IN)Interface information. 28565 * Returns: 28566 * BCM_E_XXX 28567 */ 28568 STATIC int 28569 _bcm_xgs3_l3_intf_add(int unit, _bcm_l3_intf_cfg_t *intf_info) 28570 { 28571 l3_max_entry_t l3_if_entry; /* Buffer to write interface info. */ 28572 _bcm_l3_intf_fields_t *fld; /* Interface table common fields. */ 28573 uint32 *l3_if_entry_p; /* Write buffer address. */ 28574 soc_mem_t mem; /* Interface table memory. */ 28575 #ifdef BCM_RIOT_SUPPORT 28576 egr_mac_da_profile_entry_t macda; 28577 uint32 macda_index = -1; 28578 void *entries[1]; 28579 #endif 28580 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 28581 int ivid_action_replace = 0, ivid_action_delete = 0; 28582 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 28583 28584 /* Input parameters check */ 28585 if (NULL == intf_info) { 28586 return (BCM_E_PARAM); 28587 } 28588 28589 /* Get interface table memory. */ 28590 mem = BCM_XGS3_L3_MEM(unit, intf); 28591 28592 /* Get memory fields information. */ 28593 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 28594 28595 /* Zero the buffer. */ 28596 l3_if_entry_p = (uint32 *)&l3_if_entry; 28597 sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf)); 28598 BCM_IF_ERROR_RETURN( 28599 BCM_XGS3_MEM_READ(unit, mem, intf_info->l3i_index, l3_if_entry_p)); 28600 28601 #ifdef BCM_TOMAHAWK3_SUPPORT 28602 if (SOC_IS_TOMAHAWK3(unit) && 28603 (intf_info->l3i_intf_flags & (BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY | 28604 BCM_L3_INTF_INNER_VLAN_REPLACE | 28605 BCM_L3_INTF_INNER_VLAN_ADD | 28606 BCM_L3_INTF_INNER_VLAN_DELETE))) { 28607 return (BCM_E_UNAVAIL); 28608 } 28609 #endif 28610 #ifdef BCM_TRIDENT3_SUPPORT 28611 if (soc_feature(unit, soc_feature_flex_flow) && 28612 (intf_info->flow_handle != 0)) { 28613 28614 BCM_IF_ERROR_RETURN( 28615 _bcm_td3_l3_flex_intf_add(unit, intf_info, l3_if_entry_p)); 28616 } 28617 else 28618 #endif 28619 { 28620 28621 #ifdef BCM_RIOT_SUPPORT 28622 if (BCMI_L3_INTF_OVERLAY_VALID(unit)) { 28623 int svp = intf_info->l3i_source_vp; 28624 if (BCM_GPORT_IS_VXLAN_PORT(svp)) { 28625 svp = BCM_GPORT_VXLAN_PORT_ID_GET(svp); 28626 } else if (BCM_GPORT_IS_L2GRE_PORT(svp)) { 28627 svp = BCM_GPORT_L2GRE_PORT_ID_GET(svp); 28628 } else if (BCM_GPORT_IS_MIM_PORT(svp)) { 28629 svp = BCM_GPORT_MIM_PORT_ID_GET(svp); 28630 } else if (BCM_GPORT_IS_MPLS_PORT(svp)) { 28631 svp = BCM_GPORT_MPLS_PORT_ID_GET(svp); 28632 } 28633 28634 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28635 SVPf, svp); 28636 28637 if (!soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) { 28638 /* Set mac address. */ 28639 soc_mem_mac_addr_set(unit, mem, l3_if_entry_p, 28640 fld->mac_addr, intf_info->l3i_mac_addr); 28641 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 28642 int vfi_idx = 0; 28643 _BCM_VPN_GET(vfi_idx, _BCM_VPN_TYPE_VFI, intf_info->l3i_vid); 28644 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28645 VFIf, vfi_idx); 28646 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28647 VLAN_VFI_OVERLAY_TYPEf, 1); 28648 } else { 28649 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28650 fld->vlan_id, intf_info->l3i_vid); 28651 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28652 VLAN_VFI_OVERLAY_TYPEf, 0); 28653 } 28654 } else { 28655 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 28656 int vfi_idx = 0; 28657 _BCM_VPN_GET(vfi_idx, _BCM_VPN_TYPE_VFI, intf_info->l3i_vid); 28658 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28659 VFIf, vfi_idx); 28660 /* Profiling of EGR_MAC_SA since it is overlaid*/ 28661 sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t)); 28662 soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm, 28663 &macda, MAC_ADDRESSf, intf_info->l3i_mac_addr); 28664 entries[0] = &macda; 28665 BCM_IF_ERROR_RETURN(_bcm_mac_da_profile_entry_add(unit, 28666 entries, 1, &macda_index)); 28667 28668 /* Point to the right profile in egress interface table */ 28669 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28670 MAC_ADDRESS_PROFILE_IDXf, macda_index); 28671 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28672 MAC_ADDRESS_OVERLAY_TYPEf, 1); 28673 } else { 28674 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28675 fld->vlan_id, intf_info->l3i_vid); 28676 soc_mem_mac_addr_set(unit, mem, l3_if_entry_p, 28677 fld->mac_addr, intf_info->l3i_mac_addr); 28678 } 28679 } 28680 } else 28681 #endif 28682 { 28683 /* Set vlan id. */ 28684 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28685 fld->vlan_id, intf_info->l3i_vid); 28686 /* Set mac address. */ 28687 soc_mem_mac_addr_set(unit, mem, l3_if_entry_p, 28688 fld->mac_addr, intf_info->l3i_mac_addr); 28689 } 28690 /* Set Time To Live. */ 28691 if(SOC_MEM_FIELD_VALID(unit, mem, fld->ttl)) { 28692 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28693 fld->ttl, intf_info->l3i_ttl); 28694 } 28695 28696 /* Set tunnel index. */ 28697 if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) { 28698 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28699 fld->tnl_id, intf_info->l3i_tunnel_idx); 28700 } 28701 28702 /* Set L2 bridging only flag. */ 28703 if (intf_info->l3i_flags & BCM_L3_L2ONLY) { 28704 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28705 fld->l2_switch, 1); 28706 } else { 28707 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28708 fld->l2_switch, 0); 28709 } 28710 28711 #ifdef BCM_TRX_SUPPORT 28712 if (SOC_MEM_FIELD_VALID(unit, mem, IVIDf)) { 28713 if (intf_info->l3i_inner_vlan) { 28714 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf, 28715 intf_info->l3i_inner_vlan); 28716 if (SOC_MEM_FIELD_VALID(unit, mem, IVID_VALIDf)) { 28717 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVID_VALIDf, 0x1); 28718 } 28719 } 28720 } 28721 #endif /* BCM_TRX_SUPPORT */ 28722 28723 #ifdef BCM_TRIUMPH3_SUPPORT 28724 if (SOC_MEM_FIELD_VALID(unit, mem, CLASS_IDf)) { 28725 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28726 fld->class_id, intf_info->l3i_class); 28727 } 28728 #endif 28729 28730 #ifdef BCM_TRIDENT_SUPPORT 28731 if (SOC_MEM_FIELD_VALID(unit, mem, OPRI_OCFI_SELf)) { 28732 BCM_IF_ERROR_RETURN 28733 (_bcm_td_l3_intf_qos_set(unit, l3_if_entry_p, intf_info)); 28734 } 28735 #endif /* BCM_TRIDENT_SUPPORT */ 28736 28737 #ifdef BCM_GREYHOUND2_SUPPORT 28738 if (soc_feature(unit, soc_feature_vxlan_lite_riot)) { 28739 BCM_IF_ERROR_RETURN( 28740 bcmi_gh2_l3_intf_qos_set(unit, l3_if_entry_p, intf_info)); 28741 } 28742 #endif /* BCM_GREYHOUND2_SUPPORT */ 28743 28744 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT) 28745 /* Program Inner VLAN handling actions */ 28746 if (SOC_MEM_FIELD_VALID(unit, mem, IVID_PRESENT_ACTIONf)) { 28747 ivid_action_replace = 28748 (soc_feature(unit, soc_feature_vxlan_lite_riot)) ? 2 : 1; 28749 ivid_action_delete = 28750 (soc_feature(unit, soc_feature_vxlan_lite_riot)) ? 1 : 2; 28751 28752 if (intf_info->l3i_intf_flags & 28753 BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY) { 28754 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28755 IVID_PRESENT_ACTIONf, 0); 28756 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28757 IVID_ABSENT_ACTIONf, 0); 28758 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf, 0); 28759 } else { 28760 if (intf_info->l3i_intf_flags & BCM_L3_INTF_INNER_VLAN_ADD) { 28761 if (intf_info->l3i_intf_flags & 28762 BCM_L3_INTF_INNER_VLAN_REPLACE) { 28763 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28764 IVID_PRESENT_ACTIONf, 28765 ivid_action_replace); 28766 } else if (intf_info->l3i_intf_flags & 28767 BCM_L3_INTF_INNER_VLAN_DELETE) { 28768 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28769 IVID_PRESENT_ACTIONf, 28770 ivid_action_delete); 28771 } else { 28772 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28773 IVID_PRESENT_ACTIONf, 0); 28774 } 28775 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28776 IVID_ABSENT_ACTIONf, 1); 28777 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf, 28778 intf_info->l3i_inner_vlan); 28779 } else { 28780 if (intf_info->l3i_intf_flags & 28781 BCM_L3_INTF_INNER_VLAN_REPLACE) { 28782 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28783 IVID_PRESENT_ACTIONf, 28784 ivid_action_replace); 28785 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28786 IVID_ABSENT_ACTIONf, 0); 28787 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf, 28788 intf_info->l3i_inner_vlan); 28789 } else { 28790 if (intf_info->l3i_intf_flags & 28791 BCM_L3_INTF_INNER_VLAN_DELETE) { 28792 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28793 IVID_PRESENT_ACTIONf, 28794 ivid_action_delete); 28795 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28796 IVID_ABSENT_ACTIONf, 0); 28797 soc_mem_field32_set(unit, mem, l3_if_entry_p, 28798 IVIDf, 0); 28799 } 28800 } 28801 } 28802 } 28803 } 28804 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */ 28805 } 28806 28807 /* Write entry to the chip. */ 28808 BCM_IF_ERROR_RETURN 28809 (BCM_XGS3_MEM_WRITE(unit, mem, intf_info->l3i_index, l3_if_entry_p)); 28810 28811 /* SDK-33159 : section below to update the usage of L3_IIFm index is 28812 * for fixing urpf strict mode issue on TD device. 28813 * - Such design may causes unexpected L3_IIFm entry been reserved 28814 * once the device(like HR3) can't support 4K above L3_IIFm entry. 28815 * - For fixing SDK-77744, section below will be ignored for devices 28816 * supports L3_IIFm under 4K entries. 28817 */ 28818 if (!soc_feature(unit, soc_feature_l3_iif_under_4k)) { 28819 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) { 28820 /* mark L3_ING_Interface with interface_id as Used */ 28821 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_info->l3i_index); 28822 } 28823 } 28824 28825 #ifdef BCM_TRIUMPH_SUPPORT 28826 if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) { 28827 #if defined(BCM_HURRICANE_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 28828 if(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit)|| 28829 SOC_IS_GREYHOUND2(unit)) { 28830 BCM_IF_ERROR_RETURN(_bcm_hu_l3_intf_mtu_set(unit, intf_info)); 28831 } else 28832 #endif /* BCM_HURRICANE_SUPPORT*/ 28833 { 28834 BCM_IF_ERROR_RETURN(_bcm_tr_l3_intf_mtu_set(unit, intf_info)); 28835 } 28836 } 28837 #endif /* BCM_TRIUMPH_SUPPORT */ 28838 28839 #if defined(BCM_TRIUMPH3_SUPPORT) 28840 if (SOC_IS_TRIUMPH3(unit)) { 28841 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_intf_mtu_set(unit, intf_info)); 28842 } 28843 #endif /* BCM_TRIUMPH3_SUPPORT */ 28844 28845 return (BCM_E_NONE); 28846 28847 } 28848 28849 /* 28850 * Function: 28851 * _bcm_xgs3_l3_intf_del 28852 * Purpose: 28853 * Delete an entry from L3 interface table. 28854 * Parameters: 28855 * unit - (IN)SOC unit number. 28856 * ifindex - (IN)Interface index. 28857 * Returns: 28858 * BCM_E_XXX 28859 */ 28860 STATIC int 28861 _bcm_xgs3_l3_intf_del(int unit, int ifindex) 28862 { 28863 l3_max_entry_t l3_if_entry; /* Buffer to write interface info. */ 28864 soc_mem_t mem; /* Interface table memory. */ 28865 28866 /* Get interface table memory. */ 28867 mem = BCM_XGS3_L3_MEM(unit, intf); 28868 28869 /* Zero the buffer. */ 28870 sal_memset(&l3_if_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, intf)); 28871 28872 #ifdef BCM_TRIDENT3_SUPPORT 28873 if (soc_feature(unit, soc_feature_flex_flow)) { 28874 BCM_IF_ERROR_RETURN( 28875 _bcm_td3_l3_flex_intf_profile_delete(unit, ifindex)); 28876 } 28877 #endif 28878 28879 /* SDK-33159 : section below to update the usage of L3_IIFm index is 28880 * for fixing urpf strict mode issue on TD device. 28881 * - Such design may causes unexpected L3_IIFm entry been reserved 28882 * once the device(like HR3) can't support 4K above L3_IIFm entry. 28883 * - For fixing SDK-77744, section below will be ignored for devices 28884 * supports L3_IIFm under 4K entries. 28885 */ 28886 if (!soc_feature(unit, soc_feature_l3_iif_under_4k)) { 28887 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) { 28888 /* mark L3_ING_Interface with interface_id as Un-used */ 28889 SHR_BITCLR(BCM_XGS3_L3_ING_IF_INUSE(unit), ifindex); 28890 } 28891 } 28892 28893 #ifdef BCM_TRIUMPH3_SUPPORT 28894 /* On Triumph3, MMU replication outputs next hop indices only. 28895 * Hence, a next hop index is allocated for each L3 interface 28896 * used in IPMC replication. When deleting a L3 interface, 28897 * the associated next hop index needs to be freed. 28898 */ 28899 if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) { 28900 #ifdef BCM_TOMAHAWK_SUPPORT 28901 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 28902 BCM_IF_ERROR_RETURN(bcm_th_ipmc_l3_intf_next_hop_free(unit, ifindex)); 28903 } else 28904 #endif /* BCM_TOMAHAWK_SUPPORT */ 28905 { 28906 BCM_IF_ERROR_RETURN(bcm_tr3_ipmc_l3_intf_next_hop_free(unit, ifindex)); 28907 } 28908 } 28909 #endif /* BCM_TRIUMPH3_SUPPORT */ 28910 28911 #ifdef BCM_TRIDENT2_SUPPORT 28912 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 28913 BCM_IF_ERROR_RETURN(bcm_td2_multicast_l3_vp_next_hop_free(unit, ifindex)); 28914 } 28915 #endif /* BCM_TRIDENT2_SUPPORT */ 28916 28917 /* Clear flag that indicates if L3 interface is used in Next Hop table. */ 28918 BCM_XGS3_L3_INTF_USED_NH_CLR(unit, ifindex); 28919 28920 /* Write entry to the chip. */ 28921 return BCM_XGS3_MEM_WRITE(unit, mem, ifindex, &l3_if_entry); 28922 } 28923 28924 /* 28925 * Function: 28926 * _bcm_xgs3_l3_intf_tnl_init_get 28927 * Purpose: 28928 * Get interface tunnel initiator info 28929 * Parameters: 28930 * unit - (IN)SOC unit number. 28931 * ifindex - (IN)Interface index. 28932 * tnl_info - (OUT)Tunnel initiator buffer to fill. 28933 * Returns: 28934 * BCM_E_XXX 28935 */ 28936 STATIC int 28937 _bcm_xgs3_l3_intf_tnl_init_get(int unit, int ifindex, 28938 _bcm_tnl_init_data_t *tnl_info) 28939 { 28940 l3_max_entry_t l3_if_entry; /* Buffer to read interface info. */ 28941 _bcm_l3_intf_fields_t *fld; /* Interface table common fields. */ 28942 uint32 *l3_if_entry_p; /* Write buffer address. */ 28943 soc_mem_t mem; /* Interface table memory. */ 28944 28945 /* Input parameters check */ 28946 if (NULL == tnl_info) { 28947 return (BCM_E_PARAM); 28948 } 28949 28950 /* Get interface table memory. */ 28951 mem = BCM_XGS3_L3_MEM(unit, intf); 28952 28953 /* Zero the buffer. */ 28954 l3_if_entry_p = (uint32 *)&l3_if_entry; 28955 sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf)); 28956 28957 /* Read interface table entry by index. */ 28958 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ (unit, mem, ifindex, l3_if_entry_p)); 28959 28960 /* Extract interface information. */ 28961 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 28962 28963 /* Get tunnel index. */ 28964 if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) { 28965 tnl_info->tnl_idx = soc_mem_field32_get(unit, mem, 28966 l3_if_entry_p, fld->tnl_id); 28967 } 28968 28969 return (BCM_E_NONE); 28970 } 28971 28972 /* 28973 * Function: 28974 * _bcm_xgs3_l3_intf_tnl_init_set 28975 * Purpose: 28976 * Mark interface as tunnel initiator 28977 * Parameters: 28978 * unit - (IN)SOC unit number. 28979 * ifindex - (IN)Interface index. 28980 * tnl_info - (IN)Tunnel initiator entry params. 28981 * Returns: 28982 * BCM_E_XXX 28983 */ 28984 STATIC int 28985 _bcm_xgs3_l3_intf_tnl_init_set(int unit, int ifindex, 28986 _bcm_tnl_init_data_t *tnl_info) 28987 { 28988 l3_max_entry_t l3_if_entry; /* Buffer to read interface info. */ 28989 _bcm_l3_intf_fields_t *fld; /* Interface table common fields. */ 28990 uint32 *l3_if_entry_p; /* Write buffer address. */ 28991 soc_mem_t mem; /* Interface table memory. */ 28992 28993 /* Input parameters check */ 28994 if (NULL == tnl_info) { 28995 return (BCM_E_PARAM); 28996 } 28997 28998 /* Get interface table memory. */ 28999 mem = BCM_XGS3_L3_MEM(unit, intf); 29000 29001 /* Zero the buffer. */ 29002 l3_if_entry_p = (uint32 *)&l3_if_entry; 29003 sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf)); 29004 29005 /* Read interface table entry by index. */ 29006 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_READ (unit, mem, ifindex, l3_if_entry_p)); 29007 29008 /* Extract interface information. */ 29009 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 29010 29011 /* Get tunnel index. */ 29012 if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) { 29013 soc_mem_field32_set(unit, mem, l3_if_entry_p, fld->tnl_id, 29014 tnl_info->tnl_idx); 29015 } 29016 29017 /* Write entry back to hw. */ 29018 BCM_IF_ERROR_RETURN 29019 (BCM_XGS3_MEM_WRITE(unit, mem, ifindex, l3_if_entry_p)); 29020 29021 #ifdef BCM_FIREBOLT_SUPPORT 29022 if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, L3UC_TUNNEL_TYPEf)) { 29023 BCM_IF_ERROR_RETURN 29024 (_bcm_fb_nh_intf_is_tnl_update(unit, ifindex, tnl_info->tnl_idx)); 29025 } 29026 #endif /* BCM_FIREBOLT_SUPPORT */ 29027 return (BCM_E_NONE); 29028 } 29029 29030 /* 29031 * Function: 29032 * _bcm_xgs3_l3_intf_tnl_init_reset 29033 * Purpose: 29034 * Unmark interface as tunnel initiator 29035 * Parameters: 29036 * unit - (IN)SOC unit number. 29037 * ifindex - (IN)Interface index. 29038 * Returns: 29039 * BCM_E_XXX 29040 */ 29041 STATIC int 29042 _bcm_xgs3_l3_intf_tnl_init_reset(int unit, int ifindex) 29043 { 29044 l3_max_entry_t l3_if_entry; /* Buffer to read interface info. */ 29045 _bcm_l3_intf_fields_t *fld; /* Interface table common fields. */ 29046 uint32 *l3_if_entry_p; /* Write buffer address. */ 29047 soc_mem_t mem; /* Interface table memory. */ 29048 29049 /* Get interface table memory. */ 29050 mem = BCM_XGS3_L3_MEM(unit, intf); 29051 29052 /* Zero the buffer. */ 29053 l3_if_entry_p = (uint32 *)&l3_if_entry; 29054 sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf)); 29055 29056 /* Read interface table entry by index. */ 29057 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ (unit, mem, ifindex, l3_if_entry_p)); 29058 29059 /* Extract interface information. */ 29060 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 29061 29062 /* Get tunnel index. */ 29063 if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) { 29064 soc_mem_field32_set(unit, mem, l3_if_entry_p, fld->tnl_id, 0); 29065 } 29066 29067 /* Write entry back to hw. */ 29068 BCM_IF_ERROR_RETURN 29069 (BCM_XGS3_MEM_WRITE(unit, mem, ifindex, l3_if_entry_p)); 29070 29071 #ifdef BCM_FIREBOLT_SUPPORT 29072 if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, L3UC_TUNNEL_TYPEf)) { 29073 if (SOC_IS_FBX(unit)) { 29074 BCM_IF_ERROR_RETURN(_bcm_fb_nh_intf_is_tnl_update(unit, ifindex, 0)); 29075 } 29076 } 29077 #endif /* BCM_FIREBOLT_SUPPORT */ 29078 29079 return (BCM_E_NONE); 29080 29081 } 29082 29083 #ifdef BCM_TOMAHAWK3_SUPPORT 29084 int 29085 _bcm_xgs3_th3_nh_entry_parse(int unit, uint32 *ing_entry_ptr, 29086 uint32 *egr_entry_ptr, uint32 *egr_entry_2_ptr, uint32 index, 29087 bcm_l3_egress_t *nh_entry, uint8 *nh_ent_type) 29088 { 29089 int mod = 0; /* Module id value in hw. */ 29090 int port = 0; /* Port value in hw. */ 29091 int ent_type = 0; 29092 _bcm_l3_intf_cfg_t intf_info; 29093 int ret_val; 29094 int ing_ent_type = 0; 29095 int l3mc = 0; 29096 th3_mem_ING_L3_NEXT_HOP_t *ing_ent; 29097 th3_mem_EGR_L3_NEXT_HOP_t *egr_ent; 29098 th3_mem_EGR_L3_NEXT_HOP_2_t *egr2_ent; 29099 soc_mem_t mem; /* Table location memory. */ 29100 29101 ing_ent = (th3_mem_ING_L3_NEXT_HOP_t *)ing_entry_ptr; 29102 egr_ent = (th3_mem_EGR_L3_NEXT_HOP_t *)egr_entry_ptr; 29103 egr2_ent = (th3_mem_EGR_L3_NEXT_HOP_2_t *)egr_entry_2_ptr; 29104 29105 /* Zero buffers. */ 29106 bcm_l3_egress_t_init(nh_entry); 29107 29108 /* Check if next hop entry type is L3MC */ 29109 ent_type = egr_ent->ENTRY_TYPE; 29110 if (3 == ent_type) { 29111 /* Entry type is L3MC */ 29112 l3mc = 1; 29113 } 29114 29115 /* Check if next hop entry type is L3MC */ 29116 if (l3mc) { 29117 if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) { 29118 return _bcm_tr3_l3_ipmc_nh_entry_parse(unit, ing_entry_ptr, 29119 egr_entry_ptr, egr_entry_2_ptr, nh_entry); 29120 } 29121 } 29122 29123 /* Get next hop table memory location. */ 29124 29125 /* Extract next hop info. */ 29126 /* Get port trunk information. */ 29127 port = ing_ent->PORT_NUM; 29128 29129 if (ing_ent->T) { 29130 nh_entry->flags |= BCM_L3_TGID; 29131 port = ing_ent->PORT_NUM; 29132 } 29133 if (port & BCM_TGID_TRUNK_INDICATOR(unit)) { 29134 nh_entry->flags |= BCM_L3_TGID; 29135 } 29136 29137 if (ing_ent->COPY_TO_CPU) { 29138 nh_entry->flags |= BCM_L3_COPY_TO_CPU; 29139 } 29140 29141 if (ing_ent->DROP) { 29142 nh_entry->flags |= BCM_L3_DST_DISCARD; 29143 } 29144 29145 /* Map module/port to next hop entry format. */ 29146 BCM_IF_ERROR_RETURN 29147 (_bcm_xgs3_nh_map_hw_data_to_api(unit, port, mod, nh_entry)); 29148 29149 ing_ent_type = ing_ent->ENTRY_TYPE; 29150 if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) && (ing_ent_type != 2)) { 29151 /* Get vlan id. */ 29152 nh_entry->vlan = ing_ent->VLAN_ID; 29153 } 29154 29155 if (ent_type == 0) { /* L3 Unicast */ 29156 if (egr_ent->L3__L3_UC_VLAN_DISABLE) { 29157 nh_entry->flags |= BCM_L3_KEEP_VLAN; 29158 } 29159 if (egr_ent->L3__L3_UC_TTL_DISABLE) { 29160 nh_entry->flags |= BCM_L3_KEEP_TTL; 29161 } 29162 if (egr_ent->L3__L3_UC_DA_DISABLE) { 29163 nh_entry->flags |= BCM_L3_KEEP_DSTMAC; 29164 } 29165 if (egr_ent->L3__L3_UC_SA_DISABLE) { 29166 nh_entry->flags |= BCM_L3_KEEP_SRCMAC; 29167 } 29168 } 29169 29170 if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 29171 0x2 == ent_type && _BCM_L3_FIELD_ONLY == 29172 BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index)) { 29173 29174 nh_entry->flags2 |= BCM_L3_FLAGS2_FIELD_ONLY; 29175 29176 if (egr_ent->IFP_ACTIONS__L3_UC_VLAN_DISABLE) { 29177 nh_entry->flags |= BCM_L3_KEEP_VLAN; 29178 } 29179 29180 if (egr_ent->IFP_ACTIONS__L3_UC_TTL_DISABLE) { 29181 nh_entry->flags |= BCM_L3_KEEP_TTL; 29182 } 29183 29184 if (egr_ent->IFP_ACTIONS__L3_UC_DA_DISABLE) { 29185 nh_entry->flags |= BCM_L3_KEEP_DSTMAC; 29186 } 29187 29188 if (egr_ent->IFP_ACTIONS__L3_UC_SA_DISABLE) { 29189 nh_entry->flags |= BCM_L3_KEEP_SRCMAC; 29190 } 29191 } 29192 29193 /* Get interface index. */ 29194 if (egr_entry_2_ptr) { 29195 nh_entry->intf = egr2_ent->INTF_NUM; 29196 } 29197 29198 if (nh_entry->intf == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) { 29199 nh_entry->flags |= BCM_L3_L2TOCPU; 29200 } 29201 29202 if (BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) || (ing_ent_type == 2)) { 29203 /* Now get the vlan */ 29204 sal_memset(&intf_info, 0x0, sizeof(intf_info)); 29205 intf_info.l3i_index = nh_entry->intf; 29206 29207 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 29208 BCM_XGS3_L3_MODULE_LOCK(unit); 29209 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, 29210 &intf_info); 29211 BCM_XGS3_L3_MODULE_UNLOCK(unit); 29212 BCM_IF_ERROR_RETURN(ret_val); 29213 nh_entry->vlan = intf_info.l3i_vid; 29214 } 29215 } 29216 29217 /* Get mac address. */ 29218 soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, egr_entry_ptr, 29219 MAC_ADDRESSf, nh_entry->mac_addr); 29220 29221 if (nh_ent_type) { 29222 *nh_ent_type = (uint8)ent_type; 29223 } 29224 if (ent_type == 0x1) { /* == MPLS_MACDA_PROFILE */ 29225 int macda_idx = 0; 29226 egr_mac_da_profile_entry_t macda; 29227 egr_mpls_vc_and_swap_label_table_entry_t vc_swap_entry; 29228 int vc_swap_idx = -1; 29229 29230 if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) && 29231 (_BCM_L3_MPLS_PHP == 29232 BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index))) { 29233 nh_entry->flags2 |= BCM_L3_FLAGS2_MPLS_PHP; 29234 } 29235 29236 /* Get Index to MAC-DA-PROFILEm */ 29237 if (soc_feature(unit, soc_feature_mpls_enhanced)) { 29238 macda_idx = egr_ent->MPLS__MAC_DA_PROFILE_INDEX; 29239 } 29240 29241 /* Read entry from MAC-DA-PROFILEm */ 29242 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_MAC_DA_PROFILEm, 29243 MEM_BLOCK_ANY, macda_idx, &macda)); 29244 29245 /* Obtain Mac-Address */ 29246 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, 29247 &macda, MAC_ADDRESSf, nh_entry->mac_addr); 29248 29249 if ((vc_swap_idx > 0) && 29250 !soc_feature(unit, soc_feature_th3_style_simple_mpls)) { /* 0th entry is the default */ 29251 /* Read entry from EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm */ 29252 BCM_IF_ERROR_RETURN (soc_mem_read(unit, 29253 EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm, 29254 MEM_BLOCK_ANY, vc_swap_idx, &vc_swap_entry)); 29255 nh_entry->mpls_label = 29256 soc_EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm_field32_get(unit, 29257 &vc_swap_entry, 29258 MPLS_LABELf); 29259 } else { 29260 nh_entry->mpls_label = 29261 (egr_ent->MPLS__MPLS_LABEL_2_19 << 2) | 29262 (egr_ent->MPLS__MPLS_LABEL_0_1); 29263 } 29264 } 29265 29266 nh_entry->intf_class = egr_ent->L3__CLASS_ID; 29267 29268 /* Get next hop table memory location. */ 29269 mem = BCM_XGS3_L3_MEM(unit, nh); 29270 29271 if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 29272 (0x2 == ent_type) && _BCM_L3_FIELD_ONLY == 29273 BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index)) { 29274 29275 /* Get mac address. */ 29276 soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, egr_entry_ptr, 29277 IFP_ACTIONS__MAC_ADDRESSf, nh_entry->mac_addr); 29278 29279 29280 nh_entry->flags2 |= BCM_L3_FLAGS2_FIELD_ONLY; 29281 29282 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) { 29283 if (soc_mem_field32_get(unit, mem, egr_entry_ptr, 29284 IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) { 29285 nh_entry->flags |= BCM_L3_KEEP_VLAN; 29286 } 29287 } 29288 29289 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_TTL_DISABLEf)) { 29290 if (soc_mem_field32_get(unit, mem, egr_entry_ptr, 29291 IFP_ACTIONS__L3_UC_TTL_DISABLEf)) { 29292 nh_entry->flags |= BCM_L3_KEEP_TTL; 29293 } 29294 } 29295 29296 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_DA_DISABLEf)) { 29297 if (soc_mem_field32_get(unit, mem, egr_entry_ptr, 29298 IFP_ACTIONS__L3_UC_DA_DISABLEf)) { 29299 nh_entry->flags |= BCM_L3_KEEP_DSTMAC; 29300 } 29301 } 29302 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_SA_DISABLEf)) { 29303 if (soc_mem_field32_get(unit, mem, egr_entry_ptr, 29304 IFP_ACTIONS__L3_UC_SA_DISABLEf)) { 29305 nh_entry->flags |= BCM_L3_KEEP_SRCMAC; 29306 } 29307 } 29308 } 29309 return (BCM_E_NONE); 29310 } 29311 29312 #endif 29313 29314 /* 29315 * Function: 29316 * _bcm_xgs3_nh_entry_parse 29317 * Purpose: 29318 * Parse the NextHop table entry info. 29319 * Parameters: 29320 * unit - (IN) SOC unit number. 29321 * ing_entry_ptr - (IN) Ingress next hop table entry. 29322 * egr_entry_ptr - (IN) Egress next hop table entry. 29323 * index - (IN) Next hop index. 29324 * nh_entry - (OUT) Next hop entry info. 29325 * Returns: 29326 * BCM_E_XXX 29327 */ 29328 int 29329 _bcm_xgs3_nh_entry_parse(int unit, uint32 *ing_entry_ptr, 29330 uint32 *egr_entry_ptr, uint32 *egr_entry_2_ptr, uint32 index, bcm_l3_egress_t *nh_entry, uint8 *nh_ent_type) 29331 { 29332 _bcm_l3_nh_fields_t *fld; /* Next hop table common fields. */ 29333 uint32 *hw_entry_p; /* HW entry buffer pointer. */ 29334 soc_mem_t mem; /* Table location memory. */ 29335 #ifdef BCM_TOMAHAWK3_SUPPORT 29336 soc_mem_t mem2; /* Table location memory. */ 29337 #endif 29338 int mod = 0; /* Module id value in hw. */ 29339 int port = 0; /* Port value in hw. */ 29340 int ent_type = 0; 29341 #ifdef BCM_KATANA_SUPPORT 29342 int eh_tag_type = 0; 29343 int queue_id = 0; 29344 ing_queue_map_entry_t ing_queue_entry; 29345 #endif 29346 _bcm_l3_intf_cfg_t intf_info; 29347 int ret_val; 29348 #ifdef BCM_RIOT_SUPPORT 29349 uint32 nh_dest = 0; 29350 #endif 29351 int ing_ent_type = 0; 29352 29353 int l3mc = 0; 29354 #ifdef BCM_TRIDENT3_SUPPORT 29355 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID, dest = 0; 29356 int dvp_gport=0; 29357 #endif 29358 soc_field_t entry_type_field = 0; 29359 29360 #ifdef BCM_TOMAHAWK3_SUPPORT 29361 /* It's ok to use even alpm is off */ 29362 if (SOC_IS_TOMAHAWK3(unit)) { 29363 return _bcm_xgs3_th3_nh_entry_parse(unit, ing_entry_ptr, egr_entry_ptr, 29364 egr_entry_2_ptr, index, nh_entry, nh_ent_type); 29365 } 29366 #endif 29367 29368 if (SOC_IS_TRIDENT3X(unit)) { 29369 entry_type_field = DATA_TYPEf; 29370 } else { 29371 entry_type_field = ENTRY_TYPEf; 29372 } 29373 29374 hw_entry_p = ing_entry_ptr; 29375 29376 /* Zero buffers. */ 29377 bcm_l3_egress_t_init(nh_entry); 29378 29379 29380 /* Check if next hop entry type is L3MC */ 29381 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, entry_type_field)) { 29382 if (SOC_IS_TOMAHAWK3(unit)) { 29383 if (3 == soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 29384 egr_entry_ptr, nh_entry_type_field[unit])) { 29385 /* Entry type is L3MC */ 29386 l3mc = 1; 29387 } 29388 } else if (7 == soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_entry_ptr, 29389 nh_entry_type_field[unit])) { /* Entry type is L3MC */ 29390 l3mc = 1; 29391 } 29392 } 29393 29394 /* Check if next hop entry type is L3MC */ 29395 if (l3mc) { 29396 #ifdef BCM_TRIUMPH3_SUPPORT 29397 if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) { 29398 return _bcm_tr3_l3_ipmc_nh_entry_parse(unit, ing_entry_ptr, 29399 egr_entry_ptr, egr_entry_2_ptr, nh_entry); 29400 } else 29401 #endif /* BCM_TRIUMPH3_SUPPORT */ 29402 { 29403 /* GH support entry type=7 through the feature at 29404 * 'soc_feature_l3mc_use_egress_next_hop' and the flow will 29405 * be proceeded later. 29406 */ 29407 if (!soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) { 29408 return BCM_E_UNAVAIL; 29409 } 29410 } 29411 } 29412 29413 /* Get next hop table memory location. */ 29414 mem = BCM_XGS3_L3_MEM(unit, nh); 29415 29416 /* Extract next hop fields information. */ 29417 fld = (_bcm_l3_nh_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, nh); 29418 29419 /* Extract next hop info. */ 29420 29421 #ifdef BCM_RIOT_SUPPORT 29422 if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 29423 29424 nh_dest = soc_mem_field32_get(unit, mem, hw_entry_p, DESTINATIONf); 29425 bcmi_get_port_from_destination(unit, nh_dest, nh_entry); 29426 if (!(_bcm_vp_is_vfi_type(unit, nh_entry->port)) && 29427 (!(nh_entry->flags & BCM_L3_TGID))) { 29428 29429 mod = BCM_L3_DGLP_MODULE_ID_GET(nh_entry->port); 29430 port = BCM_L3_DGLP_PORT_GET(nh_entry->port); 29431 } else { 29432 mod = 0; 29433 port = nh_entry->port; 29434 } 29435 nh_entry->port = 0; 29436 } else 29437 #endif 29438 { 29439 #ifdef BCM_TRIDENT3_SUPPORT 29440 if (SOC_IS_TRIDENT3X(unit)) { 29441 dest = soc_mem_field32_dest_get(unit, mem, hw_entry_p, 29442 fld->dest, &dest_type); 29443 if (dest_type == SOC_MEM_FIF_DEST_LAG) { 29444 nh_entry->flags |= BCM_L3_TGID; 29445 port = (dest & SOC_MEM_FIF_DGPP_TGID_MASK); 29446 } else if (dest_type == SOC_MEM_FIF_DEST_DGPP) { 29447 port = (dest & SOC_MEM_FIF_DGPP_PORT_MASK); 29448 mod = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >> 29449 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS; 29450 } else if (dest_type == SOC_MEM_FIF_DEST_DVP) { 29451 _bcm_vp_encode_gport(unit, dest, &dvp_gport); 29452 nh_entry->port = dvp_gport; 29453 port = dvp_gport; 29454 } else if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 29455 _BCM_MULTICAST_GROUP_SET(nh_entry->mc_group, 29456 _BCM_MULTICAST_TYPE_L3, dest); 29457 nh_entry->flags2 |= BCM_L3_FLAGS2_MC_GROUP; 29458 } 29459 } else 29460 #endif 29461 { 29462 /* Get port trunk information. */ 29463 if (!SOC_IS_TOMAHAWK3(unit)) { 29464 mod = soc_mem_field32_get(unit, mem, hw_entry_p, fld->module); 29465 } 29466 port = soc_mem_field32_get(unit, mem, hw_entry_p, fld->port_tgid); 29467 29468 #ifdef BCM_TRX_SUPPORT 29469 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 29470 if (soc_mem_field32_get(unit, mem, hw_entry_p, Tf)) { 29471 nh_entry->flags |= BCM_L3_TGID; 29472 port = soc_mem_field32_get(unit, mem, hw_entry_p, TGIDf); 29473 } 29474 } 29475 #endif /* BCM_TRX_SUPPORT */ 29476 if (port & BCM_TGID_TRUNK_INDICATOR(unit)) { 29477 nh_entry->flags |= BCM_L3_TGID; 29478 } 29479 } 29480 } 29481 29482 #ifdef BCM_TRX_SUPPORT 29483 if (SOC_MEM_FIELD_VALID(unit, mem, COPY_TO_CPUf)) { 29484 if (soc_mem_field32_get(unit, mem, hw_entry_p, COPY_TO_CPUf)) { 29485 nh_entry->flags |= BCM_L3_COPY_TO_CPU; 29486 } 29487 } 29488 29489 if (SOC_MEM_FIELD_VALID(unit, mem, DROPf)) { 29490 if (soc_mem_field32_get(unit, mem, hw_entry_p, DROPf)) { 29491 nh_entry->flags |= BCM_L3_DST_DISCARD; 29492 } 29493 } 29494 29495 #endif /* BCM_TRX_SUPPORT */ 29496 29497 /* Map module/port to next hop entry format. */ 29498 BCM_IF_ERROR_RETURN 29499 (_bcm_xgs3_nh_map_hw_data_to_api(unit, port, mod, nh_entry)); 29500 29501 if (SOC_MEM_FIELD_VALID(unit, mem, ENTRY_TYPEf)) { 29502 ing_ent_type = soc_mem_field32_get(unit, mem, hw_entry_p, ENTRY_TYPEf); 29503 } 29504 if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) && (ing_ent_type != 2)) { 29505 #ifdef BCM_FIREBOLT_SUPPORT 29506 if (SOC_IS_FBX(unit)) { 29507 /* Get vlan id. */ 29508 nh_entry->vlan = soc_mem_field32_get(unit, mem, hw_entry_p, VLAN_IDf); 29509 } 29510 #endif /* BCM_FIREBOLT_SUPPORT */ 29511 } 29512 29513 hw_entry_p = egr_entry_ptr; 29514 mem = EGR_L3_NEXT_HOPm; 29515 #ifdef BCM_TOMAHAWK3_SUPPORT 29516 mem2 = EGR_L3_NEXT_HOP_2m; 29517 #endif 29518 29519 if (SOC_MEM_FIELD_VALID(unit, mem, nh_entry_type_field[unit])) { 29520 ent_type = soc_mem_field32_get(unit, mem, hw_entry_p, nh_entry_type_field[unit]); 29521 } 29522 #ifdef BCM_TRIDENT3_SUPPORT 29523 if (soc_feature(unit, soc_feature_flex_flow) && 29524 (BCMI_L3_NH_FLEX_VIEW(ent_type))) { 29525 29526 return _bcm_td3_l3_flex_nh_entry_parse(unit, egr_entry_ptr, 29527 index, nh_entry); 29528 } 29529 #endif 29530 29531 if (ent_type == 0) { /* L3 Unicast */ 29532 #ifdef BCM_TRIUMPH2_SUPPORT 29533 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_VLAN_DISABLEf)) { 29534 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29535 L3__L3_UC_VLAN_DISABLEf)) { 29536 nh_entry->flags |= BCM_L3_KEEP_VLAN; 29537 } 29538 } 29539 29540 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_TTL_DISABLEf)) { 29541 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29542 L3__L3_UC_TTL_DISABLEf)) { 29543 nh_entry->flags |= BCM_L3_KEEP_TTL; 29544 } 29545 } 29546 29547 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_DA_DISABLEf)) { 29548 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29549 L3__L3_UC_DA_DISABLEf)) { 29550 nh_entry->flags |= BCM_L3_KEEP_DSTMAC; 29551 } 29552 } 29553 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_SA_DISABLEf)) { 29554 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29555 L3__L3_UC_SA_DISABLEf)) { 29556 nh_entry->flags |= BCM_L3_KEEP_SRCMAC; 29557 } 29558 } 29559 #endif /* BCM_TRIUMPH2_SUPPORT */ 29560 } 29561 29562 #ifdef BCM_TRIDENT_SUPPORT 29563 if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 29564 (((SOC_IS_TOMAHAWK3(unit)) && (0x2 == ent_type)) || (0x6 == ent_type)) && _BCM_L3_FIELD_ONLY == 29565 BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index)) { 29566 uint8 tag_action = 0; 29567 uint32 tag_buffer = 0; 29568 29569 nh_entry->flags2 |= BCM_L3_FLAGS2_FIELD_ONLY; 29570 29571 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) { 29572 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29573 IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) { 29574 nh_entry->flags |= BCM_L3_KEEP_VLAN; 29575 } 29576 } 29577 29578 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_TTL_DISABLEf)) { 29579 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29580 IFP_ACTIONS__L3_UC_TTL_DISABLEf)) { 29581 nh_entry->flags |= BCM_L3_KEEP_TTL; 29582 } 29583 } 29584 29585 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_DA_DISABLEf)) { 29586 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29587 IFP_ACTIONS__L3_UC_DA_DISABLEf)) { 29588 nh_entry->flags |= BCM_L3_KEEP_DSTMAC; 29589 } 29590 } 29591 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_SA_DISABLEf)) { 29592 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29593 IFP_ACTIONS__L3_UC_SA_DISABLEf)) { 29594 nh_entry->flags |= BCM_L3_KEEP_SRCMAC; 29595 } 29596 } 29597 29598 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__VNTAGf)) { 29599 tag_buffer = soc_mem_field32_get(unit, mem, hw_entry_p, 29600 IFP_ACTIONS__VNTAGf); 29601 } 29602 29603 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__VNTAG_ACTIONf)) { 29604 tag_action = soc_mem_field32_get(unit, mem, hw_entry_p, 29605 IFP_ACTIONS__VNTAG_ACTIONf); 29606 if (tag_action == 1) { 29607 nh_entry->vntag.direction = (tag_buffer >> 31) & 0x1; 29608 nh_entry->vntag.pointer = (tag_buffer >> 30) & 0x1; 29609 nh_entry->vntag.dst_vif = (tag_buffer >> 16) & 0x3fff; 29610 nh_entry->vntag.loop = (tag_buffer >> 15) & 0x1; 29611 nh_entry->vntag.src_vif = tag_buffer & 0xfff; 29612 nh_entry->vntag_action = bcmVnTagActionChange; 29613 } else if (tag_action == 2) { 29614 nh_entry->etag.pcp = (tag_buffer >> 29) & 0x7; 29615 nh_entry->etag.de = (tag_buffer >> 28) & 0x1; 29616 nh_entry->etag.src_vid = (tag_buffer >> 16) & 0xfff; 29617 nh_entry->etag.vid = tag_buffer & 0x3fff; 29618 nh_entry->etag_action = bcmETagActionChange; 29619 } else if (tag_action == 3) { 29620 if (tag_buffer == 0) { 29621 nh_entry->vntag_action = bcmVnTagActionDelete; 29622 } else { 29623 nh_entry->etag_action = bcmETagActionDelete; 29624 } 29625 } 29626 } 29627 29628 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 29629 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__SWAP_MAC_DA_SAf)) { 29630 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29631 IFP_ACTIONS__SWAP_MAC_DA_SAf)) { 29632 nh_entry->flags2 |= BCM_L3_FLAGS2_SRC_DST_MAC_SWAP; 29633 nh_entry->flags &= ~BCM_L3_KEEP_DSTMAC; 29634 nh_entry->flags &= ~BCM_L3_KEEP_SRCMAC; 29635 } 29636 } 29637 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 29638 } 29639 #endif 29640 29641 /* Get interface index. */ 29642 #ifdef BCM_TOMAHAWK3_SUPPORT 29643 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m) && egr_entry_2_ptr) { 29644 nh_entry->intf = 29645 soc_mem_field32_get(unit, mem2, egr_entry_2_ptr, fld->ifindex); 29646 } else 29647 #endif 29648 { 29649 nh_entry->intf = 29650 soc_mem_field32_get(unit, mem, hw_entry_p, fld->ifindex); 29651 } 29652 if (SOC_MEM_FIELD_VALID(unit, mem, MPLS__MEPIDf)) { 29653 nh_entry->oam_global_context_id = 29654 soc_mem_field32_get(unit, mem, hw_entry_p, 29655 MPLS__MEPIDf); 29656 } 29657 if (nh_entry->intf == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) { 29658 nh_entry->flags |= BCM_L3_L2TOCPU; 29659 } 29660 29661 #ifdef BCM_TRX_SUPPORT 29662 if (SOC_MEM_FIELD_VALID(unit, mem, entry_type_field)) { 29663 /* 29664 * Entry type is SD TAG actions. 29665 * no interface is associated with it. 29666 * Mark the interface as 0. 29667 * else it picks up some random value and tries to look for it. 29668 */ 29669 if (soc_mem_field32_get(unit, mem, hw_entry_p, entry_type_field) == 2) { 29670 nh_entry->intf = 0; 29671 } 29672 } 29673 #endif 29674 29675 if (BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) || (ing_ent_type == 2)) { 29676 /* Now get the vlan */ 29677 sal_memset(&intf_info, 0x0, sizeof(intf_info)); 29678 intf_info.l3i_index = nh_entry->intf; 29679 29680 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 29681 BCM_XGS3_L3_MODULE_LOCK(unit); 29682 ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, 29683 &intf_info); 29684 BCM_XGS3_L3_MODULE_UNLOCK(unit); 29685 BCM_IF_ERROR_RETURN(ret_val); 29686 nh_entry->vlan = intf_info.l3i_vid; 29687 } 29688 } 29689 29690 /* Get mac address. */ 29691 soc_mem_mac_addr_get(unit, mem, hw_entry_p, 29692 fld->mac_addr, nh_entry->mac_addr); 29693 29694 #ifdef BCM_TRX_SUPPORT 29695 if (SOC_MEM_FIELD_VALID(unit, mem, entry_type_field)) { 29696 int macda_idx; 29697 egr_mac_da_profile_entry_t macda; 29698 egr_mpls_vc_and_swap_label_table_entry_t vc_swap_entry; 29699 int entry_type; 29700 int vc_swap_idx = -1; 29701 29702 entry_type = soc_mem_field32_get(unit, mem, hw_entry_p, entry_type_field); 29703 if (nh_ent_type) { 29704 *nh_ent_type = (uint8)entry_type; 29705 } 29706 if (entry_type == 0) { /* L3 unicast */ 29707 #ifdef BCM_TRIDENT2_SUPPORT 29708 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 29709 bcm_if_t encap_id = soc_mem_field32_get(unit, mem, 29710 hw_entry_p, L3__DVPf); 29711 if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) { 29712 if (soc_mem_field32_get(unit, mem, hw_entry_p, L3__DVP_VALIDf)) { 29713 nh_entry->encap_id = encap_id; 29714 } 29715 } else { 29716 /* TD2+ onwards, the DVP_VALID bit is implicit to DVP.. 29717 Zero = invalid, Non-Zero = valid */ 29718 nh_entry->encap_id = encap_id; 29719 } 29720 29721 if (soc_mem_field_valid(unit, mem, L3__HG_HDR_SELf)) { 29722 if (!_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeNiv) && 29723 !_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeExtender) && 29724 !_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeVlan) && 29725 !_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeMpls) && 29726 soc_mem_field32_get(unit, mem, hw_entry_p, L3__HG_HDR_SELf)) { 29727 nh_entry->flags2 |= BCM_L3_FLAGS2_NON_PROXY_MODE; 29728 } 29729 } 29730 } 29731 #endif /* BCM_TRIDENT2_SUPPORT */ 29732 } else if (entry_type == 0x1) { /* == MPLS_MACDA_PROFILE */ 29733 29734 if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) && 29735 (_BCM_L3_MPLS_PHP == 29736 BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index))) { 29737 nh_entry->flags2 |= BCM_L3_FLAGS2_MPLS_PHP; 29738 } 29739 29740 /* Get Index to MAC-DA-PROFILEm */ 29741 if (soc_feature(unit, soc_feature_mpls_enhanced)) { 29742 macda_idx = soc_mem_field32_get(unit, mem, hw_entry_p, 29743 MPLS__MAC_DA_PROFILE_INDEXf); 29744 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, MPLS__VC_AND_SWAP_INDEXf)) { 29745 vc_swap_idx = soc_mem_field32_get(unit, mem, hw_entry_p, 29746 MPLS__VC_AND_SWAP_INDEXf); 29747 } 29748 } else { 29749 macda_idx = soc_mem_field32_get(unit, mem, hw_entry_p, 29750 MAC_DA_PROFILE_INDEXf); 29751 vc_swap_idx = soc_mem_field32_get(unit, mem, hw_entry_p, 29752 VC_AND_SWAP_INDEXf); 29753 } 29754 29755 /* Read entry from MAC-DA-PROFILEm */ 29756 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm, 29757 MEM_BLOCK_ANY, macda_idx, &macda)); 29758 29759 /* Obtain Mac-Address */ 29760 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, 29761 &macda, MAC_ADDRESSf, nh_entry->mac_addr); 29762 29763 if ((vc_swap_idx > 0) && 29764 !soc_feature(unit, soc_feature_th3_style_simple_mpls)) { /* 0th entry is the default */ 29765 /* Read entry from EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm */ 29766 BCM_IF_ERROR_RETURN (soc_mem_read(unit, 29767 EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm, 29768 MEM_BLOCK_ANY, vc_swap_idx, &vc_swap_entry)); 29769 nh_entry->mpls_label = 29770 soc_EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm_field32_get(unit, 29771 &vc_swap_entry, 29772 MPLS_LABELf); 29773 } else if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) { 29774 nh_entry->mpls_label = 29775 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 29776 egr_entry_ptr, 29777 MPLS__MPLS_LABELf); 29778 } 29779 29780 29781 } else if (entry_type == 0x4) { /* == WLAN PROFILE */ 29782 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT) 29783 if (soc_feature(unit, soc_feature_wlan)) { 29784 nh_entry->encap_id = soc_mem_field32_get(unit, mem, 29785 hw_entry_p, WLAN__DVPf); 29786 } 29787 #endif /* TRIUMPH2_SUPPORT || TRIUMPH3_SUPPORT */ 29788 } 29789 #ifdef BCM_GREYHOUND2_SUPPORT 29790 if (soc_feature(unit, soc_feature_vxlan_lite)) { 29791 if (entry_type == 0xa) { 29792 /* Get Index to MAC-DA-PROFILEm */ 29793 macda_idx = soc_mem_field32_get(unit, mem, hw_entry_p, 29794 VXLAN__MAC_DA_PROFILE_INDEXf); 29795 /* Read entry from MAC-DA-PROFILEm */ 29796 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm, 29797 MEM_BLOCK_ANY, macda_idx, &macda)); 29798 /* Obtain Mac-Address */ 29799 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, 29800 &macda, MAC_ADDRESSf, nh_entry->mac_addr); 29801 } 29802 } 29803 #endif /* BCM_GREYHOUND2_SUPPORT */ 29804 29805 #ifdef BCM_GREYHOUND_SUPPORT 29806 if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) { 29807 if (entry_type == 0x7) { /* == L3MC */ 29808 nh_entry->flags |= BCM_L3_IPMC; 29809 29810 if (!(soc_mem_field32_get(unit, mem, hw_entry_p, 29811 L3MC__L3MC_USE_CONFIGURED_MACf))) { 29812 nh_entry->flags |= BCM_L3_KEEP_DSTMAC; 29813 } 29814 29815 /* MAC Addr field need be re-programmed for L3MC entry type. 29816 * 29817 * Note : the reason for MAC Addr re-program 29818 * MAC Addr field in GH's EGR_L3_NEXT_HOP entry at L3MC view 29819 * is not compatiable with toher entry type. 29820 */ 29821 soc_mem_mac_addr_get(unit, mem, hw_entry_p, 29822 L3MC__MAC_ADDRESSf, nh_entry->mac_addr); 29823 } 29824 } 29825 #endif /* BCM_GREYHOUND_SUPPORT */ 29826 } 29827 29828 #ifdef BCM_TRIUMPH3_SUPPORT 29829 if (SOC_MEM_FIELD_VALID(unit, mem, L3__CLASS_IDf)) { 29830 nh_entry->intf_class = 29831 soc_mem_field32_get(unit, mem, hw_entry_p, L3__CLASS_IDf); 29832 } 29833 #endif /* BCM_TRIUMPH3_SUPPORT */ 29834 29835 #endif /* BCM_TRX_SUPPORT */ 29836 29837 #ifdef BCM_TOMAHAWK_SUPPORT 29838 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 29839 if (nh_entry->encap_id > 0 && 29840 nh_entry->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) { 29841 if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeNiv) || 29842 _bcm_vp_used_get(unit, nh_entry->encap_id, 29843 _bcmVpTypeExtender)) { 29844 if (SOC_MEM_FIELD_VALID(unit, mem, L3__HG_VNTAG_MODIFY_ENABLEf)) { 29845 if (soc_mem_field32_get(unit, mem, hw_entry_p, 29846 L3__HG_VNTAG_MODIFY_ENABLEf)) { 29847 nh_entry->flags2 |= BCM_L3_FLAGS2_NIV_ENCAP_LOCAL; 29848 } 29849 } 29850 } 29851 } 29852 } 29853 #endif /* BCM_TOMAHAWK_SUPPORT */ 29854 29855 #ifdef BCM_KATANA_SUPPORT 29856 if (soc_feature(unit, soc_feature_extended_queueing)) { 29857 mem = BCM_XGS3_L3_MEM(unit, nh); 29858 queue_id = soc_mem_field32_get(unit, mem, ing_entry_ptr, 29859 EH_QUEUE_TAGf); 29860 if (SOC_MEM_FIELD_VALID(unit, mem, EH_TAG_TYPEf)) { 29861 eh_tag_type = soc_mem_field32_get(unit, mem, ing_entry_ptr, 29862 EH_TAG_TYPEf); 29863 if (eh_tag_type == EH_TAG_TYPE_ING_QUEUE_MAP) { 29864 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, ING_QUEUE_MAPm, 29865 queue_id, &ing_queue_entry)); 29866 nh_entry->qos_map_id = 29867 soc_mem_field32_get(unit, ING_QUEUE_MAPm, 29868 &ing_queue_entry, QUEUE_OFFSET_PROFILE_INDEXf); 29869 nh_entry->flags |= BCM_L3_QUEUE_MAP; 29870 29871 queue_id = soc_mem_field32_get(unit, ING_QUEUE_MAPm, 29872 &ing_queue_entry, QUEUE_SET_BASEf); 29873 } 29874 if ((eh_tag_type == EH_TAG_TYPE_EXPLICT_QUEUE) || 29875 (eh_tag_type == EH_TAG_TYPE_ING_QUEUE_MAP)) { 29876 nh_entry->qos_map_id |= (5 << 10); 29877 } 29878 } 29879 } 29880 #endif /* BCM_KATANA_SUPPORT */ 29881 29882 #ifdef BCM_TRIDENT2_SUPPORT 29883 if (soc_feature(unit, soc_feature_fcoe) && 29884 (ent_type == 0x8) && (_BCM_L3_FCOE_ONLY == 29885 BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index))) { 29886 nh_entry->flags2 |= BCM_L3_FLAGS2_FCOE_ONLY; 29887 } 29888 #endif 29889 29890 return (BCM_E_NONE); 29891 } 29892 /* 29893 * Function: 29894 * _bcm_xgs3_nh_get 29895 * Purpose: 29896 * Read the NextHop table info given index. 29897 * Parameters: 29898 * unit - (IN) SOC unit number. 29899 * idx - (IN) Table index to read. 29900 * nh_entry - (OUT) Next hop entry info. 29901 * Returns: 29902 * BCM_E_XXX 29903 */ 29904 STATIC int 29905 _bcm_xgs3_nh_get(int unit, int idx, bcm_l3_egress_t *nh_entry) 29906 { 29907 uint32 hw_entry[SOC_MAX_MEM_WORDS]; /* Buffer to fill nh entry. */ 29908 uint32 hw_entry_null[SOC_MAX_MEM_WORDS]; /* Buffer to fill nh entry. */ 29909 egr_l3_next_hop_entry_t egr_entry; /* Egress next hop entry. */ 29910 egr_l3_next_hop_entry_t egr_entry_null; /* Egress next hop entry. */ 29911 int found_null_entry = 0; 29912 egr_l3_next_hop_2_entry_t egr_entry_2; 29913 29914 /* Input parameters check */ 29915 if (NULL == nh_entry) { 29916 return (BCM_E_PARAM); 29917 } 29918 29919 /* Zero buffers. */ 29920 sal_memset(hw_entry, 0, WORDS2BYTES(SOC_MAX_MEM_WORDS)); 29921 sal_memset(hw_entry_null, 0, WORDS2BYTES(SOC_MAX_MEM_WORDS)); 29922 sal_memset(&egr_entry_null, 0, sizeof(egr_entry_null)); 29923 29924 /* Read ingress next hop entry. */ 29925 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, BCM_XGS3_L3_MEM(unit, nh), 29926 idx, &hw_entry)); 29927 29928 #ifdef BCM_FIREBOLT_SUPPORT 29929 if (SOC_IS_FBX(unit)) { 29930 sal_memset(&egr_entry, 0, sizeof(egr_l3_next_hop_entry_t)); 29931 29932 /* Read egress next hop entry. */ 29933 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOPm, 29934 idx, &egr_entry)); 29935 29936 #ifdef BCM_TOMAHAWK3_SUPPORT 29937 if (SOC_IS_TOMAHAWK3(unit)) { 29938 sal_memset(&egr_entry_2, 0, sizeof(egr_l3_next_hop_2_entry_t)); 29939 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOP_2m, 29940 idx, &egr_entry_2)); 29941 } 29942 #endif 29943 /* Now compare whether both the entries are null */ 29944 if (!sal_memcmp(hw_entry, hw_entry_null, BCM_XGS3_L3_ENT_SZ(unit, nh)) && 29945 !sal_memcmp(&egr_entry, &egr_entry_null, sizeof(egr_entry))) { 29946 found_null_entry = 1; 29947 } 29948 } 29949 #endif /* BCM_FIREBOLT_SUPPORT */ 29950 if (found_null_entry == 0) { 29951 BCM_IF_ERROR_RETURN( 29952 _bcm_xgs3_nh_entry_parse(unit, (uint32 *)&hw_entry, 29953 (uint32 *)&egr_entry, (uint32 *)&egr_entry_2, idx, nh_entry, NULL)); 29954 } else { 29955 bcm_l3_egress_t_init(nh_entry); 29956 } 29957 return (BCM_E_NONE); 29958 } 29959 29960 /* 29961 * Function: 29962 * _bcm_xgs3_nh_del 29963 * Purpose: 29964 * Delete next hop entry from the chip. 29965 * Parameters: 29966 * unit - (IN)SOC unit number. 29967 * idx - (IN)Deleted entry index. 29968 * Returns: 29969 * BCM_E_XXX 29970 */ 29971 STATIC int 29972 _bcm_xgs3_nh_del(int unit, int idx, void *info) 29973 { 29974 uint32 hw_entry[SOC_MAX_MEM_WORDS];/* Buffer to fill nh entry. */ 29975 soc_mem_t mem; /* Table memory. */ 29976 int rv; /* Operation return status. */ 29977 int first_error = BCM_E_NONE; /* First error occured. */ 29978 29979 /* Get table memory. */ 29980 mem = BCM_XGS3_L3_MEM(unit, nh); 29981 #ifdef BCM_RIOT_SUPPORT 29982 if (BCMI_RIOT_IS_ENABLED(unit)) { 29983 BCM_IF_ERROR_RETURN(bcmi_l3_nh_assoc_ol_ul_link_delete(unit, idx)); 29984 } 29985 #endif 29986 #if defined(BCM_TOMAHAWK_SUPPORT) 29987 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 29988 BCM_IF_ERROR_RETURN(_bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear(unit, idx)); 29989 } 29990 #endif 29991 #if defined(BCM_TOMAHAWK_SUPPORT) 29992 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 29993 BCM_IF_ERROR_RETURN(_bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear(unit, idx)); 29994 } 29995 #endif 29996 #if defined(BCM_TRIDENT3_SUPPORT) 29997 /* Release MAC_DA_PROFILE if used */ 29998 if (soc_feature(unit, soc_feature_large_scale_nat)) { 29999 BCM_IF_ERROR_RETURN( 30000 bcm_td3_ipmc_egr_nh_mac_da_profile_entry_delete(unit, idx)); 30001 } 30002 #endif /* BCM_TRIDENT3_SUPPORT */ 30003 30004 /* Zero write buffer. */ 30005 sal_memset(&hw_entry, 0, SOC_MAX_MEM_WORDS *sizeof(uint32)); 30006 30007 /* Write next hop entry. */ 30008 rv = BCM_XGS3_MEM_WRITE(unit, mem, idx, &hw_entry); 30009 if (rv < 0) { 30010 first_error = rv; 30011 } 30012 30013 #ifdef BCM_FIREBOLT_SUPPORT 30014 if (SOC_IS_FBX(unit)) { 30015 /* Write egress next hop entry. */ 30016 mem = EGR_L3_NEXT_HOPm; 30017 rv = BCM_XGS3_MEM_WRITE(unit, mem, idx, &hw_entry); 30018 if ((rv < 0) && (first_error == BCM_E_NONE)) { 30019 first_error = rv; 30020 } 30021 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 30022 defined(BCM_TRX_SUPPORT) 30023 /* Write initial next hop table. */ 30024 mem = INITIAL_ING_L3_NEXT_HOPm; 30025 if (!SOC_MEM_IS_VALID(unit, mem) || !soc_mem_index_max(unit, mem)) { 30026 return (first_error); 30027 } 30028 30029 /* Write buffer to hw. */ 30030 rv = BCM_XGS3_MEM_WRITE(unit, mem, idx, &hw_entry); 30031 if ((rv < 0) && (first_error == BCM_E_NONE)) { 30032 first_error = rv; 30033 } 30034 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 30035 } 30036 #endif /* BCM_FIREBOLT_SUPPORT */ 30037 30038 return first_error; 30039 } 30040 30041 /* 30042 * Function: 30043 * _bcm_xgs3_nh_update_match 30044 * Purpose: 30045 * Update/Show/Delete all entries in nh table matching a certain rule. 30046 * Parameters: 30047 * unit - (IN)SOC unit number. 30048 * trv_data - (IN)Delete pattern + compare,act,notify routines. 30049 * Returns: 30050 * BCM_E_XXX 30051 */ 30052 STATIC int 30053 _bcm_xgs3_nh_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 30054 { 30055 bcm_l3_egress_t nh_entry; /* Next hop entry info. */ 30056 uint32 *ing_entry_ptr; /* Ingress next hop entry pointer.*/ 30057 char *ing_tbl_ptr; /* Dma table pointer. */ 30058 int cmp_result; /* Test routine result. */ 30059 soc_mem_t mem, nhmem; /* Next hop memory. */ 30060 int idx; /* Iteration index. */ 30061 #ifdef BCM_FIREBOLT_SUPPORT 30062 char *egr_tbl_ptr = NULL; /* Dma egress nh table pointer. */ 30063 #ifdef BCM_TOMAHAWK3_SUPPORT 30064 char *egr_tbl_2_ptr = NULL; /* Dma egress nh table pointer. */ 30065 #endif 30066 #endif /* BCM_FIREBOLT_SUPPORT */ 30067 uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pinter. */ 30068 uint32 *egr_entry_2_ptr = NULL; /* Egress next hop entry pinter. */ 30069 int rv = BCM_E_NONE; /* Operation return status. */ 30070 30071 /* Get next table memory. */ 30072 mem = BCM_XGS3_L3_MEM(unit, nh); 30073 nhmem = EGR_L3_NEXT_HOPm; 30074 30075 /* Table DMA the nhtable to software copy */ 30076 BCM_IF_ERROR_RETURN 30077 (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl", 30078 &ing_tbl_ptr, NULL)); 30079 30080 #ifdef BCM_FIREBOLT_SUPPORT 30081 if (SOC_IS_FBX(unit)) { 30082 /* Read egress next hop entry. */ 30083 rv = bcm_xgs3_l3_tbl_dma(unit, nhmem, 30084 sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl", 30085 &egr_tbl_ptr, NULL); 30086 if (rv < 0) { 30087 soc_cm_sfree(unit, egr_tbl_ptr); 30088 return rv; 30089 } 30090 30091 #ifdef BCM_TOMAHAWK3_SUPPORT 30092 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 30093 /* Read egress next hop entry. */ 30094 rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOP_2m, 30095 sizeof(egr_l3_next_hop_2_entry_t), "egr_nh_tbl", 30096 &egr_tbl_2_ptr, NULL); 30097 30098 if (rv < 0) { 30099 soc_cm_sfree(unit, egr_tbl_2_ptr); 30100 return rv; 30101 } 30102 } 30103 #endif 30104 30105 } 30106 #endif /* BCM_FIREBOLT_SUPPORT */ 30107 30108 for (idx = 0; idx < BCM_XGS3_L3_NH_TBL_SIZE(unit); idx++) { 30109 /* Skip unused entries. */ 30110 if (!BCM_XGS3_L3_ENT_REF_CNT (BCM_XGS3_L3_TBL_PTR(unit, next_hop), 30111 idx)) { 30112 continue; 30113 } 30114 30115 /* Skip trap to CPU entry internally installed entry. */ 30116 if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) { 30117 continue; 30118 } 30119 30120 /* Skip BLACK_HOLE entry internally installed entry. */ 30121 if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) == idx) { 30122 continue; 30123 } 30124 30125 /* Calculate entry ofset. */ 30126 ing_entry_ptr = 30127 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx); 30128 30129 #ifdef BCM_FIREBOLT_SUPPORT 30130 if (SOC_IS_FBX(unit)) { 30131 int entry_type; 30132 30133 /* Read egress next hop entry. */ 30134 egr_entry_ptr = 30135 soc_mem_table_idx_to_pointer(unit, nhmem, 30136 uint32 *, egr_tbl_ptr, idx); 30137 #ifdef BCM_TOMAHAWK3_SUPPORT 30138 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 30139 egr_entry_2_ptr = 30140 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOP_2m, 30141 uint32 *, egr_tbl_2_ptr, idx); 30142 } 30143 #endif 30144 if (SOC_MEM_FIELD_VALID(unit, nhmem, nh_entry_type_field[unit])) { 30145 entry_type = soc_mem_field32_get(unit, nhmem, 30146 egr_entry_ptr, nh_entry_type_field[unit]); 30147 if (entry_type == 0 || entry_type == 1 || entry_type == 7 || 30148 (entry_type == 4 && soc_feature(unit, soc_feature_wlan)) || 30149 #ifdef BCM_TRIDENT3_SUPPORT 30150 (BCMI_L3_NH_FLEX_VIEW(entry_type) && 30151 soc_feature(unit, soc_feature_flex_flow)) || 30152 #endif 30153 #ifdef BCM_TOMAHAWK3_SUPPORT 30154 ((SOC_IS_TOMAHAWK3(unit)) && ((entry_type == 3) || 30155 (entry_type == 2))) || 30156 #endif 30157 (entry_type == 6 && _BCM_L3_FIELD_ONLY == 30158 BCM_XGS3_L3_ENT_FLAG( 30159 BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) || 30160 (entry_type == 8 && _BCM_L3_FCOE_ONLY == 30161 BCM_XGS3_L3_ENT_FLAG( 30162 BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) || 30163 entry_type == 10) { 30164 /* Valid entry types for L3 egress object are L3UC, MPLS, 30165 * WLAN, and L3MC. 30166 */ 30167 if (entry_type == 7 30168 && SOC_MEM_FIELD_VALID(unit, nhmem, 30169 L3MC__VNTAG_ACTIONSf) 30170 && soc_mem_field32_get(unit, nhmem, 30171 egr_entry_ptr, L3MC__VNTAG_ACTIONSf) == 1) { 30172 int share_vp = 0; 30173 soc_field_t rsvd_fld = L3MC__RSVD_DVPf; 30174 if (SOC_IS_TRIDENT3X(unit)) { 30175 rsvd_fld = L3MC__RESERVED_1f; 30176 } 30177 30178 /* Exclude the case: L3 NIV multicast egress object on 30179 * a shared VP. Use a useless field for NIV to indicate 30180 * those egress objects on a shared VP. 30181 */ 30182 if (SOC_MEM_FIELD_VALID(unit, nhmem, rsvd_fld) && 30183 soc_mem_field32_get(unit, nhmem, egr_entry_ptr, 30184 rsvd_fld)) { 30185 share_vp = 1; 30186 } 30187 30188 if (share_vp) { 30189 continue; 30190 } 30191 } 30192 } else { 30193 continue; 30194 } 30195 } 30196 } 30197 #endif /* BCM_FIREBOLT_SUPPORT */ 30198 /* coverity[var_deref_model : FALSE] */ 30199 _bcm_xgs3_nh_entry_parse(unit, ing_entry_ptr, egr_entry_ptr, egr_entry_2_ptr, idx, 30200 &nh_entry, NULL); 30201 30202 #ifdef BCM_TRIUMPH3_SUPPORT 30203 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 30204 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 30205 if (!BCM_GPORT_IS_SET(nh_entry.port)) { 30206 BCM_IF_ERROR_RETURN 30207 (bcm_th2_l3_egress_dlb_attr_get(unit, idx, &nh_entry)); 30208 } 30209 } else 30210 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 30211 { 30212 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 30213 bcm_tr3_l3_egress_dlb_attr_get(unit, idx, &nh_entry); 30214 } 30215 } 30216 #endif /* BCM_TRIUMPH3_SUPPORT */ 30217 30218 /* Execute operation routine if any. */ 30219 if (trv_data->op_cb) { 30220 rv = (*trv_data->op_cb)(unit, (void *)trv_data, 30221 (void *)&nh_entry,(void *)&idx, &cmp_result); 30222 30223 if (rv < 0) { 30224 #ifdef BCM_CB_ABORT_ON_ERR 30225 if (SOC_CB_ABORT_ON_ERR(unit)) { 30226 break; 30227 } 30228 #endif 30229 } 30230 } 30231 } 30232 soc_cm_sfree(unit, ing_tbl_ptr); 30233 #ifdef BCM_FIREBOLT_SUPPORT 30234 if (SOC_IS_FBX(unit)) { 30235 soc_cm_sfree(unit, egr_tbl_ptr); 30236 } 30237 #ifdef BCM_TOMAHAWK3_SUPPORT 30238 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 30239 soc_cm_sfree(unit, egr_tbl_2_ptr); 30240 } 30241 #endif 30242 30243 #endif /* BCM_FIREBOLT_SUPPORT */ 30244 return (rv); 30245 } 30246 30247 /* 30248 * Function: 30249 * _bcm_xgs3_l3_ent_init 30250 * Purpose: 30251 * Service routine used to init hw l3 entry 30252 * Parameters: 30253 * unit - (IN)SOC unit number. 30254 * mem - (IN)L3 table memory. 30255 * l3cfg - (IN/OUT)l3 entry lookup key & search result. 30256 * l3x_entry - (IN)hw buffer. 30257 * Returns: 30258 * void 30259 */ 30260 STATIC void 30261 _bcm_xgs3_l3_ent_init(int unit, soc_mem_t mem, 30262 _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 30263 { 30264 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 30265 uint32 *buf_p; /* HW buffer address. */ 30266 int ipv6; /* Entry is IPv6 flag. */ 30267 30268 /* Get entry type. */ 30269 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30270 30271 /* Zero destination buffer. */ 30272 buf_p = (uint32 *)l3x_entry; 30273 sal_memset(buf_p, 0, (ipv6) ? BCM_XGS3_L3_ENT_SZ(unit, v6) : \ 30274 BCM_XGS3_L3_ENT_SZ(unit, v4)); 30275 30276 /* Extract l3 ipv6/4 fields information. */ 30277 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \ 30278 BCM_XGS3_L3_MEM_FIELDS(unit, v4)); 30279 30280 #ifdef BCM_TRIUMPH_SUPPORT 30281 if (soc_feature(unit, soc_feature_l3_entry_key_type) && ipv6) { 30282 /* Set address lower part (64-127). */ 30283 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f, 30284 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 30285 30286 /* Set address upper part (0-63). */ 30287 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f, 30288 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 30289 30290 /* Mark entry as ipv6. */ 30291 #ifdef BCM_TRIDENT2_SUPPORT 30292 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 30293 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 30294 TD2_L3_HASH_KEY_TYPE_V6UC); 30295 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 30296 TD2_L3_HASH_KEY_TYPE_V6UC); 30297 } else 30298 #endif /* BCM_TRIDENT2_SUPPORT */ 30299 { 30300 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 30301 TR_L3_HASH_KEY_TYPE_V6UC); 30302 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 30303 TR_L3_HASH_KEY_TYPE_V6UC); 30304 } 30305 30306 /* Set valid bit. */ 30307 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 30308 } else 30309 #endif /* BCM_TRIUMPH_SUPPORT*/ 30310 if (SOC_IS_FBX(unit) && ipv6) { 30311 /* Set address lower part (64-127). */ 30312 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f, 30313 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 30314 30315 /* Set address upper part (0-63). */ 30316 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f, 30317 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 30318 30319 /* Mark entry as ipv6. */ 30320 soc_mem_field32_set(unit, mem, buf_p, V6_0f, 1); 30321 soc_mem_field32_set(unit, mem, buf_p, V6_1f, 1); 30322 30323 /* Set valid bit. */ 30324 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 30325 } else { 30326 #ifdef BCM_TRIUMPH_SUPPORT 30327 if (soc_feature(unit, soc_feature_l3_entry_key_type)) { 30328 /* Mark entry as ipv4. */ 30329 #ifdef BCM_TRIDENT2_SUPPORT 30330 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 30331 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 30332 TD2_L3_HASH_KEY_TYPE_V4UC); 30333 } else 30334 #endif /* BCM_TRIDENT2_SUPPORT */ 30335 { 30336 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 30337 TR_L3_HASH_KEY_TYPE_V4UC); 30338 } 30339 } 30340 #endif /* BCM_TRIUMPH_SUPPORT */ 30341 30342 /* Set ip address. */ 30343 soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf, l3cfg->l3c_ip_addr); 30344 } 30345 30346 /* Set virtual router id. */ 30347 if (SOC_MEM_FIELD_VALID(unit, mem, fld->vrf)) { 30348 soc_mem_field32_set(unit, mem, buf_p, fld->vrf, l3cfg->l3c_vrf); 30349 } 30350 30351 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 30352 defined(BCM_SCORPION_SUPPORT) 30353 if (SOC_MEM_FIELD_VALID(unit, mem, VRF_ID_1f) && ipv6) { 30354 soc_mem_field32_set(unit, mem, buf_p, VRF_ID_1f, l3cfg->l3c_vrf); 30355 } 30356 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT */ 30357 30358 /* Set entry valid bit. */ 30359 soc_mem_field32_set(unit, mem, buf_p, fld->valid, 1); 30360 30361 } 30362 30363 30364 /* 30365 * Function: 30366 * _bcm_xgs3_l3_ent_parse 30367 * Purpose: 30368 * Service routine used to parse hw l3 entry to api format. 30369 * Parameters: 30370 * unit - (IN)SOC unit number. 30371 * mem - (IN)L3 table memory. 30372 * l3cfg - (IN/OUT)l3 entry key & parse result. 30373 * nh_idx - (IN/OUT)Next hop index. 30374 * l3x_entry - (IN)hw buffer. 30375 * Returns: 30376 * void 30377 */ 30378 STATIC void 30379 _bcm_xgs3_l3_ent_parse(int unit, soc_mem_t mem, 30380 _bcm_l3_cfg_t *l3cfg, int *nh_idx, void *l3x_entry) 30381 { 30382 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 30383 uint32 *buf_p; /* HW buffer address. */ 30384 int ipv6; /* Entry is IPv6 flag. */ 30385 30386 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30387 buf_p = (uint32 *)l3x_entry; 30388 30389 /* Extract l3 ipv6/4 fields information. */ 30390 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \ 30391 BCM_XGS3_L3_MEM_FIELDS(unit, v4)); 30392 30393 /* Reset entry flags first. */ 30394 l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0; 30395 30396 30397 /* Get info from L3 and next hop table */ 30398 if (soc_mem_field32_get(unit, mem, buf_p, fld->hit) || 30399 BCM_XGS3_V6_FLD32_GET_IF_FBX(unit, ipv6, mem, buf_p, HIT_1f)) { 30400 l3cfg->l3c_flags |= BCM_L3_HIT; 30401 } 30402 30403 /* Get priority override flag. */ 30404 if (soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) { 30405 l3cfg->l3c_flags |= BCM_L3_RPE; 30406 } 30407 30408 /* Get destination discard flag. */ 30409 if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) { 30410 if (soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) { 30411 l3cfg->l3c_flags |= BCM_L3_DST_DISCARD; 30412 } 30413 } 30414 30415 #if defined(BCM_TRX_SUPPORT) 30416 /* Get classification group id. */ 30417 if (SOC_MEM_FIELD_VALID(unit, mem, fld->class_id)) { 30418 l3cfg->l3c_lookup_class = 30419 soc_mem_field32_get(unit, mem, buf_p, fld->class_id); 30420 } 30421 #endif /* BCM_TRX_SUPPORT */ 30422 30423 /* Get priority. */ 30424 l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority); 30425 30426 /* Get virtual router id. */ 30427 if (SOC_MEM_FIELD_VALID(unit, mem, fld->vrf)) { 30428 l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf); 30429 } else { 30430 l3cfg->l3c_vrf = BCM_L3_VRF_DEFAULT; 30431 } 30432 30433 /* Get next hop info. */ 30434 if (nh_idx) { 30435 *nh_idx = soc_mem_field32_get(unit, mem, buf_p, fld->nh_idx); 30436 } 30437 30438 return; 30439 } 30440 30441 /* 30442 * Function: 30443 * _bcm_xgs3_l3_clear_hit 30444 * Purpose: 30445 * Clear hit bit on l3 entry 30446 * Parameters: 30447 * unit - (IN)SOC unit number. 30448 * mem - (IN)L3 table memory. 30449 * l3cfg - (IN)l3 entry info. 30450 * l3x_entry - (IN)l3 entry filled hw buffer. 30451 * Returns: 30452 * BCM_E_XXX 30453 */ 30454 STATIC int 30455 _bcm_xgs3_l3_clear_hit(int unit, soc_mem_t mem, 30456 _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 30457 { 30458 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 30459 uint32 *buf_p; /* HW buffer address. */ 30460 int mcast; /* Entry is multicast flag. */ 30461 int ipv6; /* Entry is IPv6 flag. */ 30462 #ifdef BCM_FIREBOLT_SUPPORT 30463 int idx; /* Iterator index. */ 30464 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f }; 30465 #endif /* BCM_FIREBOLT_SUPPORT */ 30466 30467 /* Input parameters check */ 30468 if ((NULL == l3cfg) || (NULL == l3x_entry)) { 30469 return (BCM_E_PARAM); 30470 } 30471 30472 /* Get entry type. */ 30473 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30474 mcast = (l3cfg->l3c_flags & BCM_L3_IPMC); 30475 30476 /* Extract l3 ipv6/4 fields information. */ 30477 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \ 30478 BCM_XGS3_L3_MEM_FIELDS(unit, v4)); 30479 30480 /* Init memory pointers. */ 30481 buf_p = (uint32 *)l3x_entry; 30482 30483 /* If entry was not hit there is nothing to clear */ 30484 if (!(l3cfg->l3c_flags & BCM_L3_HIT)) { 30485 return (BCM_E_NONE); 30486 } 30487 30488 #ifdef BCM_FIREBOLT_SUPPORT 30489 /* Reset entry hit bit in hw. */ 30490 if (ipv6 && mcast) { 30491 /* IPV6 multicast entry hit reset. */ 30492 if (SOC_IS_FBX(unit)) { 30493 for (idx = 1; idx < 4; idx++) { 30494 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0); 30495 } 30496 } 30497 } else if (ipv6) { 30498 /* Reset IPV6 unicast hit bit. */ 30499 if (SOC_IS_FBX(unit)) { 30500 for (idx = 1; idx < 2; idx++) { 30501 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0); 30502 } 30503 } 30504 } 30505 #endif /* BCM_FIREBOLT_SUPPORT */ 30506 30507 /* Reset hit bit. */ 30508 soc_mem_field32_set(unit, mem, buf_p, fld->hit, 0); 30509 30510 /* Write entry back to hw. */ 30511 return BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p); 30512 } 30513 30514 /* 30515 * Function: 30516 * _bcm_xgs3_l3_get 30517 * Purpose: 30518 * Get an entry from L3 table. 30519 * Parameters: 30520 * unit - (IN)SOC unit number. 30521 * l3cfg - (IN/OUT)l3 entry lookup key & search result. 30522 * nh_index - (IN/OUT)Next hop index. 30523 * Returns: 30524 * BCM_E_XXX 30525 */ 30526 STATIC int 30527 _bcm_xgs3_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx) 30528 { 30529 l3_entry_ipv6_unicast_entry_t l3x_key; /* Lookup entry buffer. */ 30530 l3_entry_ipv6_unicast_entry_t l3x_entry; /* Search result buffer. */ 30531 soc_mem_t mem; /* L3 table memory. */ 30532 int clear_hit; /* Clear hit bit. */ 30533 int ipv6; /* IPv6 entry indicator. */ 30534 int rv = BCM_E_NONE; /* Operation return status. */ 30535 30536 /* Get entry type. */ 30537 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30538 30539 /* Preserve clear_hit value. */ 30540 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 30541 30542 /* Get table memory. */ 30543 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 30544 if (INVALIDm == mem) { 30545 return (BCM_E_NOT_FOUND); 30546 } 30547 30548 /* Prepare lookup key. */ 30549 /* coverity[overrun-buffer-val : FALSE] */ 30550 _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, &l3x_key); 30551 30552 /* Perform lookup hw. */ 30553 #ifdef BCM_TRX_SUPPORT 30554 if (soc_feature(unit, soc_feature_generic_table_ops)) { 30555 /* coverity[overrun-buffer-val : FALSE] */ 30556 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &l3cfg->l3c_hw_index, 30557 &l3x_key, &l3x_entry, 0); 30558 } else 30559 #endif /* BCM_TRX_SUPPORT */ 30560 #ifdef BCM_FIREBOLT_SUPPORT 30561 if (SOC_IS_FBX(unit)) { 30562 rv = soc_fb_l3x_lookup(unit, (void *)&l3x_key, 30563 (void *)&l3x_entry, &l3cfg->l3c_hw_index); 30564 } 30565 #endif /* BCM_FIREBOLT_SUPPORT */ 30566 BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND); 30567 30568 #ifdef BCM_TRIDENT_SUPPORT 30569 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit)) { 30570 soc_mem_t mem_y; 30571 l3_entry_ipv6_unicast_entry_t l3x_entry_y; 30572 uint32 hit; 30573 mem_y = ipv6 ? L3_ENTRY_IPV6_UNICAST_Ym : L3_ENTRY_IPV4_UNICAST_Ym; 30574 BCM_IF_ERROR_RETURN 30575 (BCM_XGS3_MEM_READ(unit, mem_y, l3cfg->l3c_hw_index, 30576 &l3x_entry_y)); 30577 if (ipv6) { 30578 hit = soc_mem_field32_get(unit, mem, &l3x_entry, HIT_0f); 30579 hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_0f); 30580 soc_mem_field32_set(unit, mem, &l3x_entry, HIT_0f, hit); 30581 hit = soc_mem_field32_get(unit, mem, &l3x_entry, HIT_1f); 30582 hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_1f); 30583 soc_mem_field32_set(unit, mem, &l3x_entry, HIT_1f, hit); 30584 } else { 30585 hit = soc_mem_field32_get(unit, mem, &l3x_entry, HITf); 30586 hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HITf); 30587 soc_mem_field32_set(unit, mem, &l3x_entry, HITf, hit); 30588 } 30589 } 30590 #endif /* BCM_TRIDENT_SUPPORT */ 30591 30592 /* Extract entry info. */ 30593 _bcm_xgs3_l3_ent_parse(unit, mem, l3cfg, nh_idx, &l3x_entry); 30594 30595 /* Clear the HIT bit */ 30596 if (clear_hit) { 30597 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem, 30598 l3cfg, &l3x_entry)); 30599 } 30600 return (BCM_E_NONE); 30601 } 30602 30603 /* 30604 * Function: 30605 * _bcm_xgs3_l3_add 30606 * Purpose: 30607 * Add an entry to L3 table. 30608 * Parameters: 30609 * unit - (IN)SOC unit number. 30610 * l3cfg - (IN)l3 entry information. 30611 * nh_idx - (IN)Next hop index. 30612 * Returns: 30613 * BCM_E_XXX 30614 */ 30615 STATIC int 30616 _bcm_xgs3_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 30617 { 30618 l3_entry_ipv6_unicast_entry_t l3x_entry; /* Buffer for write */ 30619 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 30620 uint32 *buf_p; /* Hardware buffer address.*/ 30621 soc_mem_t mem; /* L3 table memory. */ 30622 int ipv6; /* IPv6 entry indicator. */ 30623 int rv = BCM_E_NONE; /* Operation status. */ 30624 30625 buf_p = (uint32 *)&l3x_entry; 30626 30627 /* Get entry type. */ 30628 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30629 30630 /* Extract l3 ipv6/4 fields information. */ 30631 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \ 30632 BCM_XGS3_L3_MEM_FIELDS(unit, v4)); 30633 30634 /* Get table memory. */ 30635 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 30636 if (INVALIDm == mem) { 30637 return (BCM_E_DISABLED); 30638 } 30639 30640 /* Prepare hw entry for addition. */ 30641 _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, buf_p); 30642 30643 /* Set hit bit. */ 30644 if ((!SOC_IS_TOMAHAWK3(unit)) && (l3cfg->l3c_flags & BCM_L3_HIT)) { 30645 soc_mem_field32_set(unit, mem, buf_p, fld->hit, 1); 30646 BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, HIT_1f, 1); 30647 } 30648 30649 /* Set priority override bit. */ 30650 if (l3cfg->l3c_flags & BCM_L3_RPE) { 30651 soc_mem_field32_set(unit, mem, buf_p, fld->rpe, 1); 30652 BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, RPE_1f, 1); 30653 } 30654 30655 /* Set destination discard bit. */ 30656 if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) { 30657 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 30658 soc_mem_field32_set(unit, mem, buf_p, fld->dst_discard, 1); 30659 BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, 30660 DST_DISCARD_1f, 1); 30661 } 30662 } 30663 30664 #if defined(BCM_TRX_SUPPORT) 30665 /* Get classification group id. */ 30666 if (SOC_MEM_FIELD_VALID(unit, mem, fld->class_id)) { 30667 soc_mem_field32_set(unit, mem, buf_p, fld->class_id, 30668 l3cfg->l3c_lookup_class); 30669 BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, 30670 CLASS_ID_1f, l3cfg->l3c_lookup_class); 30671 } 30672 #endif /* BCM_TRX_SUPPORT */ 30673 30674 /* Set priority. */ 30675 if (SOC_MEM_FIELD_VALID(unit, mem, fld->priority)) { 30676 int pri_field_len; 30677 int max_pri; 30678 30679 pri_field_len = soc_mem_field_length(unit, mem, fld->priority); 30680 max_pri = (1 << pri_field_len) - 1; 30681 30682 /* 30683 * to validate the assigning priority : 30684 * - Different device may support different max priority. 30685 */ 30686 if (l3cfg->l3c_prio > max_pri) { 30687 return BCM_E_PARAM; 30688 } 30689 soc_mem_field32_set(unit, mem, buf_p, fld->priority, l3cfg->l3c_prio); 30690 BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, 30691 PRI_1f, l3cfg->l3c_prio); 30692 } 30693 30694 /* Set next hop index. */ 30695 soc_mem_field32_set(unit, mem, buf_p, fld->nh_idx, nh_idx); 30696 BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, 30697 NEXT_HOP_INDEX_1f, nh_idx); 30698 /* Write entry to hw. */ 30699 /* Handle replacement if hw index already known, write directly. */ 30700 if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) { 30701 rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p); 30702 } else { 30703 #ifdef BCM_TRX_SUPPORT 30704 if (soc_feature(unit, soc_feature_generic_table_ops)) { 30705 /* coverity[overrun-buffer-val : FALSE] */ 30706 rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry); 30707 } else 30708 #endif /* BCM_TRX_SUPPORT */ 30709 #ifdef BCM_FIREBOLT_SUPPORT 30710 if (SOC_IS_FBX(unit)) { 30711 rv = soc_fb_l3x_insert(unit, (void *)&l3x_entry); 30712 } 30713 #endif /* BCM_FIREBOLT_SUPPORT */ 30714 } 30715 30716 /* Write status check. */ 30717 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 30718 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++; 30719 } 30720 return rv; 30721 } 30722 30723 30724 /* 30725 * Function: 30726 * _bcm_xgs3_l3_bucket_get 30727 * Purpose: 30728 * Get l3 entry bucket start index. 30729 * Parameters: 30730 * unit - (IN)SOC unit number. 30731 * l3cfg - (IN)l3 entry information. 30732 * idx_primary - (OUT)Primary bank bucket start index. 30733 * idx_secondary - (OUT)Secondary bank bucket start index. 30734 * Returns: 30735 * BCM_E_XXX 30736 * NOTE: 30737 * idx_primary = points to the first half of the bucket. 30738 * idx_secondary = points to the second half of the bucket. 30739 * If dual hash is not supported idx_primary & idx_secondary 30740 * point to the same bucket. 30741 */ 30742 30743 STATIC int 30744 _bcm_xgs3_l3_bucket_get (int unit, _bcm_l3_cfg_t *l3cfg, 30745 int *idx_primary, int *idx_secondary) 30746 { 30747 l3_entry_ipv6_multicast_entry_t l3x_entry; /* Buffer for hw write */ 30748 uint32 *buf_p; /* Hardware buffer address.*/ 30749 soc_mem_t mem; /* L3 table memory. */ 30750 uint8 ipv6; /* IPv6 entry indicator. */ 30751 uint8 ipmc; /* IPMC entry indicator. */ 30752 int prim_idx; /* Primary bucket. */ 30753 int sec_idx; /* Secondary bucket. */ 30754 30755 if ((NULL == idx_primary) || (NULL == idx_secondary)) { 30756 return (BCM_E_PARAM); 30757 } 30758 30759 sal_memset(&l3x_entry, 0, sizeof(l3x_entry)); 30760 buf_p = (uint32 *)&l3x_entry; 30761 30762 /* Get entry type. */ 30763 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6) ? 1 : 0; 30764 ipmc = (l3cfg->l3c_flags & BCM_L3_IPMC) ? 1 : 0; 30765 30766 /* Get table memory. */ 30767 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 30768 if (INVALIDm == mem) { 30769 return (BCM_E_DISABLED); 30770 } 30771 30772 /* Prepare hw entry for addition. */ 30773 30774 if (ipmc) { 30775 #if defined(BCM_TRIUMPH_SUPPORT) 30776 if (SOC_IS_TR_VL(unit)) { 30777 _bcm_tr_l3_ipmc_ent_init(unit, buf_p, l3cfg); 30778 } else 30779 #endif /* BCM_TRIUMPH_SUPPORT */ 30780 { 30781 #ifdef BCM_FIREBOLT_SUPPORT 30782 _bcm_fb_l3_ipmc_ent_init(unit, buf_p, l3cfg); 30783 #endif /* BCM_FIREBOLT_SUPPORT */ 30784 } 30785 } else { 30786 _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, buf_p); 30787 } 30788 30789 #ifdef BCM_FIREBOLT_SUPPORT 30790 if (SOC_IS_FBX(unit)) { 30791 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) ||\ 30792 defined(BCM_TRX_SUPPORT) 30793 if (soc_feature(unit, soc_feature_dual_hash)) { 30794 30795 prim_idx = 30796 soc_fb_l3x_bank_entry_hash(unit, 0, (uint32 *)&l3x_entry); 30797 if (prim_idx < 0) { 30798 return prim_idx; 30799 } 30800 /* coverity[overrun-buffer-val : FALSE] */ 30801 sec_idx = 30802 soc_fb_l3x_bank_entry_hash(unit, 1, (uint32 *)&l3x_entry); 30803 if (sec_idx < 0) { 30804 return sec_idx; 30805 } 30806 } else 30807 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 30808 { 30809 sec_idx = prim_idx = soc_fb_l3x2_entry_hash(unit, (uint32 *)&l3x_entry); 30810 } 30811 } else 30812 #endif /* BCM_FIREBOLT_SUPPORT */ 30813 { 30814 *idx_primary = *idx_secondary = -1; 30815 return (BCM_E_UNAVAIL); 30816 } 30817 30818 /* First half of primary bucket. */ 30819 *idx_primary = prim_idx * SOC_L3X_BUCKET_SIZE(unit); 30820 30821 /* Second half of secondary bucket */ 30822 *idx_secondary = sec_idx * SOC_L3X_BUCKET_SIZE(unit) + 30823 SOC_L3X_BUCKET_SIZE(unit)/2; 30824 30825 return (BCM_E_NONE); 30826 } 30827 30828 30829 /* 30830 * Function: 30831 * _bcm_xgs3_l3_del 30832 * Purpose: 30833 * Delete an entry to L3 table. 30834 * Parameters: 30835 * unit - (IN)SOC unit number. 30836 * l3cfg - (IN/OUT)l3 entry deletion key. 30837 * Returns: 30838 * BCM_E_XXX 30839 */ 30840 STATIC int 30841 _bcm_xgs3_l3_del(int unit, _bcm_l3_cfg_t *l3cfg) 30842 { 30843 l3_entry_ipv6_unicast_entry_t l3x_entry; /* Buffer for write */ 30844 soc_mem_t mem; /* L3 table memory. */ 30845 int ipv6; /* IPv6 entry indicator. */ 30846 int rv = BCM_E_NONE; /* Operation status. */ 30847 30848 /* Get entry type. */ 30849 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30850 30851 /* Get table memory. */ 30852 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 30853 if (INVALIDm == mem) { 30854 return (BCM_E_DISABLED); 30855 } 30856 30857 /* Prepare hw entry for addition. */ 30858 _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, &l3x_entry); 30859 30860 /* Write entry to hw. */ 30861 #ifdef BCM_TRX_SUPPORT 30862 if (soc_feature(unit, soc_feature_generic_table_ops)) { 30863 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry); 30864 } else 30865 #endif /* BCM_TRX_SUPPORT */ 30866 #ifdef BCM_FIREBOLT_SUPPORT 30867 if (SOC_IS_FBX(unit)) { 30868 rv = soc_fb_l3x_delete(unit, (void *)&l3x_entry); 30869 } 30870 #endif /* BCM_FIREBOLT_SUPPORT */ 30871 30872 /* Write status check. */ 30873 if (rv >= 0) { 30874 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--; 30875 } 30876 return rv; 30877 } 30878 30879 /* 30880 * Function: 30881 * _bcm_xgs3_l3_get_by_idx 30882 * Purpose: 30883 * Get an entry from L3 table by index. 30884 * Parameters: 30885 * unit - (IN)SOC unit number. 30886 * dma_ptr - (IN)Table pointer in dma. 30887 * idx - (IN)Index to read. 30888 * l3cfg - (OUT)l3 entry search result. 30889 * nh_index - (OUT)Next hop index. 30890 * Returns: 30891 * BCM_E_XXX 30892 */ 30893 STATIC int 30894 _bcm_xgs3_l3_get_by_idx(int unit, void *dma_ptr, int idx, 30895 _bcm_l3_cfg_t *l3cfg, int *nh_idx) 30896 { 30897 l3_entry_ipv6_unicast_entry_t *l3x_entry_p; /* Read buffer address. */ 30898 l3_entry_ipv6_unicast_entry_t l3x_entry; /* Read buffer. */ 30899 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 30900 soc_mem_t mem; /* L3 table memory. */ 30901 int clear_hit; /* Clear hit bit flag. */ 30902 uint32 ipv6; /* IPv6 entry indicator. */ 30903 30904 /* Get entry type. */ 30905 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 30906 30907 /* Get table memory. */ 30908 mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4); 30909 30910 /* Extract l3 ipv6/4 fields information. */ 30911 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \ 30912 BCM_XGS3_L3_MEM_FIELDS(unit, v4)); 30913 30914 /* Get clear hit flag. */ 30915 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 30916 30917 if (NULL == dma_ptr) { /* Read from hardware. */ 30918 l3x_entry_p = &l3x_entry; 30919 /* Zero buffers. */ 30920 sal_memset(l3x_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, v6)); 30921 30922 /* Read entry from hw. */ 30923 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, l3x_entry_p)); 30924 30925 } else { /* Read from dma. */ 30926 l3x_entry_p = 30927 soc_mem_table_idx_to_pointer(unit, mem, 30928 l3_entry_ipv6_unicast_entry_t *, 30929 dma_ptr, idx); 30930 } 30931 30932 #ifdef BCM_TRIDENT_SUPPORT 30933 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit)) { 30934 soc_mem_t mem_y; 30935 l3_entry_ipv6_unicast_entry_t l3x_entry_y; 30936 uint32 hit; 30937 mem_y = ipv6 ? L3_ENTRY_IPV6_UNICAST_Ym : L3_ENTRY_IPV4_UNICAST_Ym; 30938 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem_y, idx, &l3x_entry_y)); 30939 if (ipv6) { 30940 hit = soc_mem_field32_get(unit, mem, l3x_entry_p, HIT_0f); 30941 hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_0f); 30942 soc_mem_field32_set(unit, mem, l3x_entry_p, HIT_0f, hit); 30943 hit = soc_mem_field32_get(unit, mem, l3x_entry_p, HIT_1f); 30944 hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_1f); 30945 soc_mem_field32_set(unit, mem, l3x_entry_p, HIT_1f, hit); 30946 } else { 30947 hit = soc_mem_field32_get(unit, mem, l3x_entry_p, HITf); 30948 hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HITf); 30949 soc_mem_field32_set(unit, mem, l3x_entry_p, HITf, hit); 30950 } 30951 } 30952 #endif /* BCM_TRIDENT_SUPPORT */ 30953 30954 /* Ignore invalid entries. */ 30955 if (soc_mem_field_valid(unit, mem, fld->valid)) { 30956 if (!soc_mem_field32_get(unit, mem, l3x_entry_p, fld->valid)) { 30957 return (BCM_E_NOT_FOUND); 30958 } 30959 } 30960 #ifdef BCM_TRIUMPH_SUPPORT 30961 if (soc_feature(unit, soc_feature_l3_entry_key_type)) { 30962 /* Get protocol. */ 30963 int key_type; 30964 30965 key_type = soc_mem_field32_get(unit, L3_ENTRY_ONLYm, 30966 l3x_entry_p, KEY_TYPEf); 30967 30968 #ifdef BCM_TRIDENT2_SUPPORT 30969 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 30970 switch (key_type) { 30971 case TD2_L3_HASH_KEY_TYPE_V4UC: 30972 l3cfg->l3c_flags = 0; 30973 break; 30974 case TD2_L3_HASH_KEY_TYPE_V4MC: 30975 l3cfg->l3c_flags = BCM_L3_IPMC; 30976 break; 30977 case TD2_L3_HASH_KEY_TYPE_V6UC: 30978 l3cfg->l3c_flags = BCM_L3_IP6; 30979 break; 30980 case TD2_L3_HASH_KEY_TYPE_V6MC: 30981 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 30982 break; 30983 default: 30984 break; 30985 } 30986 } else 30987 #endif /* BCM_TRIDENT2_SUPPORT */ 30988 { 30989 if (key_type == TR_L3_HASH_KEY_TYPE_RMEP || 30990 key_type == TR_L3_HASH_KEY_TYPE_LMEP) { 30991 /* Ignore OAM entries. 30992 * They handled in OAM, should not changed in L3 30993 */ 30994 return (BCM_E_NOT_FOUND); 30995 } 30996 switch (key_type) { 30997 case TR_L3_HASH_KEY_TYPE_V4UC: 30998 l3cfg->l3c_flags = 0; 30999 break; 31000 case TR_L3_HASH_KEY_TYPE_V4MC: 31001 l3cfg->l3c_flags = BCM_L3_IPMC; 31002 break; 31003 case TR_L3_HASH_KEY_TYPE_V6UC: 31004 l3cfg->l3c_flags = BCM_L3_IP6; 31005 break; 31006 case TR_L3_HASH_KEY_TYPE_V6MC: 31007 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 31008 break; 31009 default: 31010 break; 31011 } 31012 } 31013 31014 /* Ignore protocol mismatch & multicast entries. */ 31015 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 31016 (l3cfg->l3c_flags & BCM_L3_IPMC)) { 31017 return (BCM_E_NONE); 31018 } 31019 31020 /* Get host ip address. */ 31021 if (ipv6) { 31022 /* Extract host info from the entry. */ 31023 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, 31024 IP_ADDR_LWR_64f, l3cfg->l3c_ip6, 31025 SOC_MEM_IP6_LOWER_ONLY); 31026 31027 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, 31028 IP_ADDR_UPR_64f, l3cfg->l3c_ip6, 31029 SOC_MEM_IP6_UPPER_ONLY); 31030 } 31031 } else 31032 #endif /* BCM_TRIUMPH_SUPPORT */ 31033 #ifdef BCM_FIREBOLT_SUPPORT 31034 if (SOC_IS_FBX(unit)) { 31035 /* Get protocol. */ 31036 if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->v6_entry)){ 31037 l3cfg->l3c_flags = BCM_L3_IP6; 31038 } else { 31039 l3cfg->l3c_flags = 0; 31040 } 31041 31042 /* Get ipmc flag . */ 31043 if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->ipmc_entry)) { 31044 l3cfg->l3c_flags |= BCM_L3_IPMC; 31045 } 31046 31047 /* Ignore protocol mismatch & multicast entries. */ 31048 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 31049 (l3cfg->l3c_flags & BCM_L3_IPMC)) { 31050 return (BCM_E_NONE); 31051 } 31052 31053 31054 /* Get host ip address. */ 31055 if (ipv6) { 31056 /* Extract host info from the entry. */ 31057 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, 31058 IP_ADDR_LWR_64f, l3cfg->l3c_ip6, 31059 SOC_MEM_IP6_LOWER_ONLY); 31060 31061 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, 31062 IP_ADDR_UPR_64f, l3cfg->l3c_ip6, 31063 SOC_MEM_IP6_UPPER_ONLY); 31064 } 31065 } 31066 #endif /* BCM_FIREBOLT_SUPPORT */ 31067 31068 /* Set index to l3cfg. */ 31069 l3cfg->l3c_hw_index = idx; 31070 31071 if (!ipv6) { 31072 l3cfg->l3c_ip_addr = 31073 soc_mem_field32_get(unit, mem, l3x_entry_p, IP_ADDRf); 31074 } 31075 31076 /* Parse entry data. */ 31077 _bcm_xgs3_l3_ent_parse(unit, mem, l3cfg, nh_idx, l3x_entry_p); 31078 31079 /* Clear the HIT bit */ 31080 if (clear_hit) { 31081 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem, 31082 l3cfg, (void *)l3x_entry_p)); 31083 } 31084 return (BCM_E_NONE); 31085 } 31086 31087 /* 31088 * Function: 31089 * _bcm_xgs3_nh_inc_ref_count 31090 * Purpose: 31091 * Increment Next Hop Reference count 31092 * Parameters: 31093 * unit - (IN)SOC unit number. 31094 * nh_index - (IN)Next hop index. 31095 */ 31096 31097 void 31098 bcm_xgs3_nh_inc_ref_count(int unit, int nh_index) 31099 { 31100 _bcm_l3_tbl_t *nh_tbl_ptr; /* Next hop table ptr. */ 31101 31102 /* Get table pointers */ 31103 nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 31104 31105 BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, nh_index, 31106 _BCM_SINGLE_WIDE); 31107 } 31108 31109 /* 31110 * Function: 31111 * _bcm_xgs3_nh_dec_ref_count 31112 * Purpose: 31113 * Decrement Next Hop Reference count 31114 * Parameters: 31115 * unit - (IN)SOC unit number. 31116 * nh_index - (IN)Next hop index. 31117 */ 31118 31119 void 31120 bcm_xgs3_nh_dec_ref_count(int unit, int nh_index) 31121 { 31122 _bcm_l3_tbl_t *nh_tbl_ptr; /* Next hop table ptr. */ 31123 31124 /* Get table pointers */ 31125 nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 31126 31127 BCM_XGS3_L3_ENT_REF_CNT_DEC(nh_tbl_ptr, nh_index, 31128 _BCM_SINGLE_WIDE); 31129 31130 } 31131 31132 /* 31133 * Function: 31134 * _bcm_xgs3_nh_ref_count_get 31135 * Purpose: 31136 * Get Next Hop Reference count 31137 * Parameters: 31138 * unit - (IN)SOC unit number. 31139 * nh_index - (IN)Next hop index. 31140 * ref_count - (OUT)Reference count. 31141 */ 31142 31143 int 31144 bcm_xgs3_nh_ref_count_get(int unit, int nh_index, int *ref_count) 31145 { 31146 _bcm_l3_tbl_t *nh_tbl_ptr; 31147 31148 /* Get table pointers */ 31149 nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 31150 31151 31152 *ref_count = BCM_XGS3_L3_ENT_REF_CNT(nh_tbl_ptr, nh_index); 31153 31154 return BCM_E_NONE; 31155 } 31156 31157 #ifdef BCM_FIREBOLT_SUPPORT 31158 /* 31159 * Function: 31160 * _bcm_fb_l3_intf_vrf_get 31161 * Purpose: 31162 * Get the VRF,flags info for the specified L3 interface 31163 * Parameters: 31164 * unit - (IN)SOC unit number. 31165 * intf_info - (IN/OUT)Interface configuration info. 31166 * Returns: 31167 * BCM_E_XXX. 31168 */ 31169 STATIC int 31170 _bcm_fb_l3_intf_vrf_get(int unit, _bcm_l3_intf_cfg_t *intf_info) 31171 { 31172 int vrf; 31173 int ret_val; /* Operation return value. */ 31174 bcm_vlan_control_vlan_t vlan_control; /* Vlan configuration structure. */ 31175 31176 #if defined(BCM_TRIUMPH_SUPPORT) 31177 int ingress_map_mode = 0; 31178 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 31179 31180 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 31181 BCM_IF_ERROR_RETURN( 31182 bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode)); 31183 } 31184 31185 if (ingress_map_mode && !soc_feature(unit, soc_feature_l3_iif_under_4k)) { 31186 iif.intf_id = intf_info->l3i_index; 31187 ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 31188 vrf = iif.vrf; 31189 } else 31190 #endif /* BCM_TRIUMPH_SUPPORT */ 31191 { 31192 ret_val = _bcm_xgs3_vlan_control_vlan_get(unit, intf_info->l3i_vid, 31193 BCM_VLAN_CONTROL_VLAN_ALL_MASK, 31194 &vlan_control); 31195 vrf = vlan_control.vrf; 31196 } 31197 31198 if (BCM_SUCCESS(ret_val)) { 31199 /* Get Virtual Router id */ 31200 intf_info->l3i_vrf = vrf; 31201 } else { 31202 intf_info->l3i_vrf = BCM_L3_VRF_DEFAULT; 31203 } 31204 31205 return (BCM_E_NONE); 31206 } 31207 31208 /* 31209 * Function: 31210 * _bcm_fb_l3_intf_vrf_bind 31211 * Purpose: 31212 * Bind interface to the VRF & update if info. 31213 * Parameters: 31214 * unit - (IN) SOC unit number. 31215 * intf_info - (IN) Interface configuration info. 31216 * Returns: 31217 * BCM_E_XXX. 31218 */ 31219 STATIC int 31220 _bcm_fb_l3_intf_vrf_bind(int unit, _bcm_l3_intf_cfg_t *intf_info) 31221 { 31222 int rv; 31223 #if defined(BCM_TRIUMPH_SUPPORT) 31224 int ingress_map_mode = 0; 31225 #endif /* BCM_TRIUMPH_SUPPORT */ 31226 31227 if (intf_info->l3i_vrf < 0) { 31228 return BCM_E_PARAM; 31229 } 31230 31231 if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) { 31232 bcm_vlan_control_vlan_t vlan_control; 31233 31234 sal_memset(&vlan_control, 0, sizeof(vlan_control)); 31235 /* 31236 * Need to use the ALL mask for _bcm_xgs3_vlan_control_vlan_get() 31237 * due to the current implementation in 31238 * _bcm_xgs3_vlan_control_vlan_set(). 31239 * This _set() routine sets other fields besides the ones 31240 * specified by the "valid_fields" parameter 31241 */ 31242 rv = _bcm_xgs3_vlan_control_vlan_get(unit, intf_info->l3i_vid, 31243 BCM_VLAN_CONTROL_VLAN_ALL_MASK, 31244 &vlan_control); 31245 if ((BCM_E_NOT_FOUND == rv) || (BCM_E_UNAVAIL == rv)) { 31246 /* Assuming application will set vrf id later on 31247 through vlan commands. */ 31248 return BCM_E_NONE; 31249 } 31250 31251 /* Return any other error. */ 31252 if (BCM_FAILURE(rv)){ 31253 return (rv); 31254 } 31255 31256 vlan_control.vrf = intf_info->l3i_vrf; 31257 BCM_IF_ERROR_RETURN 31258 (_bcm_xgs3_vlan_control_vlan_set(unit, intf_info->l3i_vid, 31259 BCM_VLAN_CONTROL_VLAN_VRF_MASK, 31260 &vlan_control)); 31261 } 31262 #if defined(BCM_TRIUMPH_SUPPORT) 31263 else { 31264 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 31265 BCM_IF_ERROR_RETURN 31266 (bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode)); 31267 } 31268 if (!ingress_map_mode) { 31269 BCM_IF_ERROR_RETURN 31270 (_bcm_tr_l3_intf_vrf_bind(unit, 31271 intf_info->l3i_vid, 31272 intf_info->l3i_vrf)); 31273 } 31274 } 31275 #endif /* BCM_TRIUMPH_SUPPORT */ 31276 31277 return BCM_E_NONE; 31278 } 31279 31280 /* 31281 * Function: 31282 * _bcm_fb_l3_intf_vrf_unbind 31283 * Purpose: 31284 * Restore VRF value to defaults. 31285 * Parameters: 31286 * unit - (IN) SOC unit number. 31287 * intf_info - (IN) Interface configuration info. 31288 * Returns: 31289 * BCM_E_XXX. 31290 */ 31291 STATIC int 31292 _bcm_fb_l3_intf_vrf_unbind(int unit, _bcm_l3_intf_cfg_t *intf_info) 31293 { 31294 int rv; 31295 bcm_vrf_t vrf_temp; 31296 31297 vrf_temp = intf_info->l3i_vrf; 31298 intf_info->l3i_vrf = BCM_L3_VRF_DEFAULT; 31299 31300 rv = _bcm_fb_l3_intf_vrf_bind(unit, intf_info); 31301 31302 if ((BCM_E_NOT_FOUND == rv) || (BCM_E_PARAM == rv) || 31303 (BCM_E_UNAVAIL == rv)) { 31304 /* Assuming application did not set vrf. */ 31305 return BCM_E_NONE; 31306 } 31307 31308 /* Restore original value */ 31309 intf_info->l3i_vrf = vrf_temp; 31310 31311 return rv; 31312 } 31313 31314 #ifdef BCM_TRIDENT2_SUPPORT 31315 /* 31316 * Function: 31317 * _bcm_fb_l3_intf_nat_realm_id_set 31318 * Purpose: 31319 * Set the NAT realm id for the interface. 31320 * Parameters: 31321 * unit - (IN) SOC unit number. 31322 * intf_info - (IN) Interface configuration info. 31323 * Returns: 31324 * BCM_E_XXX. 31325 */ 31326 STATIC int 31327 _bcm_fb_l3_intf_nat_realm_id_set(int unit, _bcm_l3_intf_cfg_t *intf_info) 31328 { 31329 bcm_vlan_t vid; 31330 uint32 buf[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 31331 soc_mem_t vlan_attrs_mem = VLAN_MPLSm; 31332 soc_mem_t vlan_mem = VLAN_TABm; 31333 31334 vid = intf_info->l3i_vid; 31335 sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 31336 31337 #ifdef BCM_TRIDENT3_SUPPORT 31338 if (SOC_IS_TRIDENT3X(unit)) { 31339 vlan_attrs_mem = VLAN_TABm; 31340 vlan_mem = VLAN_TABm; 31341 } 31342 #endif 31343 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) { 31344 /* Get Vlan mapping */ 31345 31346 /* The current logic needs to be duplicated 31347 * from _bcm_xgs3_vlan_control_vlan_set() in order 31348 * to avoid deadlock between the L3 and the VLAN modules. 31349 */ 31350 31351 if (SOC_MEM_FIELD_VALID(unit, vlan_attrs_mem, L3_IIFf)) { 31352 31353 /* 31354 * Check that L3_IIF is valid before using it. 31355 * Allow case when VLAN has not been created yet. 31356 * Assuming application will this later on 31357 * through vlan commands. 31358 */ 31359 SOC_IF_ERROR_RETURN 31360 (soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, (int) vid, buf)); 31361 if (!soc_mem_field32_get(unit, vlan_mem, buf, VALIDf)) { 31362 return BCM_E_NONE; 31363 } 31364 31365 sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 31366 BCM_IF_ERROR_RETURN 31367 (soc_mem_read(unit, vlan_attrs_mem, MEM_BLOCK_ANY, vid, 31368 buf)); 31369 vid = soc_mem_field32_get(unit, vlan_attrs_mem, 31370 buf, L3_IIFf); 31371 } else { 31372 vid = 0; 31373 } 31374 } 31375 31376 BCM_IF_ERROR_RETURN 31377 (_bcm_tr_l3_intf_nat_realm_id_set(unit, vid, 31378 intf_info->l3i_nat_realm_id)); 31379 return BCM_E_NONE; 31380 } 31381 31382 /* 31383 * Function: 31384 * _bcm_fb_l3_intf_nat_realm_id_get 31385 * Purpose: 31386 * Get the NAT realm id for the specified L3 interface 31387 * Parameters: 31388 * unit - (IN)SOC unit number. 31389 * intf_info - (IN/OUT)Interface configuration info. 31390 * Returns: 31391 * BCM_E_XXX. 31392 */ 31393 STATIC int 31394 _bcm_fb_l3_intf_nat_realm_id_get(int unit, _bcm_l3_intf_cfg_t *intf_info) 31395 { 31396 int nat_realm_id = 0; 31397 int ret_val = BCM_E_NONE; /* Operation return value. */ 31398 31399 #if defined(BCM_TRIUMPH_SUPPORT) 31400 int ingress_map_mode = 0; 31401 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 31402 31403 #ifdef BCM_RIOT_SUPPORT 31404 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 31405 return BCM_E_NONE; 31406 } 31407 #endif 31408 31409 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 31410 BCM_IF_ERROR_RETURN( 31411 bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode)); 31412 } 31413 31414 if (ingress_map_mode) { 31415 iif.intf_id = intf_info->l3i_index; 31416 ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 31417 nat_realm_id = iif.nat_realm_id; 31418 } else 31419 #endif /* BCM_TRIUMPH_SUPPORT */ 31420 31421 { 31422 if (SOC_MEM_IS_VALID(unit, L3_IIFm) && 31423 SOC_MEM_FIELD_VALID(unit, L3_IIFm, SRC_REALM_IDf)) { 31424 ret_val = _bcm_tr_l3_intf_nat_realm_id_get(unit, 31425 intf_info->l3i_vid, &nat_realm_id); 31426 } 31427 } 31428 31429 if (BCM_SUCCESS(ret_val)) { 31430 /* Get Virtual Router id */ 31431 intf_info->l3i_nat_realm_id = nat_realm_id; 31432 } 31433 31434 return (BCM_E_NONE); 31435 } 31436 #endif /* BCM_TRIDENT2_SUPPORT */ 31437 31438 /* 31439 * Function: 31440 * _bcm_fb_nh_add 31441 * Purpose: 31442 * Routine set next hop entry in the chip. 31443 * Parameters: 31444 * unit - (IN)SOC unit number. 31445 * idx - (IN)Allocated entry index. 31446 * buf - (IN)Next hop entry data. 31447 * Returns: 31448 * BCM_E_XXX 31449 */ 31450 STATIC int 31451 _bcm_fb_nh_add(int unit, int idx, void *buf, void *info) 31452 { 31453 ing_l3_next_hop_entry_t in_entry; /* Buffer to read ingress nh entry. */ 31454 egr_l3_next_hop_entry_t eg_entry; /* Buffer to read egress nh entry. */ 31455 #ifdef BCM_TOMAHAWK3_SUPPORT 31456 egr_l3_next_hop_2_entry_t eg_2_entry; /* Buffer to read egress nh entry. */ 31457 soc_mem_t mem2; /* Next hop table memory. */ 31458 #endif 31459 bcm_l3_egress_t *nh_entry; /* Next hop entry passed buffer. */ 31460 int tunnel_id; /* Tunnel id attached to interface. */ 31461 soc_mem_t mem; /* Next hop table memory. */ 31462 uint32 entry_type=0; 31463 int max_intf = 0; 31464 #ifdef BCM_RIOT_SUPPORT 31465 uint32 nh_dest = 0; 31466 #endif 31467 #ifdef BCM_TRIDENT2_SUPPORT 31468 _bcm_l3_ingress_intf_t iif; 31469 #endif 31470 #if defined(BCM_MONTEREY_SUPPORT) 31471 soc_field_t field = INVALIDf, field2 = INVALIDf; 31472 #endif 31473 bcm_port_t nh_port; 31474 31475 /* Input parameters check */ 31476 if (NULL == buf) { 31477 return (BCM_E_PARAM); 31478 } 31479 31480 nh_entry = (bcm_l3_egress_t *) buf; 31481 31482 if ((nh_entry->flags & BCM_L3_IPMC) && 31483 !(nh_entry->flags & BCM_L3_L2GRE_ONLY) && 31484 !(nh_entry->flags & BCM_L3_VXLAN_ONLY)) { 31485 #ifdef BCM_TRIUMPH3_SUPPORT 31486 if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) { 31487 /* Triumph3 is the first XGS device in which MMU no longer 31488 * replicates L3 interfaces directly. Rather, MMU will output 31489 * next hop indices, and L3 interface will be derived from 31490 * egress next hop entry having the type L3MC. 31491 */ 31492 return _bcm_tr3_l3_ipmc_nh_add(unit, idx, nh_entry); 31493 } else 31494 #endif /* BCM_TRIUMPH3_SUPPORT */ 31495 { 31496 /* Greyhound through 'soc_feature_l3mc_use_egress_next_hop' to 31497 * support new L3MC egress logic. This egress logic for IPMC 31498 * replication will use egress next hop entry to reference L3 31499 * interface entry always. 31500 */ 31501 if (!soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) { 31502 return BCM_E_UNAVAIL; 31503 } 31504 } 31505 } 31506 31507 /* Zero buffers. */ 31508 sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh)); 31509 sal_memset(&eg_entry, 0, sizeof(egr_l3_next_hop_entry_t)); 31510 #ifdef BCM_TOMAHAWK3_SUPPORT 31511 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 31512 sal_memset(&eg_2_entry, 0, sizeof(egr_l3_next_hop_2_entry_t)); 31513 } 31514 #endif 31515 31516 mem = ING_L3_NEXT_HOPm; 31517 31518 /* Read ingress next hop entry. */ 31519 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &in_entry)); 31520 if (nh_entry->intf == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) { 31521 soc_mem_field32_set(unit, mem, &in_entry, VLAN_IDf, nh_entry->vlan); 31522 } else { 31523 if (SOC_MEM_FIELD_VALID(unit, mem, L3_OIFf) && 31524 (BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit))) { 31525 max_intf = (1 << soc_mem_field_length(unit, mem, L3_OIFf)) - 1; 31526 if (nh_entry->intf > max_intf) { 31527 return BCM_E_PARAM; 31528 } 31529 soc_mem_field32_set(unit, mem, &in_entry, L3_OIFf, nh_entry->intf); 31530 } else { 31531 soc_mem_field32_set(unit, mem, &in_entry, VLAN_IDf, nh_entry->vlan); 31532 } 31533 } 31534 31535 31536 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || \ 31537 defined(BCM_GREYHOUND_SUPPORT) 31538 if (SOC_MEM_FIELD_VALID(unit, mem, INTF_NUMf)) { 31539 soc_mem_field32_set(unit, mem, &in_entry, INTF_NUMf, nh_entry->intf); 31540 } 31541 #endif /* BCM_HURRICANE_SUPPORT */ 31542 31543 #ifdef BCM_RIOT_SUPPORT 31544 /* 31545 * TD2+ has a separate encoding values for different destinations. 31546 * If Riot in not enabled then we may need to change this to 31547 * modid + port combination. 31548 */ 31549 if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 31550 BCM_IF_ERROR_RETURN( 31551 bcmi_l3_nh_dest_set(unit, nh_entry, &nh_dest)); 31552 31553 soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf, 31554 nh_dest); 31555 31556 LOG_INFO(BSL_LS_BCM_L3, (BSL_META_U(unit, 31557 "Setting up destination = 0x%x for port = 0x%x\n"), nh_dest, 31558 nh_entry->port)); 31559 } else 31560 #ifdef BCM_TRIDENT3_SUPPORT 31561 if (soc_feature(unit, soc_feature_generic_dest)) { 31562 31563 BCM_IF_ERROR_RETURN( 31564 bcmi_td3_l3_nh_dest_set(unit, nh_entry, &nh_dest)); 31565 31566 soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf, 31567 nh_dest); 31568 } else 31569 #endif /* BCM_TRIDENT3_SUPPORT */ 31570 #endif /* BCM_RIOT_SUPPORT */ 31571 { 31572 if (soc_feature(unit, soc_feature_generic_dest)) { 31573 /* Set module id. */ 31574 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 31575 if (nh_entry->flags & BCM_L3_TGID) { 31576 soc_mem_field32_dest_set(unit, ING_L3_NEXT_HOPm, &in_entry, 31577 DESTINATIONf, SOC_MEM_FIF_DEST_LAG, nh_entry->port); 31578 } else { 31579 soc_mem_field32_dest_set(unit, ING_L3_NEXT_HOPm, &in_entry, 31580 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP, 31581 (nh_entry->module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | 31582 nh_entry->port)); 31583 } 31584 } 31585 } else { 31586 nh_port = nh_entry->port; 31587 #if defined(BCM_MONTEREY_SUPPORT) 31588 if (soc_feature(unit, soc_feature_xflow_macsec) && 31589 ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) || 31590 (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) { 31591 nh_port = 66; 31592 } 31593 #endif 31594 if (!SOC_IS_TOMAHAWK3(unit)) { 31595 /* Set module id. */ 31596 soc_mem_field32_set( 31597 unit, mem, &in_entry, MODULE_IDf, nh_entry->module); 31598 } 31599 #ifdef BCM_TRX_SUPPORT 31600 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 31601 31602 if (nh_entry->flags & BCM_L3_TGID) { 31603 soc_mem_field32_set(unit, mem, &in_entry, Tf, 1); 31604 soc_mem_field32_set(unit, mem, &in_entry, TGIDf, nh_port); 31605 } else { 31606 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0); 31607 soc_mem_field32_set( 31608 unit, mem, &in_entry, PORT_NUMf, nh_port); 31609 } 31610 } else 31611 #endif /* BCM_TRX_SUPPORT */ 31612 { 31613 /* Set port/trunk id. */ 31614 if (SOC_IS_TOMAHAWKX(unit)) { 31615 /* 31616 * implies the switch has a latency mode enabled. trunking 31617 * is not supported in any latency mode in TH. 31618 */ 31619 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0); 31620 soc_mem_field32_set( 31621 unit, mem, &in_entry, PORT_NUMf, nh_port); 31622 } else { 31623 soc_mem_field32_set( 31624 unit, mem, &in_entry, PORT_TGIDf, nh_port); 31625 } 31626 } 31627 } 31628 } 31629 31630 if (nh_entry->flags & BCM_L3_COPY_TO_CPU) { 31631 if (SOC_MEM_FIELD_VALID(unit, mem, COPY_TO_CPUf)) { 31632 soc_mem_field32_set(unit, mem, &in_entry, COPY_TO_CPUf, 1); 31633 } else { 31634 return (BCM_E_UNAVAIL); 31635 } 31636 } else { 31637 if (SOC_MEM_FIELD_VALID(unit, mem, COPY_TO_CPUf)) { 31638 soc_mem_field32_set(unit, mem, &in_entry, COPY_TO_CPUf, 0); 31639 } 31640 } 31641 31642 if (nh_entry->flags & BCM_L3_DST_DISCARD) { 31643 if (SOC_MEM_FIELD_VALID(unit, mem, DROPf)) { 31644 soc_mem_field32_set(unit, mem, &in_entry, DROPf, 1); 31645 } 31646 /* 31647 * Host or route entry will handle drop 31648 * condition no else required. 31649 */ 31650 } else { 31651 if (SOC_MEM_FIELD_VALID(unit, mem, DROPf)) { 31652 soc_mem_field32_set(unit, mem, &in_entry, DROPf, 0); 31653 } 31654 } 31655 31656 if (idx != BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit)) { 31657 /* Set interface is tunnel bit. */ 31658 BCM_IF_ERROR_RETURN 31659 (_bcm_xgs3_l3_get_tunnel_id(unit, nh_entry->intf, &tunnel_id)); 31660 31661 /* Set flag that packet going to be tunneled. */ 31662 if (tunnel_id) { 31663 if (SOC_MEM_FIELD_VALID(unit, mem, L3UC_TUNNEL_TYPEf)) { 31664 soc_mem_field32_set(unit, mem, &in_entry, L3UC_TUNNEL_TYPEf, 1); 31665 } 31666 #if defined(BCM_TRIUMPH_SUPPORT) 31667 if (SOC_MEM_FIELD_VALID(unit, mem, ENTRY_TYPEf)) { 31668 soc_mem_field32_set(unit, mem, &in_entry, ENTRY_TYPEf, 1); 31669 } 31670 #endif /* BCM_TRIUMPH_SUPPORT */ 31671 } 31672 } 31673 #ifdef BCM_TRIDENT2_SUPPORT 31674 if (soc_feature(unit, soc_feature_nat)) { 31675 uint32 entry_buf[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.*/ 31676 soc_mem_t vlan_mem = VLAN_MPLSm; 31677 #ifdef BCM_TRIDENT3_SUPPORT 31678 if (SOC_IS_TRIDENT3X(unit)) { 31679 vlan_mem = VLAN_TABm; 31680 } 31681 #endif 31682 31683 /* get realm id from the incoming interface */ 31684 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit) && 31685 SOC_MEM_FIELD_VALID(unit, vlan_mem, L3_IIFf)) { 31686 sal_memset(entry_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 31687 SOC_IF_ERROR_RETURN( 31688 soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, 31689 nh_entry->vlan, entry_buf)); 31690 iif.intf_id = soc_mem_field32_get(unit, vlan_mem, 31691 entry_buf, L3_IIFf); 31692 } else { 31693 iif.intf_id = nh_entry->vlan; 31694 } 31695 BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif)); 31696 31697 if (SOC_MEM_FIELD_VALID(unit, mem, DST_REALM_IDf)) { 31698 soc_mem_field32_set(unit, mem, &in_entry, DST_REALM_IDf, 31699 iif.nat_realm_id); 31700 } 31701 } 31702 #endif 31703 31704 /* Write ingress next hop entry. */ 31705 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem, idx, &in_entry)); 31706 31707 mem = EGR_L3_NEXT_HOPm; 31708 #ifdef BCM_TOMAHAWK3_SUPPORT 31709 mem2 = EGR_L3_NEXT_HOP_2m; 31710 #endif 31711 31712 /* Read egress next hop entry. */ 31713 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &eg_entry)); 31714 #ifdef BCM_TOMAHAWK3_SUPPORT 31715 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 31716 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOP_2m, idx, &eg_2_entry)); 31717 31718 } 31719 #endif 31720 #ifdef BCM_TRIDENT3_SUPPORT 31721 if (soc_feature(unit, soc_feature_flex_flow) && 31722 (nh_entry->flow_handle != 0)) { 31723 31724 BCM_IF_ERROR_RETURN 31725 (_bcm_td3_l3_flex_nh_add(unit, idx, nh_entry, (uint32 *)&eg_entry, 0)); 31726 31727 } 31728 else 31729 #endif 31730 { 31731 #if defined(BCM_GREYHOUND_SUPPORT) 31732 if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) { 31733 if ((nh_entry->flags & BCM_L3_IPMC) && 31734 !(nh_entry->flags & BCM_L3_L2GRE_ONLY) && 31735 !(nh_entry->flags & BCM_L3_VXLAN_ONLY)) { 31736 /* Special process for GH's L3MC entry. 31737 * 31738 * 1. write to egress nh entry for L3MC view only. 31739 * 2. write to a dummy INITIAL_ING_L3_NEXT_HOPm entry. 31740 * - this table and ING_L3_NEXT_HOPm are ignored for 31741 * IPMC logic in GH. 31742 */ 31743 31744 /* Set ENTRY_TYPE to L3MC view */ 31745 soc_mem_field32_set(unit, mem, &eg_entry, nh_entry_type_field[unit], 0x7); 31746 31747 /* set next hop interface number */ 31748 soc_mem_field32_set(unit, mem, &eg_entry, L3MC__INTF_NUMf, 31749 nh_entry->intf); 31750 31751 /* set l3mc_use_configured _mac */ 31752 if (nh_entry->flags & BCM_L3_KEEP_DSTMAC) { 31753 soc_mem_field32_set(unit, mem, &eg_entry, 31754 L3MC__L3MC_USE_CONFIGURED_MACf, 0); 31755 } else { 31756 /* Use MAC_ADDRESS configured in this table */ 31757 soc_mem_field32_set(unit, mem, &eg_entry, 31758 L3MC__L3MC_USE_CONFIGURED_MACf, 1); 31759 } 31760 31761 /* set l3mc_mac_address*/ 31762 soc_mem_mac_addr_set(unit, mem, &eg_entry, L3MC__MAC_ADDRESSf, 31763 nh_entry->mac_addr); 31764 31765 /* goto hw mem write operation */ 31766 goto l3mc_egr_nh_done; 31767 } 31768 } 31769 #endif /* BCM_GREYHOUND_SUPPORT */ 31770 31771 #if defined(BCM_TRIUMPH_SUPPORT) 31772 if (SOC_MEM_FIELD_VALID(unit, mem, nh_entry_type_field[unit])) { 31773 entry_type = soc_mem_field32_get (unit, mem, &eg_entry, 31774 nh_entry_type_field[unit]); 31775 } 31776 if ((nh_entry->oam_global_context_id) && 31777 SOC_MEM_FIELD_VALID(unit, mem, MPLS__MEPIDf)) { 31778 soc_mem_field32_set(unit, mem, &eg_entry, MPLS__MEPIDf, 31779 nh_entry->oam_global_context_id); 31780 /* Writing MPLS LM/DM value. it doesnt matter since 31781 data packets are similar for BHH and MPLS LM/DM */ 31782 soc_mem_field32_set(unit, mem, &eg_entry, MPLS__MPLS_OAM_DOWNMEP_ENABLEf, 31783 2); 31784 } 31785 if ((soc_feature(unit, soc_feature_nh_for_ifp_actions) || 31786 SOC_IS_TOMAHAWK3(unit)) && 31787 (nh_entry->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) { 31788 entry_type = 2; 31789 } 31790 #endif /* BCM_TRIUMPH_SUPPORT */ 31791 #ifdef BCM_TRIDENT3_SUPPORT 31792 if (SOC_IS_TRIDENT3X(unit)) { 31793 if (nh_entry->flags2 & BCM_L3_FLAGS2_FCOE_ONLY) { 31794 if (SOC_MEM_FIELD_VALID(unit, mem, DATA_TYPEf)) { 31795 soc_mem_field32_set(unit, mem, &eg_entry, DATA_TYPEf, 8); 31796 } 31797 } 31798 } 31799 #endif /* BCM_TRIDENT3_SUPPORT */ 31800 if ((entry_type == 0) || 31801 ((soc_feature(unit, soc_feature_nh_for_ifp_actions) || 31802 SOC_IS_TOMAHAWK3(unit)) && 31803 (entry_type == 2))) { /* L3 Unicast */ 31804 #ifdef BCM_TRIUMPH2_SUPPORT 31805 if (entry_type == 2) { 31806 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) { 31807 soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_VLAN_DISABLEf, 31808 _SHR_IS_FLAG_SET(nh_entry->flags, 31809 BCM_L3_KEEP_VLAN)); 31810 } 31811 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_TTL_DISABLEf)) { 31812 soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_TTL_DISABLEf, 31813 _SHR_IS_FLAG_SET(nh_entry->flags, 31814 BCM_L3_KEEP_TTL)); 31815 } 31816 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_DA_DISABLEf)) { 31817 soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_DA_DISABLEf, 31818 _SHR_IS_FLAG_SET(nh_entry->flags, 31819 BCM_L3_KEEP_DSTMAC)); 31820 } 31821 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_SA_DISABLEf)) { 31822 soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_SA_DISABLEf, 31823 _SHR_IS_FLAG_SET(nh_entry->flags, 31824 BCM_L3_KEEP_SRCMAC)); 31825 } 31826 } else { 31827 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_VLAN_DISABLEf)) { 31828 soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_VLAN_DISABLEf, 31829 _SHR_IS_FLAG_SET(nh_entry->flags, 31830 BCM_L3_KEEP_VLAN)); 31831 } 31832 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_TTL_DISABLEf)) { 31833 soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_TTL_DISABLEf, 31834 _SHR_IS_FLAG_SET(nh_entry->flags, 31835 BCM_L3_KEEP_TTL)); 31836 } 31837 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_DA_DISABLEf)) { 31838 soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_DA_DISABLEf, 31839 _SHR_IS_FLAG_SET(nh_entry->flags, 31840 BCM_L3_KEEP_DSTMAC)); 31841 } 31842 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_SA_DISABLEf)) { 31843 soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_SA_DISABLEf, 31844 _SHR_IS_FLAG_SET(nh_entry->flags, 31845 BCM_L3_KEEP_SRCMAC)); 31846 } 31847 } 31848 if (SOC_MEM_FIELD_VALID(unit, mem, L3__CLASS_IDf)) { 31849 soc_mem_field32_set(unit, mem, &eg_entry, L3__CLASS_IDf, 31850 nh_entry->intf_class); 31851 } 31852 #endif /* BCM_TRIUMPH2_SUPPORT */ 31853 #ifdef BCM_TRIDENT3_SUPPORT 31854 if (soc_feature(unit, soc_feature_flex_flow) && 31855 (nh_entry->flags2 & BCM_L3_FLAGS2_IFA_DST_PORT)) { 31856 if (nh_entry->port > (1 << BCMI_TD3_L3_NH_IFA_DST_PORT_SHIFT)) { 31857 return BCM_E_PARAM; 31858 } 31859 if (SOC_MEM_FIELD_VALID(unit, mem, L3__VNTAG_ACTIONSf)) { 31860 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_ACTIONSf, 1); 31861 } 31862 if (SOC_MEM_FIELD_VALID(unit, mem, L3__VNTAG_Pf)) { 31863 uint32 vntag_p = 31864 (nh_entry->module >> BCMI_TD3_L3_NH_IFA_DST_PORT_SHIFT) & 0x1; 31865 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_Pf, vntag_p); 31866 } 31867 if (SOC_MEM_FIELD_VALID(unit, mem, L3__VNTAG_DST_VIFf)) { 31868 uint32 vntag_dst_vif = 31869 (nh_entry->port & BCMI_TD3_L3_NH_IFA_DST_PORT_MASK) | 31870 ((nh_entry->module & BCMI_TD3_L3_NH_IFA_DST_PORT_MASK) << 31871 BCMI_TD3_L3_NH_IFA_DST_PORT_SHIFT); 31872 soc_mem_field32_set(unit, mem, &eg_entry, 31873 L3__VNTAG_DST_VIFf, vntag_dst_vif); 31874 } 31875 } 31876 #endif /* BCM_TRIDENT3_SUPPORT */ 31877 } 31878 31879 #ifdef BCM_TRIDENT2_SUPPORT 31880 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 31881 if (nh_entry->encap_id > 0 && 31882 nh_entry->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) { 31883 /* encap_id contains the virtual port value if it's greater than 0 and 31884 * less than the starting value of egress object ID. 31885 */ 31886 bcm_niv_port_t niv_port; 31887 int count; 31888 bcm_niv_egress_t niv_egress; 31889 int virtual_interface_id; 31890 bcm_extender_port_t ep; 31891 int etag_dot1p_mapping_ptr = 0; 31892 bcm_extender_egress_t extender_egress; 31893 uint16 extended_port_vid; 31894 uint8 pcp, de; 31895 uint32 pcp_de_select; 31896 int qos_map_id; 31897 31898 if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeNiv)) { 31899 /* NIV */ 31900 BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, nh_entry->encap_id); 31901 BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port)); 31902 if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) { 31903 BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit, 31904 niv_port.niv_port_id, 1, &niv_egress, &count)); 31905 if (count == 0) { 31906 /* No NIV egress object has been added to VP yet. */ 31907 return BCM_E_CONFIG; 31908 } 31909 if (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) { 31910 return BCM_E_PARAM; 31911 } 31912 virtual_interface_id = niv_egress.virtual_interface_id; 31913 } else { 31914 if (niv_port.flags & BCM_NIV_PORT_MULTICAST) { 31915 return BCM_E_PARAM; 31916 } 31917 virtual_interface_id = niv_port.virtual_interface_id; 31918 } 31919 if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) { 31920 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf, 31921 TRUE); 31922 } 31923 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf, 31924 nh_entry->encap_id); 31925 soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf, 31926 TRUE); /* PPD-2 header */ 31927 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_ACTIONSf, 31928 1); /* Add or replace VNTAG */ 31929 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_DST_VIFf, 31930 virtual_interface_id); 31931 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_Pf, 31932 0); 31933 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_FORCE_Lf, 31934 (niv_port.flags & BCM_NIV_VNTAG_L_BIT_FORCE_1) ? 1 : 0); 31935 #ifdef BCM_TOMAHAWK_SUPPORT 31936 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 31937 if (nh_entry->flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) { 31938 soc_mem_field32_set(unit, mem, &eg_entry, 31939 L3__HG_VNTAG_MODIFY_ENABLEf, 1); 31940 } else { 31941 soc_mem_field32_set(unit, mem, &eg_entry, 31942 L3__HG_VNTAG_MODIFY_ENABLEf, 0); 31943 } 31944 } 31945 #endif 31946 } else if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeExtender)) { 31947 /* Port Extender */ 31948 BCM_GPORT_EXTENDER_PORT_ID_SET(ep.extender_port_id, nh_entry->encap_id); 31949 BCM_IF_ERROR_RETURN(bcm_esw_extender_port_get(unit, &ep)); 31950 if (ep.flags & BCM_EXTENDER_PORT_MATCH_NONE) { 31951 bcm_extender_egress_t_init(&extender_egress); 31952 BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit, 31953 ep.extender_port_id, 1, &extender_egress, &count)); 31954 if (count == 0) { 31955 /* No Extender egress object has been added to VP yet. */ 31956 return BCM_E_CONFIG; 31957 } 31958 if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) { 31959 return BCM_E_PARAM; 31960 } 31961 qos_map_id = extender_egress.qos_map_id; 31962 extended_port_vid = extender_egress.extended_port_vid; 31963 pcp_de_select = extender_egress.pcp_de_select; 31964 pcp = extender_egress.pcp; 31965 de = extender_egress.de; 31966 } else { 31967 if (ep.flags & BCM_EXTENDER_PORT_MULTICAST) { 31968 return BCM_E_PARAM; 31969 } 31970 qos_map_id = ep.qos_map_id; 31971 extended_port_vid = ep.extended_port_vid; 31972 pcp_de_select = ep.pcp_de_select; 31973 pcp = ep.pcp; 31974 de = ep.de; 31975 } 31976 31977 if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) { 31978 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf, 31979 TRUE); 31980 } 31981 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf, 31982 nh_entry->encap_id); 31983 soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf, 31984 TRUE); /* PPD-2 header */ 31985 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_ACTIONSf, 31986 0x2); /* Add or replace ETAG */ 31987 soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_DST_VIFf, 31988 extended_port_vid); 31989 if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_DEFAULT) { 31990 soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_PCP_DE_SOURCEf, 0x2); 31991 soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_PCPf, pcp); 31992 soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_DEf, de); 31993 } else if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_PHB) { 31994 soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_PCP_DE_SOURCEf, 0x3); 31995 bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id, 31996 &etag_dot1p_mapping_ptr); 31997 soc_mem_field32_set(unit, mem, &eg_entry, 31998 L3__ETAG_DOT1P_MAPPING_PTRf, etag_dot1p_mapping_ptr); 31999 } 32000 #ifdef BCM_TOMAHAWK_SUPPORT 32001 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 32002 if (nh_entry->flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) { 32003 soc_mem_field32_set(unit, mem, &eg_entry, 32004 L3__HG_VNTAG_MODIFY_ENABLEf, 1); 32005 } else { 32006 soc_mem_field32_set(unit, mem, &eg_entry, 32007 L3__HG_VNTAG_MODIFY_ENABLEf, 0); 32008 } 32009 } 32010 #endif 32011 } else if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeVlan) || 32012 _bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeMpls)) { 32013 /* VEPA or MPLS */ 32014 if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) { 32015 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf, 32016 TRUE); 32017 } 32018 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf, 32019 nh_entry->encap_id); 32020 soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf, 32021 TRUE); /* PPD-2 header */ 32022 } 32023 } else if (nh_entry->encap_id >= BCM_XGS3_EGRESS_IDX_MIN(unit)) { 32024 return BCM_E_PARAM; 32025 } else if (entry_type == 0) { 32026 32027 /* Zero-out DVP values for regular NH */ 32028 if (SOC_MEM_FIELD_VALID(unit, mem, L3__DVP_VALIDf)) { 32029 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf, FALSE); 32030 } 32031 32032 if (SOC_MEM_FIELD_VALID(unit, mem, L3__DVPf)) { 32033 soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf, 0x0); 32034 } 32035 32036 if (SOC_MEM_FIELD_VALID(unit, mem, L3__HG_HDR_SELf)) { 32037 soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf, 32038 _SHR_IS_FLAG_SET(nh_entry->flags2, 32039 BCM_L3_FLAGS2_NON_PROXY_MODE)); 32040 } 32041 32042 } 32043 } 32044 #endif /* BCM_TRIDENT2_SUPPORT */ 32045 32046 #ifdef BCM_TRIUMPH2_SUPPORT 32047 if (soc_feature(unit, soc_feature_wlan) && 32048 (nh_entry->encap_id > 0 && 32049 nh_entry->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) && 32050 _bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeWlan)) { 32051 /* Set ENTRY_TYPE to WLAN DVP */ 32052 if (SOC_MEM_FIELD_VALID(unit, mem, nh_entry_type_field[unit])) { 32053 soc_mem_field32_set(unit, mem, &eg_entry, nh_entry_type_field[unit], 4); 32054 } 32055 /* Set next hop mac address. */ 32056 soc_mem_mac_addr_set(unit, mem, &eg_entry, WLAN__MAC_ADDRESSf, 32057 nh_entry->mac_addr); 32058 /* Set interface id. */ 32059 soc_mem_field32_set(unit, mem, &eg_entry, WLAN__INTF_NUMf, 32060 nh_entry->intf); 32061 /* Set the DVP */ 32062 soc_mem_field32_set(unit, mem, &eg_entry, WLAN__DVPf, 32063 nh_entry->encap_id); 32064 #if defined(BCM_TRIUMPH3_SUPPORT) 32065 if (SOC_IS_TRIUMPH3(unit)) { 32066 soc_mem_field32_set(unit, mem, &eg_entry, WLAN__DGLPf, 32067 BCM_L3_DGLP_GET(nh_entry->module, nh_entry->port)); 32068 } 32069 #endif /* BCM_TRIUMPH3_SUPPORT */ 32070 } else 32071 #endif /* BCM_TRIUMPH2_SUPPORT */ 32072 { 32073 soc_field_t mac_addr_field = MAC_ADDRESSf; 32074 soc_field_t intf_field = INTF_NUMf; 32075 32076 if (SOC_IS_TRIDENT3X(unit)) { 32077 mac_addr_field = L3__MAC_ADDRESSf; 32078 intf_field = L3__INTF_NUMf; 32079 } 32080 if (entry_type == 0) { 32081 /* Set next hop mac address. */ 32082 soc_mem_mac_addr_set(unit, mem, &eg_entry, mac_addr_field, 32083 nh_entry->mac_addr); 32084 } else if ((entry_type == 6) || 32085 ((SOC_IS_TOMAHAWK3(unit)) && (entry_type == 2))) { 32086 if (soc_mem_field_valid(unit, mem, IFP_ACTIONS__MAC_ADDRESSf)) { 32087 soc_mem_mac_addr_set(unit, mem, &eg_entry, 32088 IFP_ACTIONS__MAC_ADDRESSf, 32089 nh_entry->mac_addr); 32090 } 32091 } else if (entry_type == 7) { 32092 if (soc_mem_field_valid(unit, mem, L3MC__MAC_ADDRESSf)) { 32093 soc_mem_mac_addr_set(unit, mem, &eg_entry, L3MC__MAC_ADDRESSf, 32094 nh_entry->mac_addr); 32095 } 32096 #ifdef BCM_TRIDENT3_SUPPORT 32097 if (SOC_IS_TRIDENT3X(unit)) { 32098 intf_field = L3MC__INTF_NUMf; 32099 } 32100 #endif 32101 } 32102 /* Set interface id. */ 32103 #ifdef BCM_TOMAHAWK3_SUPPORT 32104 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 32105 soc_mem_field32_set(unit, mem2, &eg_2_entry, INTF_NUMf, nh_entry->intf); 32106 } else 32107 #endif 32108 { 32109 soc_mem_field32_set(unit, mem, &eg_entry, intf_field, nh_entry->intf); 32110 } 32111 } 32112 } 32113 #if defined(BCM_MONTEREY_SUPPORT) 32114 if (soc_feature(unit, soc_feature_xflow_macsec) && 32115 ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) || 32116 (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) { 32117 switch (entry_type) { 32118 case 0: 32119 field = L3__MACSEC_ENCRYPTf; 32120 field2 = L3__MACSEC_DECRYPTf; 32121 break; 32122 case 1: 32123 field = MPLS__MACSEC_ENCRYPTf; 32124 field2 = MPLS__MACSEC_DECRYPTf; 32125 break; 32126 case 2: 32127 field = SD_TAG__MACSEC_ENCRYPTf; 32128 field2 = SD_TAG__MACSEC_DECRYPTf; 32129 break; 32130 case 6: 32131 field = IFP_ACTIONS__MACSEC_ENCRYPTf; 32132 field2 = IFP_ACTIONS__MACSEC_DECRYPTf; 32133 break; 32134 case 7: 32135 field = L3MC__MACSEC_ENCRYPTf; 32136 field2 = L3MC__MACSEC_DECRYPTf; 32137 break; 32138 default: 32139 break; 32140 } 32141 if ((field != INVALIDf) && (field2 != INVALIDf)) { 32142 if (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) { 32143 soc_mem_field32_set(unit, mem, &eg_entry, field, 1); 32144 } else { 32145 soc_mem_field32_set(unit, mem, &eg_entry, field, 0); 32146 } 32147 32148 if (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT) { 32149 soc_mem_field32_set(unit, mem, &eg_entry, field2, 1); 32150 } else { 32151 soc_mem_field32_set(unit, mem, &eg_entry, field2, 0); 32152 } 32153 } 32154 32155 if (entry_type == 0) { /* L3 Unicast */ 32156 soc_mem_field32_set(unit, mem, &eg_entry, L3__DST_MOD_IDf, nh_entry->module); 32157 soc_mem_field32_set(unit, mem, &eg_entry, L3__DST_PORT_NUMf, nh_entry->port); 32158 } else if (entry_type == 6) { /* IFP Actions */ 32159 soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__DST_MOD_IDf, nh_entry->module); 32160 soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__DST_PORT_NUMf, nh_entry->port); 32161 } 32162 } 32163 #endif /* defined(BCM_MONTEREY_SUPPORT) */ 32164 32165 #if defined(BCM_GREYHOUND_SUPPORT) 32166 l3mc_egr_nh_done: 32167 #endif /* BCM_GREYHOUND_SUPPORT */ 32168 32169 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem, idx, &eg_entry)); 32170 #ifdef BCM_TOMAHAWK3_SUPPORT 32171 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 32172 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem2, idx, &eg_2_entry)); 32173 } 32174 #endif 32175 32176 /* 32177 * Set to indicate that L3 interface is used in Next Hop entry. 32178 * This is used to skip the Next Hop table search in 32179 * _bcm_fb_nh_intf_is_tnl_update(). 32180 */ 32181 BCM_XGS3_L3_INTF_USED_NH_SET(unit, nh_entry->intf); 32182 32183 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 32184 defined(BCM_TRX_SUPPORT) 32185 /* Write initial ingress next hop entry. */ 32186 mem = INITIAL_ING_L3_NEXT_HOPm; 32187 if (!SOC_MEM_IS_VALID(unit, mem) || !soc_mem_index_max(unit, mem) || 32188 !soc_mem_index_count(unit, mem)) { 32189 return (BCM_E_NONE); 32190 } 32191 /* Reset ingress buffer. */ 32192 sal_memset(&in_entry, 0, sizeof(ing_l3_next_hop_entry_t)); 32193 /* Read initial ingress next hop entry. */ 32194 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &in_entry)); 32195 32196 32197 #ifdef BCM_RIOT_SUPPORT 32198 /* 32199 * TD2+ has a separate encoding values for different destinations. 32200 * If Riot in not enabled then we may need to change this to 32201 * modid + port combination. 32202 */ 32203 if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 32204 soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf, 32205 nh_dest); 32206 LOG_INFO(BSL_LS_BCM_L3, (BSL_META_U(unit, 32207 "Setting up destination = 0x%x for port = 0x%x\n"), 32208 nh_dest, nh_entry->port)); 32209 } else 32210 #ifdef BCM_TRIDENT3_SUPPORT 32211 if (soc_feature(unit, soc_feature_generic_dest)) { 32212 soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf, 32213 nh_dest); 32214 } else 32215 #endif /* BCM_TRIDENT3_SUPPORT */ 32216 #endif /* BCM_RIOT_SUPPORT */ 32217 { 32218 nh_port = nh_entry->port; 32219 #if defined(BCM_MONTEREY_SUPPORT) 32220 if (soc_feature(unit, soc_feature_xflow_macsec) && 32221 ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) || 32222 (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) { 32223 nh_port = 66; 32224 } 32225 #endif 32226 if (!SOC_IS_TOMAHAWK3(unit)) { 32227 /* Set module id to initial ingress l3 next hop entry. */ 32228 soc_mem_field32_set(unit, mem, &in_entry, MODULE_IDf, 32229 nh_entry->module); 32230 } 32231 #ifdef BCM_TRX_SUPPORT 32232 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 32233 if (nh_entry->flags & BCM_L3_TGID) { 32234 soc_mem_field32_set(unit, mem, &in_entry, Tf, 1); 32235 soc_mem_field32_set(unit, mem, &in_entry, TGIDf, 32236 nh_port); 32237 } else { 32238 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0); 32239 soc_mem_field32_set(unit, mem, &in_entry, PORT_NUMf, 32240 nh_port); 32241 } 32242 } else 32243 #endif /* BCM_TRX_SUPPORT */ 32244 { 32245 /* Set port/trunk id. */ 32246 if (SOC_IS_TOMAHAWKX(unit)) { 32247 /* 32248 * implies the switch has a latency mode enabled. trunking is 32249 * not supported in any latency mode in TH. 32250 */ 32251 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0); 32252 soc_mem_field32_set(unit, mem, &in_entry, PORT_NUMf, 32253 nh_port); 32254 } else { 32255 soc_mem_field32_set(unit, mem, &in_entry, PORT_TGIDf, 32256 nh_port); 32257 } 32258 } 32259 } 32260 #ifdef BCM_TRIDENT2_SUPPORT 32261 if (soc_feature(unit, soc_feature_nat) && SOC_MEM_FIELD_VALID(unit, mem, 32262 DST_REALM_IDf)) { 32263 soc_mem_field32_set(unit, mem, &in_entry, DST_REALM_IDf, 32264 iif.nat_realm_id); 32265 } 32266 #endif 32267 32268 /* Write buffer to hw. */ 32269 return BCM_XGS3_MEM_WRITE(unit, mem, idx, &in_entry); 32270 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 32271 32272 return (BCM_E_NONE); 32273 } 32274 32275 32276 /* 32277 * Function: 32278 * _bcm_fb_nh_intf_is_tnl_update 32279 * Purpose: 32280 * Routine updates next hop interface is tunnel bit. 32281 * Routine updates all next hop entries using a certain 32282 * interface tunnel bit. 32283 * Parameters: 32284 * unit - (IN)SOC unit number. 32285 * intf - (IN)Interface index to update. 32286 * tunnel_id - (IN)Tunnel index. 32287 * Returns: 32288 * BCM_E_XXX 32289 */ 32290 STATIC int 32291 _bcm_fb_nh_intf_is_tnl_update(int unit, bcm_if_t intf, int tunnel_id) 32292 { 32293 uint32 *ing_entry_ptr; /* Ingress next hop entry pointer.*/ 32294 char *ing_tbl_ptr; /* Dma table pointer. */ 32295 int ifindex; /* Interface index. */ 32296 soc_mem_t mem; /* Next hop memory. */ 32297 int idx; /* Iteration index. */ 32298 char *egr_tbl_ptr; /* Dma egress nh table pointer. */ 32299 uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pointer. */ 32300 int rv = BCM_E_NONE; /* Operation return status. */ 32301 #if defined(BCM_TRIUMPH_SUPPORT) 32302 soc_field_t entry_type_field = 0; 32303 32304 if (SOC_IS_TRIDENT3X(unit)) { 32305 entry_type_field = DATA_TYPEf; 32306 } else { 32307 entry_type_field = ENTRY_TYPEf; 32308 } 32309 #endif 32310 /* Check if L3 interface is used in Next Hop table. */ 32311 if (!BCM_XGS3_L3_INTF_USED_NH_GET(unit, intf)) { 32312 return BCM_E_NONE; 32313 } 32314 32315 /* Get next table memory. */ 32316 mem = BCM_XGS3_L3_MEM(unit, nh); 32317 32318 /* Lock ingress next hop table. */ 32319 32320 /* Table DMA the nhtable to software copy */ 32321 rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl", 32322 &ing_tbl_ptr, NULL); 32323 BCM_IF_ERROR_RETURN(rv); 32324 32325 /* Read egress next hop entry. */ 32326 rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm, 32327 sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl", 32328 &egr_tbl_ptr, NULL); 32329 if (rv < 0) { 32330 soc_cm_sfree(unit, ing_tbl_ptr); 32331 return rv; 32332 } 32333 32334 for (idx = 0; idx < BCM_XGS3_L3_NH_TBL_SIZE(unit); idx++) { 32335 /* Skip unused entries. */ 32336 if (!BCM_XGS3_L3_ENT_REF_CNT 32337 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) { 32338 continue; 32339 } 32340 32341 /* Skip trap to CPU entry internally installed entry. */ 32342 if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) { 32343 continue; 32344 } 32345 32346 /* Read egress next hop entry. */ 32347 egr_entry_ptr = 32348 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm, 32349 uint32 *, egr_tbl_ptr, idx); 32350 32351 /* Get interface index. */ 32352 ifindex = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 32353 egr_entry_ptr, INTF_NUMf); 32354 if (ifindex != intf) { 32355 continue; 32356 } 32357 32358 /* Calculate entry ofset. */ 32359 ing_entry_ptr = 32360 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx); 32361 if (SOC_MEM_FIELD_VALID(unit, mem, L3UC_TUNNEL_TYPEf)) { 32362 soc_mem_field32_set(unit, mem, ing_entry_ptr, L3UC_TUNNEL_TYPEf, 32363 (tunnel_id > 0) ? 1 : 0); 32364 } 32365 #if defined(BCM_TRIUMPH_SUPPORT) 32366 if (SOC_MEM_FIELD_VALID(unit, mem, entry_type_field)) { 32367 soc_mem_field32_set(unit, mem, ing_tbl_ptr, entry_type_field, 32368 (tunnel_id > 0) ? 1 : 0); 32369 } 32370 #endif /* BCM_TRIUMPH_SUPPORT */ 32371 } 32372 32373 /* Write the buffer back. */ 32374 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 32375 soc_mem_index_min(unit, mem), 32376 soc_mem_index_max(unit, mem), ing_tbl_ptr); 32377 32378 soc_cm_sfree(unit, ing_tbl_ptr); 32379 soc_cm_sfree(unit, egr_tbl_ptr); 32380 return (rv); 32381 } 32382 32383 /* 32384 * Function: 32385 * _bcm_fb_l3_ipmc_ent_init 32386 * Purpose: 32387 * Set GROUP/SOURCE/VID/IMPC flag in the entry. 32388 * Parameters: 32389 * unit - (IN)SOC unit number. 32390 * l3x_entry - (IN/OUT) IPMC entry to fill. 32391 * l3cfg - (IN) Api IPMC data. 32392 * Returns: 32393 * BCM_E_XXX 32394 */ 32395 STATIC void 32396 _bcm_fb_l3_ipmc_ent_init(int unit, uint32 *buf_p, _bcm_l3_cfg_t *l3cfg) 32397 { 32398 soc_mem_t mem; /* IPMC table memory. */ 32399 int ipv6; /* IPv6 entry indicator. */ 32400 soc_field_t v6f[] = { V6_0f, V6_1f, V6_2f, V6_3f }; 32401 soc_field_t mcf[] = { IPMC_0f, IPMC_1f, IPMC_2f, IPMC_3f }; 32402 soc_field_t vidf[] = { VLAN_ID_0f, VLAN_ID_1f, VLAN_ID_2f, VLAN_ID_3f }; 32403 soc_field_t validf[] = { VALID_0f, VALID_1f, VALID_2f, VALID_3f }; 32404 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 32405 defined(BCM_TRX_SUPPORT) 32406 soc_field_t vrff[] = { VRF_ID_0f, VRF_ID_1f, VRF_ID_2f, VRF_ID_3f }; 32407 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 32408 int idx; 32409 32410 /* Get entry type. */ 32411 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 32412 32413 /* Get table memory. */ 32414 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 32415 sal_memset(buf_p, 0, (ipv6) ? BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) : \ 32416 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4)); 32417 if (ipv6) { 32418 /* Set group address. */ 32419 soc_mem_ip6_addr_set(unit, mem, buf_p, GROUP_IP_ADDR_LWR_64f, 32420 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 32421 l3cfg->l3c_ip6[0] = 0x0; /* Don't write ff entry already mcast. */ 32422 soc_mem_ip6_addr_set(unit, mem, buf_p, GROUP_IP_ADDR_UPR_56f, 32423 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 32424 l3cfg->l3c_ip6[0] = 0xff; /* Restore The entry */ 32425 32426 /* Set source address. */ 32427 soc_mem_ip6_addr_set(unit, mem, buf_p, SOURCE_IP_ADDR_LWR_64f, 32428 l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY); 32429 soc_mem_ip6_addr_set(unit, mem, buf_p, SOURCE_IP_ADDR_UPR_64f, 32430 l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY); 32431 32432 for (idx = 0; idx < 4; idx++) { 32433 /* Set address v6 bit. */ 32434 soc_mem_field32_set(unit, mem, buf_p, v6f[idx], 1); 32435 32436 /* Set address is multicast. */ 32437 soc_mem_field32_set(unit, mem, buf_p, mcf[idx], 1); 32438 32439 /* Set vlan id. */ 32440 soc_mem_field32_set(unit, mem, buf_p, vidf[idx], l3cfg->l3c_vid); 32441 32442 /* Set entry valid flag. */ 32443 soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1); 32444 32445 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 32446 defined(BCM_TRX_SUPPORT) 32447 /* Set virtual router id. */ 32448 /*vrf id feild is reserved in hurricane*/ 32449 if ((!(SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit))) && 32450 (SOC_MEM_FIELD_VALID(unit, mem, vrff[idx]))) { 32451 soc_mem_field32_set(unit, mem, buf_p, 32452 vrff[idx], l3cfg->l3c_vrf); 32453 } 32454 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 32455 } 32456 } else { 32457 /* Set group id. */ 32458 soc_mem_field32_set(unit, mem, buf_p, GROUP_IP_ADDRf, 32459 l3cfg->l3c_ip_addr); 32460 32461 /* Set source address. */ 32462 soc_mem_field32_set(unit, mem, buf_p, SOURCE_IP_ADDRf, 32463 l3cfg->l3c_src_ip_addr); 32464 32465 /* Set vlan id. */ 32466 soc_mem_field32_set(unit, mem, buf_p, VLAN_IDf, l3cfg->l3c_vid); 32467 32468 /* Set multicast flag. */ 32469 soc_mem_field32_set(unit, mem, buf_p, IPMCf, 1); 32470 32471 /* Set entry valid flag. */ 32472 soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1); 32473 32474 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 32475 defined(BCM_TRX_SUPPORT) 32476 /* Set virtual router id. */ 32477 /* vrf id is reserved in hurricane*/ 32478 if ((!(SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) || 32479 SOC_IS_GREYHOUND2(unit))) && 32480 (SOC_MEM_FIELD_VALID(unit, mem, VRF_IDf))) { 32481 soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, l3cfg->l3c_vrf); 32482 } 32483 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 32484 } 32485 32486 return; 32487 32488 } 32489 32490 /* 32491 * Function: 32492 * _bcm_fb_l3_ipmc_ent_parse 32493 * Purpose: 32494 * Service routine used to parse hw l3 ipmc entry to api format. 32495 * Parameters: 32496 * unit - (IN)SOC unit number. 32497 * l3cfg - (IN/OUT)l3 entry parsing destination buf. 32498 * l3x_entry - (IN/OUT)hw buffer. 32499 * Returns: 32500 * void 32501 */ 32502 STATIC INLINE void 32503 _bcm_fb_l3_ipmc_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg, 32504 l3_entry_ipv6_multicast_entry_t *l3x_entry) 32505 { 32506 _bcm_l3_fields_t *fld; /* IPMC table fields. */ 32507 soc_mem_t mem; /* IPMC table memory. */ 32508 uint32 *buf_p; /* HW buffer address. */ 32509 int ipv6; /* IPv6 entry indicator. */ 32510 int idx; /* Iteration index. */ 32511 soc_field_t hitf[] = {HIT_1f, HIT_2f, HIT_3f }; 32512 32513 buf_p = (uint32 *)l3x_entry; 32514 32515 /* Get entry type. */ 32516 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 32517 32518 /* Extract l3 ipv6/4 fields information. */ 32519 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) :\ 32520 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4)); 32521 32522 /* Get table memory. */ 32523 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 32524 32525 /* Mark entry as multicast & clear rest of the flags. */ 32526 l3cfg->l3c_flags = BCM_L3_IPMC; 32527 if (ipv6) { 32528 l3cfg->l3c_flags |= BCM_L3_IP6; 32529 } 32530 32531 /* Read hit value. */ 32532 if(soc_mem_field32_get(unit, mem, buf_p, fld->hit)) { 32533 l3cfg->l3c_flags |= BCM_L3_HIT; 32534 } else if (ipv6) { 32535 /* Get hit bit. */ 32536 for (idx = 0; idx < 3; idx++) { 32537 if(soc_mem_field32_get(unit, mem, buf_p, hitf[idx])) { 32538 l3cfg->l3c_flags |= BCM_L3_HIT; 32539 break; 32540 } 32541 } 32542 } 32543 32544 /* Set ipv6 group address to multicast. */ 32545 if (ipv6) { 32546 l3cfg->l3c_ip6[0] = 0xff; /* Set entry ip to mcast address. */ 32547 } 32548 32549 /* Read priority override */ 32550 if(soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) { 32551 l3cfg->l3c_flags |= BCM_L3_RPE; 32552 } 32553 32554 /* Read destination discard bit. */ 32555 if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) { 32556 if(soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) { 32557 l3cfg->l3c_flags |= BCM_L3_DST_DISCARD; 32558 } 32559 } 32560 32561 /* Read Virtual Router Id. */ 32562 if (SOC_MEM_FIELD_VALID(unit, mem, fld->vrf)) { 32563 l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf); 32564 } else { 32565 l3cfg->l3c_vrf = BCM_L3_VRF_DEFAULT; 32566 } 32567 32568 /* */ 32569 l3cfg->l3c_ipmc_ptr = 32570 soc_mem_field32_get(unit, mem, buf_p, fld->l3mc_index); 32571 32572 /* Read priority value. */ 32573 l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority); 32574 32575 return; 32576 } 32577 32578 /* 32579 * Function: 32580 * _bcm_fb_l3_ipmc_get 32581 * Purpose: 32582 * Get l3 multicast entry. 32583 * Parameters: 32584 * unit - (IN)SOC unit number. 32585 * l3cfg - (IN/OUT)Group/Source key & Get result buffer. 32586 * Returns: 32587 * BCM_E_XXX 32588 */ 32589 STATIC int 32590 _bcm_fb_l3_ipmc_get(int unit, _bcm_l3_cfg_t *l3cfg) 32591 { 32592 l3_entry_ipv6_multicast_entry_t l3x_key; /* Lookup key buffer. */ 32593 l3_entry_ipv6_multicast_entry_t l3x_entry; /* Search result buffer. */ 32594 int clear_hit; /* Clear hit flag. */ 32595 soc_mem_t mem; /* IPMC table memory. */ 32596 int ipv6; /* IPv6 entry indicator. */ 32597 int rv; /* Return value. */ 32598 32599 /* Get entry type. */ 32600 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 32601 32602 /* Zero buffers. */ 32603 sal_memset(&l3x_key, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6)); 32604 sal_memset(&l3x_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6)); 32605 32606 /* Get table memory. */ 32607 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 32608 32609 /* Check if clear hit bit is required. */ 32610 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 32611 32612 /* Lookup Key preparation. */ 32613 _bcm_fb_l3_ipmc_ent_init(unit, (uint32 *)&l3x_key, l3cfg); 32614 32615 /* Perform hw lookup. */ 32616 #ifdef BCM_TRX_SUPPORT 32617 if (soc_feature(unit, soc_feature_generic_table_ops)) { 32618 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &l3cfg->l3c_hw_index, 32619 &l3x_key, &l3x_entry, 0); 32620 } else 32621 #endif /* BCM_TRX_SUPPORT */ 32622 { 32623 rv = soc_fb_l3x_lookup(unit, (void *)&l3x_key, (void *)&l3x_entry, 32624 &l3cfg->l3c_hw_index); 32625 } 32626 BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND); 32627 32628 /* Extract buffer information. */ 32629 _bcm_fb_l3_ipmc_ent_parse(unit, l3cfg, &l3x_entry); 32630 32631 /* Clear the HIT bit */ 32632 if (clear_hit) { 32633 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem, 32634 l3cfg, &l3x_entry)); 32635 } 32636 return rv; 32637 } 32638 32639 /* 32640 * Function: 32641 * _bcm_fb_l3_ipmc_add 32642 * Purpose: 32643 * Add l3 multicast entry. 32644 * Parameters: 32645 * unit - (IN)SOC unit number. 32646 * l3cfg - (IN/OUT)Group/Source key. 32647 * Returns: 32648 * BCM_E_XXX 32649 */ 32650 STATIC int 32651 _bcm_fb_l3_ipmc_add(int unit, _bcm_l3_cfg_t *l3cfg) 32652 { 32653 l3_entry_ipv6_multicast_entry_t l3x_entry; /* Write entry buffer. */ 32654 _bcm_l3_fields_t *fld; /* IPMC table fields. */ 32655 soc_mem_t mem; /* IPMC table memory. */ 32656 uint32 *buf_p; /* HW buffer address. */ 32657 int ipv6; /* IPv6 entry indicator. */ 32658 int idx; /* Iteration index. */ 32659 int rv; /* Return value. */ 32660 soc_field_t priorityf[] = { PRI_0f, PRI_1f, PRI_2f, PRI_3f }; 32661 soc_field_t idxf[] = { L3MC_INDEX_0f, L3MC_INDEX_1f, \ 32662 L3MC_INDEX_2f, L3MC_INDEX_3f }; 32663 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f }; 32664 soc_field_t rpef[] = { RPE_0f, RPE_1f, RPE_2f, RPE_3f }; 32665 soc_field_t dst_discf[] = { DST_DISCARD_0f, DST_DISCARD_1f,\ 32666 DST_DISCARD_2f, DST_DISCARD_3f }; 32667 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 32668 defined(BCM_TRX_SUPPORT) 32669 soc_field_t vrf_idf[] = { VRF_ID_0f, VRF_ID_1f, VRF_ID_2f, VRF_ID_3f}; 32670 #else /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 32671 soc_field_t vrf_idf[] = { INVALIDf, INVALIDf, INVALIDf, INVALIDf}; 32672 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 32673 /* Get entry type. */ 32674 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 32675 32676 /* Zero buffers. */ 32677 buf_p = (uint32 *)&l3x_entry; 32678 sal_memset(buf_p, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6)); 32679 32680 /* Get table memory. */ 32681 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 32682 32683 /* Extract l3 ipv6/4 fields information. */ 32684 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) :\ 32685 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4)); 32686 32687 /* Overwrite field values if entry is ipv4 */ 32688 if (!ipv6) { 32689 priorityf[0] = fld->priority; 32690 idxf[0] = fld->l3mc_index; 32691 hitf[0] = fld->hit; 32692 rpef[0] = fld->rpe; 32693 dst_discf[0] = fld->dst_discard; 32694 vrf_idf[0] = fld->vrf; 32695 } 32696 32697 /* Prepare entry to write. */ 32698 _bcm_fb_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg); 32699 32700 for (idx = 0; idx < 4; idx++) { 32701 /* Set hit bit. */ 32702 if (l3cfg->l3c_flags & BCM_L3_HIT) { 32703 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 1); 32704 } 32705 32706 /* Set priority override bit. */ 32707 if (l3cfg->l3c_flags & BCM_L3_RPE) { 32708 soc_mem_field32_set(unit, mem, buf_p, rpef[idx], 1); 32709 } 32710 32711 /* Set destination discard. */ 32712 if (SOC_MEM_FIELD_VALID(unit, mem, dst_discf[idx])) { 32713 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 32714 soc_mem_field32_set(unit, mem, buf_p, dst_discf[idx], 1); 32715 } 32716 } 32717 32718 /* Virtual router id. */ 32719 if (SOC_MEM_FIELD_VALID(unit, mem, vrf_idf[idx])) { 32720 soc_mem_field32_set(unit, mem, buf_p, vrf_idf[idx], l3cfg->l3c_vrf); 32721 } 32722 32723 /* Set priority. */ 32724 if (SOC_MEM_FIELD_VALID(unit, mem, priorityf[idx])) { 32725 int pri_field_len; 32726 int max_pri; 32727 32728 pri_field_len = soc_mem_field_length(unit, mem, priorityf[idx]); 32729 max_pri = (1 << pri_field_len) - 1; 32730 32731 /* 32732 * to validate the assigning priority : 32733 * - Different device may support different max priority. 32734 */ 32735 if (l3cfg->l3c_prio > max_pri) { 32736 return BCM_E_PARAM; 32737 } 32738 32739 soc_mem_field32_set(unit, mem, buf_p, 32740 priorityf[idx], l3cfg->l3c_prio); 32741 } 32742 32743 /* . */ 32744 soc_mem_field32_set(unit, mem, buf_p, idxf[idx], l3cfg->l3c_ipmc_ptr); 32745 32746 /* IPv4 entry needs only first field. */ 32747 if (!ipv6) { 32748 break; 32749 } 32750 } 32751 32752 /* Write entry to the hw. */ 32753 /* Handle replacement. */ 32754 if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) { 32755 rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p); 32756 } else { 32757 #ifdef BCM_TRX_SUPPORT 32758 if (soc_feature(unit, soc_feature_generic_table_ops)) { 32759 rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)buf_p); 32760 } else 32761 #endif /* BCM_TRX_SUPPORT */ 32762 { 32763 rv = soc_fb_l3x_insert(unit, (void *)buf_p); 32764 } 32765 } 32766 32767 /* Increment number of ipmc routes. */ 32768 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 32769 (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)++ : \ 32770 BCM_XGS3_L3_IP4_IPMC_CNT(unit)++; 32771 } 32772 return rv; 32773 } 32774 32775 /* 32776 * Function: 32777 * _bcm_fb_l3_ipmc_del 32778 * Purpose: 32779 * Delete l3 multicast entry. 32780 * Parameters: 32781 * unit - (IN)SOC unit number. 32782 * l3cfg - (IN)Group/Source deletion key. 32783 * Returns: 32784 * BCM_E_XXX 32785 */ 32786 STATIC int 32787 _bcm_fb_l3_ipmc_del(int unit, _bcm_l3_cfg_t *l3cfg) 32788 { 32789 l3_entry_ipv6_multicast_entry_t l3x_entry; /* Delete buffer. */ 32790 #ifdef BCM_TRX_SUPPORT 32791 soc_mem_t mem; /* IPMC table memory. */ 32792 #endif 32793 int ipv6; /* IPv6 entry indicator. */ 32794 int rv; /* Operation return value. */ 32795 32796 /* Get entry type. */ 32797 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 32798 32799 /* Zero entry buffer. */ 32800 sal_memset(&l3x_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6)); 32801 32802 /* Key preparation. */ 32803 _bcm_fb_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg); 32804 32805 /* Delete the entry from hw. */ 32806 #ifdef BCM_TRX_SUPPORT 32807 if (soc_feature(unit, soc_feature_generic_table_ops)) { 32808 /* Get table memory. */ 32809 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 32810 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry); 32811 } else 32812 #endif /* BCM_TRX_SUPPORT */ 32813 { 32814 rv = soc_fb_l3x_delete(unit, (void *)&l3x_entry); 32815 } 32816 32817 /* Decrement number of ipmc routes. */ 32818 if (rv >= 0) { 32819 (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)-- : \ 32820 BCM_XGS3_L3_IP4_IPMC_CNT(unit)--; 32821 } 32822 return rv; 32823 } 32824 32825 /* 32826 * Function: 32827 * _bcm_fb_l3_ipmc_get_by_idx 32828 * Purpose: 32829 * Get l3 multicast entry by entry index. 32830 * Parameters: 32831 * unit - (IN)SOC unit number. 32832 * dma_ptr - (IN)Table pointer in dma. 32833 * idx - (IN)Index to read. 32834 * l3cfg - (IN/OUT)Entry data. 32835 * Returns: 32836 * BCM_E_XXX 32837 */ 32838 STATIC int 32839 _bcm_fb_l3_ipmc_get_by_idx(int unit, void *dma_ptr, 32840 int idx, _bcm_l3_cfg_t *l3cfg) 32841 { 32842 l3_entry_ipv6_multicast_entry_t *l3x_entry_p; /* Read buffer address. */ 32843 l3_entry_ipv6_multicast_entry_t l3x_entry; /* Read buffer. */ 32844 _bcm_l3_fields_t *fld; /* IPMC table fields. */ 32845 soc_mem_t mem; /* IPMC table memory. */ 32846 uint32 ipv6; /* IPv6 entry indicator. */ 32847 int clear_hit; /* Clear hit bit indicator.*/ 32848 32849 /* Get entry type. */ 32850 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 32851 32852 /* Get table memory. */ 32853 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 32854 32855 /* Extract l3 ipv6/4 fields information. */ 32856 fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) :\ 32857 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4)); 32858 32859 /* Check if clear hit is required. */ 32860 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 32861 32862 if (NULL == dma_ptr) { /* Read from hardware. */ 32863 /* Zero buffers. */ 32864 l3x_entry_p = &l3x_entry; 32865 sal_memset(l3x_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6)); 32866 /* Read entry from hw. */ 32867 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, l3x_entry_p)); 32868 } else { /* Read from dma. */ 32869 l3x_entry_p = 32870 soc_mem_table_idx_to_pointer(unit, mem, 32871 l3_entry_ipv6_multicast_entry_t *, 32872 dma_ptr, idx); 32873 } 32874 32875 /* Ignore invalid entries. */ 32876 if (!soc_mem_field32_get(unit, mem, l3x_entry_p, fld->valid)) { 32877 return (BCM_E_NOT_FOUND); 32878 } 32879 32880 /* Get protocol. */ 32881 if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->v6_entry)){ 32882 l3cfg->l3c_flags = BCM_L3_IP6; 32883 } else { 32884 l3cfg->l3c_flags = 0; 32885 } 32886 32887 /* Get ipmc flag . */ 32888 if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->ipmc_entry)) { 32889 l3cfg->l3c_flags |= BCM_L3_IPMC; 32890 } 32891 32892 /* Ignore protocol mismatch & multicast entries. */ 32893 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 32894 (!(l3cfg->l3c_flags & BCM_L3_IPMC))) { 32895 return (BCM_E_NOT_FOUND); 32896 } 32897 32898 /* Set index to l3cfg. */ 32899 l3cfg->l3c_hw_index = idx; 32900 32901 if (ipv6) { 32902 /* Get group address. */ 32903 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, GROUP_IP_ADDR_LWR_64f, 32904 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 32905 32906 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, GROUP_IP_ADDR_UPR_56f, 32907 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 32908 32909 /* Get source address. */ 32910 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, SOURCE_IP_ADDR_LWR_64f, 32911 l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY); 32912 soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, SOURCE_IP_ADDR_UPR_64f, 32913 l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY); 32914 32915 l3cfg->l3c_ip6[0] = 0xff; /* Set entry to multicast*/ 32916 } else { 32917 /* Get group id. */ 32918 l3cfg->l3c_ip_addr = 32919 soc_mem_field32_get(unit, mem, l3x_entry_p, GROUP_IP_ADDRf); 32920 32921 /* Get source address. */ 32922 l3cfg->l3c_src_ip_addr = 32923 soc_mem_field32_get(unit, mem, l3x_entry_p, SOURCE_IP_ADDRf); 32924 } 32925 /* Get vlan id. */ 32926 l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, l3x_entry_p, fld->vlan_id); 32927 32928 /* Parse entry data. */ 32929 _bcm_fb_l3_ipmc_ent_parse(unit, l3cfg, l3x_entry_p); 32930 32931 /* Clear the HIT bit */ 32932 if (clear_hit) { 32933 BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem, 32934 l3cfg, l3x_entry_p)); 32935 } 32936 return (BCM_E_NONE); 32937 } 32938 32939 32940 /* 32941 * Function: 32942 * bcm_xgs3_internal_lpm_vrf_calc 32943 * Purpose: 32944 * Service routine used to translate API vrf id to hw specific. 32945 * Parameters: 32946 * unit - (IN)SOC unit number. 32947 * lpm_cfg - (IN)Prefix info. 32948 * vrf_id - (OUT)Internal vrf id. 32949 * vrf_mask - (OUT)Internal vrf mask. 32950 * Returns: 32951 * BCM_E_XXX 32952 */ 32953 int 32954 bcm_xgs3_internal_lpm_vrf_calc(int unit, _bcm_defip_cfg_t *lpm_cfg, 32955 int *vrf_id, int *vrf_mask) 32956 { 32957 /* Handle special vrf id cases. */ 32958 switch (lpm_cfg->defip_vrf) { 32959 case BCM_L3_VRF_OVERRIDE: 32960 *vrf_id = 0; 32961 *vrf_mask = 0; 32962 break; 32963 case BCM_L3_VRF_GLOBAL: 32964 *vrf_id = SOC_VRF_MAX(unit); 32965 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m) || 32966 SOC_MEM_FIELD_VALID(unit, 32967 BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) { 32968 *vrf_id = 0; 32969 } 32970 *vrf_mask = 0; 32971 break; 32972 default: 32973 *vrf_id = lpm_cfg->defip_vrf; 32974 *vrf_mask = SOC_VRF_MAX(unit); 32975 } 32976 32977 /* In any case vrf id shouldn't exceed max field mask. */ 32978 if ((*vrf_id < 0) || (*vrf_id > SOC_VRF_MAX(unit))) { 32979 return (BCM_E_PARAM); 32980 } 32981 return (BCM_E_NONE); 32982 } 32983 32984 /* 32985 * Function: 32986 * bcm_ext_lpm_vrf_get 32987 * Purpose: 32988 * Service routine used to translate hw specific vrf id to API format. 32989 * i.e. Reverse operation of bcm_xgs3_internal_lpm_vrf_calc 32990 * Parameters: 32991 * unit - (IN)SOC unit number. 32992 * vrf_id - (IN)Virtual router id from HW entry 32993 * vrf_mask - (IN)VRF Mask from HW entry 32994 * global - (IN)GLOBAL_ROUTE field from HW entry 32995 * Returns: 32996 * VRF in API format 32997 */ 32998 int 32999 bcm_ext_lpm_vrf_get(int unit, int vrf_id, int vrf_mask, int global) 33000 { 33001 int vrf; 33002 33003 /* Special vrf's handling. */ 33004 if (vrf_mask) { 33005 vrf = vrf_id; 33006 } else if (SOC_VRF_MAX(unit) == vrf_id) { 33007 vrf = SOC_L3_VRF_GLOBAL; 33008 } else { 33009 vrf = SOC_L3_VRF_OVERRIDE; 33010 if (global) { 33011 vrf = SOC_L3_VRF_GLOBAL; 33012 } 33013 } 33014 return vrf; 33015 } 33016 33017 /* 33018 * Function: 33019 * _bcm_fb_lpm_ent_parse 33020 * Purpose: 33021 * Parse an entry from DEFIP table. 33022 * Parameters: 33023 * unit - (IN)SOC unit number. 33024 * lpm_cfg - (OUT)Buffer to fill defip information. 33025 * nh_ecmp_idx - (OUT)Next hop index or ecmp group id. 33026 * lpm_entry - (IN) Buffer read from hw. 33027 * Returns: 33028 * void 33029 */ 33030 int 33031 _bcm_fb_lpm_ent_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx, 33032 uint32 *lpm_entry, int *b128) 33033 { 33034 int ipv6; 33035 soc_mem_t mem = L3_DEFIPm; 33036 33037 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 33038 mem = L3_DEFIP_LEVEL1m; 33039 } 33040 33041 /* Reset entry flags first. */ 33042 lpm_cfg->defip_flags = 0; 33043 33044 /* Get hit bit. */ 33045 if (soc_mem_field32_get(unit, mem, lpm_entry, HIT0f)) { 33046 lpm_cfg->defip_flags |= BCM_L3_HIT; 33047 } 33048 33049 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 33050 uint32 _key_data[2]; 33051 uint32 mode = 0; 33052 sal_memset(_key_data, 0, sizeof(_key_data)); 33053 33054 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data); 33055 ipv6 = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf); 33056 33057 lpm_cfg->defip_ip_addr = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf); 33058 lpm_cfg->defip_entry_type = bcmDefipEntryTypeIp; 33059 mode = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf); 33060 lpm_cfg->defip_vrf = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf); 33061 33062 33063 if (ipv6) { 33064 if ((b128 != NULL) && (mode == 3)) { 33065 *b128 = 1; 33066 } 33067 33068 lpm_cfg->defip_flags |= BCM_L3_IP6; 33069 33070 /* Get hit bit from the second part of the entry. */ 33071 if (soc_mem_field32_get(unit, mem,lpm_entry, HIT1f)) { 33072 lpm_cfg->defip_flags |= BCM_L3_HIT; 33073 } 33074 } 33075 33076 soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, ASSOC_DATA0f, _key_data); 33077 lpm_cfg->defip_prio = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, PRIf); 33078 lpm_cfg->defip_lookup_class = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, CLASS_IDf); 33079 33080 if (nh_ecmp_idx) { 33081 *nh_ecmp_idx = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, 33082 _key_data, DESTINATIONf); 33083 } 33084 33085 if (soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, DEST_TYPEf)) { 33086 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 33087 lpm_cfg->defip_ecmp = 1; 33088 } 33089 33090 /* Get priority override bit. */ 33091 if (soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, RPEf)) { 33092 lpm_cfg->defip_flags |= BCM_L3_RPE; 33093 } 33094 33095 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 33096 lpm_cfg->defip_flex_ctr_mode = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, FLEX_CTR_OFFSET_MODEf); 33097 lpm_cfg->defip_flex_ctr_pool = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, FLEX_CTR_POOL_NUMBERf); 33098 lpm_cfg->defip_flex_ctr_base_id = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, FLEX_CTR_BASE_COUNTER_IDXf); 33099 } 33100 if (soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, DST_DISCARDf)) { 33101 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 33102 } 33103 return BCM_E_NONE; 33104 33105 } 33106 ipv6 = soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode0_bit[unit]); 33107 if (b128 != NULL && ipv6 == 3) { 33108 *b128 = 1; 33109 } 33110 33111 /* Get priority override bit. */ 33112 if (soc_mem_field32_get(unit, mem, lpm_entry, RPE0f)) { 33113 lpm_cfg->defip_flags |= BCM_L3_RPE; 33114 } 33115 33116 #ifdef BCM_TRIDENT3_SUPPORT 33117 if (soc_feature(unit, soc_feature_flex_flow)) { 33118 uint32 key_type; 33119 33120 key_type = soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, KEY_TYPE0f); 33121 33122 if (BCMI_LPM_FLEX_VIEW(key_type)) { 33123 return _bcm_td3_lpm_flex_ent_parse(unit, 33124 (uint32 *)lpm_entry, 33125 key_type, 33126 L3_DEFIPm, 33127 lpm_cfg, 33128 nh_ecmp_idx); 33129 } 33130 } 33131 #endif 33132 33133 /* Check if entry points to ecmp group. */ 33134 /*hurricane does not have ecmp flag*/ 33135 lpm_cfg->defip_ecmp = 0; 33136 if (SOC_IS_TRIDENT3X(unit)) { 33137 uint32 dest_type = 0; 33138 if (nh_ecmp_idx) { 33139 *nh_ecmp_idx = soc_mem_field32_dest_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, DESTINATION0f, 33140 &dest_type); 33141 } 33142 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 33143 lpm_cfg->defip_ecmp = 1; 33144 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 33145 } else { 33146 /* Mark entry as non-ecmp. */ 33147 lpm_cfg->defip_ecmp = 0; 33148 33149 /* Reset ecmp group next hop count. */ 33150 lpm_cfg->defip_ecmp_count = 0; 33151 } 33152 } else if ((!(SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit))) && 33153 (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f))) { 33154 lpm_cfg->defip_ecmp = 1; 33155 /* Mark entry as ecmp */ 33156 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 33157 33158 /* Get ecmp group id. */ 33159 if (nh_ecmp_idx) { 33160 *nh_ecmp_idx = 33161 soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f); 33162 } 33163 } else { 33164 /* Mark entry as non-ecmp. */ 33165 lpm_cfg->defip_ecmp = 0; 33166 33167 /* Reset ecmp group next hop count. */ 33168 lpm_cfg->defip_ecmp_count = 0; 33169 33170 /* Get next hop index. */ 33171 if (nh_ecmp_idx) { 33172 *nh_ecmp_idx = 33173 soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f); 33174 } 33175 } 33176 /* Get entry priority. */ 33177 lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f); 33178 33179 /* Get destination discard flag. */ 33180 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), DST_DISCARD0f)) { 33181 if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) { 33182 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 33183 } 33184 } 33185 33186 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ENTRY_TYPE0f)) { 33187 lpm_cfg->defip_entry_type = soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33188 ENTRY_TYPE0f); 33189 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, D_ID0f)) { 33190 lpm_cfg->defip_fcoe_d_id = soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33191 D_ID0f); 33192 lpm_cfg->defip_fcoe_d_id_mask = soc_L3_DEFIPm_field32_get(unit, 33193 lpm_entry, D_ID_MASK0f); 33194 } 33195 lpm_cfg->defip_vrf = soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33196 VRF_ID_0f); 33197 } 33198 #if defined(BCM_TRIDENT3_SUPPORT) 33199 else if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, KEY_TYPE0f)) { 33200 lpm_cfg->defip_entry_type = soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33201 KEY_TYPE0f); 33202 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, D_ID0f)) { 33203 lpm_cfg->defip_fcoe_d_id = soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33204 D_ID0f); 33205 lpm_cfg->defip_fcoe_d_id_mask = soc_L3_DEFIPm_field32_get(unit, 33206 lpm_entry, D_ID_MASK0f); 33207 } 33208 lpm_cfg->defip_vrf = soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33209 VRF_ID_0f); 33210 } 33211 #endif 33212 33213 #if defined(BCM_TRX_SUPPORT) 33214 /* Set classification group id. */ 33215 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) { 33216 lpm_cfg->defip_lookup_class = 33217 soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f); 33218 } 33219 #endif /* BCM_TRX_SUPPORT */ 33220 33221 33222 if (ipv6) { 33223 lpm_cfg->defip_flags |= BCM_L3_IP6; 33224 /* Get hit bit from the second part of the entry. */ 33225 if (ipv6 == 1) { 33226 if (soc_mem_field32_get(unit, mem,lpm_entry, HIT1f)) { 33227 lpm_cfg->defip_flags |= BCM_L3_HIT; 33228 } 33229 /* Get priority override bit from the second part of the entry. */ 33230 if (soc_mem_field32_get(unit, mem, lpm_entry, RPE1f)) { 33231 lpm_cfg->defip_flags |= BCM_L3_RPE; 33232 } 33233 } 33234 } 33235 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 33236 if (soc_feature(unit, soc_feature_ipmc_defip)) { 33237 int ipmc_route = 0; 33238 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 33239 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 33240 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 33241 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 33242 ipmc_route = 1; 33243 } else { 33244 ipmc_route = 0; 33245 } 33246 } 33247 33248 if (ipmc_route) { 33249 int val; 33250 lpm_cfg->defip_flags |= BCM_L3_IPMC; 33251 33252 if (nh_ecmp_idx) { 33253 *nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; 33254 } 33255 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f)) { 33256 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP; 33257 } 33258 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f)) { 33259 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 33260 } 33261 /* 33262 * RP ID and ExpectedIIF are overlaid. 33263 */ 33264 val = soc_L3_DEFIPm_field32_get(unit, lpm_entry, EXPECTED_L3_IIF0f); 33265 if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) { 33266 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIPm, RPA_ID0f)) - 1; 33267 /* 33268 * 1) If value is more than RPA_ID field then its l3_iif. 33269 * N/A for TD3/MV2/HX5 to support warmboot. 33270 * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid 33271 */ 33272 if ((lpm_cfg->defip_ipmc_flags & 33273 (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) || 33274 (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) || 33275 SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) { 33276 lpm_cfg->defip_expected_intf = val; 33277 if (0 != lpm_cfg->defip_expected_intf) { 33278 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 33279 } 33280 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 33281 } else { 33282 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE; 33283 lpm_cfg->defip_l3a_rp = val & rpa_id_mask; 33284 lpm_cfg->defip_expected_intf = val; 33285 } 33286 } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) { 33287 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val); 33288 } else { 33289 lpm_cfg->defip_expected_intf = val; 33290 if (0 != lpm_cfg->defip_expected_intf) { 33291 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 33292 } 33293 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 33294 } 33295 33296 if (soc_feature(unit, soc_feature_generic_dest)) { 33297 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 33298 uint32 dest_value = 0; 33299 dest_value = soc_mem_field32_dest_get(unit, 33300 L3_DEFIPm, lpm_entry, 33301 DESTINATION0f, &dest_type); 33302 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 33303 lpm_cfg->defip_mc_group = dest_value; 33304 } else { 33305 lpm_cfg->defip_mc_group = 0; 33306 } 33307 } else { 33308 lpm_cfg->defip_mc_group = 33309 soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f); 33310 } 33311 } 33312 } 33313 #endif 33314 #if defined(BCM_TRIDENT2_SUPPORT) 33315 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 33316 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, FLEX_CTR_OFFSET_MODE0f)) { 33317 lpm_cfg->defip_flex_ctr_mode = 33318 soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33319 FLEX_CTR_OFFSET_MODE0f); 33320 lpm_cfg->defip_flex_ctr_pool = 33321 soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33322 FLEX_CTR_POOL_NUMBER0f); 33323 lpm_cfg->defip_flex_ctr_base_id = 33324 soc_L3_DEFIPm_field32_get(unit, lpm_entry, 33325 FLEX_CTR_BASE_COUNTER_IDX0f); 33326 } 33327 } 33328 #endif 33329 return BCM_E_NONE; 33330 } 33331 33332 /* 33333 * Function: 33334 * _bcm_fb_lpm_get 33335 * Purpose: 33336 * Get an entry from DEFIP table. 33337 * Parameters: 33338 * unit - (IN)SOC unit number. 33339 * lpm_cfg - (IN)Buffer to fill defip information. 33340 * nh_ecmp_idx - (IN)Next hop or ecmp group index 33341 * Returns: 33342 * BCM_E_XXX 33343 */ 33344 int 33345 _bcm_fb_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 33346 { 33347 uint32 lpm_key[SOC_MAX_MEM_WORDS]; /* Route lookup key. */ 33348 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 33349 int clear_hit; /* Clear hit indicator. */ 33350 int rv; /* Operation return status. */ 33351 soc_mem_t mem = L3_DEFIPm; 33352 /* Input parameters check */ 33353 if (NULL == lpm_cfg) { 33354 return (BCM_E_PARAM); 33355 } 33356 33357 if (!SOC_MEM_IS_VALID(unit, mem)) { 33358 mem = L3_DEFIP_LEVEL1m; 33359 } 33360 33361 /* Zero buffers. */ 33362 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 33363 sal_memset(lpm_key, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 33364 33365 /* Check if clear hit bit required. */ 33366 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 33367 33368 /* Initialize lkup key. */ 33369 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, lpm_key)); 33370 33371 33372 /* Perform hw lookup. */ 33373 rv = soc_fb_lpm_match(unit, lpm_key, lpm_entry, &lpm_cfg->defip_index); 33374 BCM_IF_ERROR_RETURN(rv); 33375 33376 /* 33377 * If entry is ipv4 we always operate on entry in "zero" half of the, 33378 * buffer "zero" half of lpm_entry if the original entry 33379 * is in the "one" half. 33380 */ 33381 if ((!(lpm_cfg->defip_flags & BCM_L3_IP6)) && (lpm_cfg->defip_index & 0x1)) { 33382 soc_fb_lpm_ip4entry1_to_0(unit, &lpm_entry, &lpm_entry, TRUE); 33383 } 33384 33385 #ifdef BCM_TRIDENT_SUPPORT 33386 if ((SOC_IS_TD_TT(unit) || SOC_IS_TD2_TT2(unit)) && !(SOC_IS_TOMAHAWK3(unit))) { 33387 uint32 i, hit; 33388 defip_hit_only_entry_t hit_entry[2]; 33389 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym}; 33390 int hit_mem_cnt = 2; 33391 33392 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) { 33393 hit_mem[0] = L3_DEFIP_HIT_ONLYm; 33394 hit_mem_cnt = 1; 33395 } 33396 33397 if (lpm_cfg->defip_flags & BCM_L3_IP6) { 33398 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 33399 BCM_IF_ERROR_RETURN 33400 (BCM_XGS3_MEM_READ(unit, hit_mem[i], 33401 lpm_cfg->defip_index, &hit_entry[i])); 33402 hit |= soc_mem_field32_get(unit, hit_mem[i], 33403 &hit_entry[i], HIT0f); 33404 } 33405 soc_mem_field32_set(unit, mem, &lpm_entry, HIT0f, hit); 33406 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 33407 hit |= soc_mem_field32_get(unit, hit_mem[i], 33408 &hit_entry[i], HIT1f); 33409 } 33410 soc_mem_field32_set(unit, mem, &lpm_entry, HIT1f, hit); 33411 } else { 33412 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 33413 BCM_IF_ERROR_RETURN 33414 (BCM_XGS3_MEM_READ(unit, hit_mem[i], 33415 lpm_cfg->defip_index >> 1, &hit_entry[i])); 33416 hit |= soc_mem_field32_get(unit, hit_mem[i], &hit_entry[i], 33417 lpm_cfg->defip_index & 0x1 ? 33418 HIT1f : HIT0f); 33419 } 33420 soc_mem_field32_set(unit, mem, &lpm_entry, HIT0f, hit); 33421 } 33422 } 33423 #endif /* BCM_TRIDENT_SUPPORT */ 33424 33425 /* Parse hw buffer to defip entry. */ 33426 BCM_IF_ERROR_RETURN( 33427 _bcm_fb_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, (uint32 *)lpm_entry, NULL)); 33428 33429 /* Clear the HIT bit */ 33430 if (clear_hit) { 33431 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_clear_hit(unit, lpm_cfg, lpm_entry)); 33432 } 33433 return (BCM_E_NONE); 33434 } 33435 33436 33437 /* 33438 * Function: 33439 * _bcm_fb_lpm_add 33440 * Purpose: 33441 * Add an entry to DEFIP table. 33442 * Parameters: 33443 * unit - (IN)SOC unit number. 33444 * lpm_cfg - (IN)Buffer to fill defip information. 33445 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 33446 * Returns: 33447 * BCM_E_XXX 33448 */ 33449 int 33450 _bcm_fb_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 33451 { 33452 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 33453 int rv; /* Operation return status. */ 33454 33455 /* Input parameters check */ 33456 if (NULL == lpm_cfg) { 33457 return (BCM_E_PARAM); 33458 } 33459 33460 /* Zero buffers. */ 33461 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 33462 _bcm_fb_lpm_prepare_defip_entry(unit, lpm_cfg, nh_ecmp_idx, 33463 lpm_entry, NULL); 33464 /* Write buffer to hw. */ 33465 rv = soc_fb_lpm_insert_index(unit, lpm_entry, lpm_cfg->defip_index); 33466 33467 /* If new route added increment total number of routes. */ 33468 /* Lack of index indicates a new route. */ 33469 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index)) { 33470 BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 33471 } 33472 33473 return rv; 33474 } 33475 33476 /* 33477 * Function: 33478 * _bcm_fb_lpm_del 33479 * Purpose: 33480 * Delete an entry from DEFIP table. 33481 * Parameters: 33482 * unit - (IN)SOC unit number. 33483 * lpm_cfg - (IN)Buffer to fill defip information. 33484 * Returns: 33485 * BCM_E_XXX 33486 */ 33487 int 33488 _bcm_fb_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 33489 { 33490 int rv; /* Operation return status. */ 33491 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; /* Search result buffer. */ 33492 33493 /* Input parameters check */ 33494 if (NULL == lpm_cfg) { 33495 return (BCM_E_PARAM); 33496 } 33497 33498 /* Zero buffers. */ 33499 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 33500 33501 /* Initialize hw buffer deletion key. */ 33502 BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, (uint32 *)lpm_entry)); 33503 33504 /* Write buffer to hw. */ 33505 rv = soc_fb_lpm_delete_index(unit, (uint32 *)lpm_entry, lpm_cfg->defip_index); 33506 33507 /* If new route added increment total number of routes. */ 33508 if (rv >= 0) { 33509 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6); 33510 } 33511 return rv; 33512 } 33513 33514 /* 33515 * Function: 33516 * _bcm_fb_lpm_update_match 33517 * Purpose: 33518 * Update/Delete all entries in defip table matching a certain rule. 33519 * Parameters: 33520 * unit - (IN)SOC unit number. 33521 * trv_data - (IN)Delete pattern + compare,act,notify routines. 33522 * Returns: 33523 * BCM_E_XXX 33524 */ 33525 int 33526 _bcm_fb_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 33527 { 33528 uint32 ipv6; /* Iterate over ipv6 only flag. */ 33529 int idx; /* Iteration index. */ 33530 int tmp_idx; /* ipv4 entries iterator. */ 33531 char *lpm_tbl_ptr = NULL; /* Dma table pointer. */ 33532 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 33533 int cmp_result; /* Test routine result. */ 33534 uint32 *lpm_entry; /* Hw entry buffer. */ 33535 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 33536 int defip_table_size; /* Defip table size. */ 33537 int rv = BCM_E_NONE; /* Operation return status. */ 33538 int idx_start = 0; 33539 int idx_end = 0; 33540 #ifdef BCM_TRIDENT_SUPPORT 33541 char *lpm_hit_only_tbl_ptr[2] = { NULL }; /* Dma table pointer. */ 33542 int tbl_entry_sz; 33543 #endif /* BCM_TRIDENT_SUPPORT */ 33544 #ifdef BCM_KATANA_SUPPORT 33545 soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit); 33546 #endif 33547 int tcam_pair_count = 0; 33548 int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 33549 uint32 lpm_entry_tmp[SOC_MAX_MEM_WORDS]; 33550 #ifdef BCM_WARM_BOOT_SUPPORT 33551 int need_reinit = 0; 33552 #endif 33553 33554 ipv6 = (trv_data->flags & BCM_L3_IP6); 33555 33556 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 33557 /* Table DMA the LPM table to software copy */ 33558 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 33559 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 33560 &lpm_tbl_ptr, &defip_table_size); 33561 if (rv < 0) { 33562 goto free_table; 33563 } 33564 33565 /* Table DMA the HIT table to software copy */ 33566 #ifdef BCM_TRIDENT_SUPPORT 33567 if (SOC_IS_TD_TT(unit)) { 33568 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_HIT_ONLYm) && (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit))) { 33569 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit, 33570 L3_DEFIP_HIT_ONLYm)); 33571 rv = bcm_xgs3_l3_tbl_dma(unit, 33572 L3_DEFIP_HIT_ONLYm, 33573 tbl_entry_sz, 33574 "lpm_hit_only_tbl", 33575 &lpm_hit_only_tbl_ptr[0], 33576 NULL); 33577 if (rv < 0) { 33578 goto free_table; 33579 } 33580 } else if (SOC_MEM_IS_VALID(unit, L3_DEFIP_HIT_ONLY_Xm)){ 33581 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit, 33582 L3_DEFIP_HIT_ONLY_Xm)); 33583 rv = bcm_xgs3_l3_tbl_dma(unit, 33584 L3_DEFIP_HIT_ONLY_Xm, 33585 tbl_entry_sz, 33586 "lpm_hit_only_x_tbl", 33587 &lpm_hit_only_tbl_ptr[0], 33588 NULL); 33589 if (rv < 0) { 33590 goto free_table; 33591 } 33592 33593 rv = bcm_xgs3_l3_tbl_dma(unit, 33594 L3_DEFIP_HIT_ONLY_Ym, 33595 tbl_entry_sz, 33596 "lpm_hit_only_y_tbl", 33597 &lpm_hit_only_tbl_ptr[1], 33598 NULL); 33599 if (rv < 0) { 33600 goto free_table; 33601 } 33602 } 33603 } 33604 #endif /* BCM_TRIDENT_SUPPORT */ 33605 } else { 33606 defip_table_size = soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)); 33607 idx_end = soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)); 33608 rv = soc_fb_lpm_tcam_pair_count_get(unit, 33609 &tcam_pair_count); 33610 if (rv < 0) { 33611 goto free_table; 33612 } 33613 /* If soc_feature_l3_defip_advanced_lookup is TRUE then 33614 * both DIP and SIP lookup is done using only 1 L3_DEFIP entry. 33615 * L3_DEFIP table is not divided into 2 to support URPF (For ex: Katana2). 33616 */ 33617 if (SOC_URPF_STATUS_GET(unit) && 33618 !soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) { 33619 defip_table_size >>= 1; 33620 idx_end >>= 1; 33621 switch(tcam_pair_count) { 33622 case 1: 33623 case 2: 33624 idx_start = 2 * tcam_depth; 33625 break; 33626 case 3: 33627 case 4: 33628 idx_start = 4 * tcam_depth; 33629 break; 33630 case 5: 33631 case 6: 33632 idx_start = 6 * tcam_depth; 33633 break; 33634 case 7: 33635 case 8: 33636 idx_start = 8 * tcam_depth; 33637 break; 33638 default: 33639 idx_start = 0; 33640 break; 33641 } 33642 } else { 33643 idx_start = (tcam_pair_count * tcam_depth * 2); 33644 } 33645 defip_table_size = defip_table_size - idx_start; 33646 if (!defip_table_size) { 33647 rv = BCM_E_NONE; 33648 goto free_table; 33649 } 33650 33651 /* Table DMA the LPM table to software copy */ 33652 rv = bcm_xgs3_l3_tbl_range_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 33653 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 33654 idx_start, idx_end - 1, 33655 &lpm_tbl_ptr); 33656 if (rv < 0) { 33657 goto free_table; 33658 } 33659 33660 /* Table DMA the HIT table to software copy */ 33661 #ifdef BCM_TRIDENT_SUPPORT 33662 if (SOC_IS_TD_TT(unit) && !(SOC_IS_TOMAHAWK3(unit))) { 33663 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) { 33664 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit, 33665 L3_DEFIP_HIT_ONLYm)); 33666 rv = bcm_xgs3_l3_tbl_range_dma(unit, 33667 L3_DEFIP_HIT_ONLYm, 33668 tbl_entry_sz, 33669 "lpm_hit_only_x_tbl", 33670 idx_start, idx_end - 1, 33671 &lpm_hit_only_tbl_ptr[0]); 33672 if (rv < 0) { 33673 goto free_table; 33674 } 33675 } else { 33676 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit, 33677 L3_DEFIP_HIT_ONLY_Xm)); 33678 rv = bcm_xgs3_l3_tbl_range_dma(unit, 33679 L3_DEFIP_HIT_ONLY_Xm, 33680 tbl_entry_sz, 33681 "lpm_hit_only_x_tbl", 33682 idx_start, idx_end - 1, 33683 &lpm_hit_only_tbl_ptr[0]); 33684 if (rv < 0) { 33685 goto free_table; 33686 } 33687 33688 rv = bcm_xgs3_l3_tbl_range_dma(unit, 33689 L3_DEFIP_HIT_ONLY_Ym, 33690 tbl_entry_sz, 33691 "lpm_hit_only_y_tbl", 33692 idx_start, idx_end - 1, 33693 &lpm_hit_only_tbl_ptr[1]); 33694 if (rv < 0) { 33695 goto free_table; 33696 } 33697 } 33698 } 33699 #endif /* BCM_TRIDENT_SUPPORT */ 33700 } 33701 33702 /* If soc_feature_l3_defip_advanced_lookup is TRUE then 33703 * both DIP and SIP lookup is done using only 1 L3_DEFIP entry. 33704 * L3_DEFIP table is not divided into 2 to support URPF (For ex: Katana2). 33705 */ 33706 if (SOC_URPF_STATUS_GET(unit) && 33707 !soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) { 33708 if (soc_feature(unit, soc_feature_l3_defip_hole)) { 33709 defip_table_size = SOC_APOLLO_B0_L3_DEFIP_URPF_SIZE; 33710 } else if (SOC_IS_APOLLO(unit)) { 33711 defip_table_size = SOC_APOLLO_L3_DEFIP_URPF_SIZE; 33712 } else { 33713 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 33714 defip_table_size >>= 1; 33715 } 33716 } 33717 } 33718 33719 #if defined(BCM_KATANA_SUPPORT) 33720 if (SOC_IS_KATANA(unit)) { 33721 idx_start = lpm_ipv6_info->ipv6_64b.dip_start_offset; 33722 idx_end = idx_start + lpm_ipv6_info->ipv6_64b.depth; 33723 } else 33724 #endif 33725 { 33726 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 33727 idx_start = 0; 33728 idx_end = defip_table_size; 33729 } 33730 33731 } 33732 33733 for (idx = idx_start; idx < idx_end; idx++) { 33734 /* Calculate entry ofset. */ 33735 if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 33736 lpm_entry = 33737 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 33738 defip_entry_t *, lpm_tbl_ptr, idx - idx_start); 33739 } else { 33740 lpm_entry = 33741 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 33742 defip_level1_entry_t *, lpm_tbl_ptr, idx - idx_start); 33743 } 33744 33745 sal_memcpy(&lpm_entry_tmp, lpm_entry, BCM_XGS3_L3_ENT_SZ(unit, defip)); 33746 #ifdef BCM_WARM_BOOT_SUPPORT 33747 need_reinit = 0; 33748 #endif 33749 /* Each lpm entry contains 2 ipv4 entries -> Check both. */ 33750 for (tmp_idx = 0; tmp_idx < ((ipv6) ? 1 : 2); tmp_idx++) { 33751 33752 if (tmp_idx) { 33753 /* Check second part of the entry. */ 33754 soc_fb_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE); 33755 } 33756 33757 /* The ipv4 route can not be in the first half of L3_DEFIPm since the TH2 L3_DEFIP issue , 33758 so skip it*/ 33759 if (soc_feature(unit,soc_feature_half_of_l3_defip_ipv4_capacity) && 33760 !ipv6 && !tmp_idx) { 33761 continue; 33762 } 33763 33764 /* Make sure entry is valid. */ 33765 if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID0f)) { 33766 continue; 33767 } 33768 33769 #ifdef BCM_TRIDENT_SUPPORT 33770 if (SOC_IS_TD_TT(unit) && !SOC_IS_TOMAHAWK3(unit)) { 33771 uint32 i, hit; 33772 defip_hit_only_entry_t *hit_entry[2]; 33773 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym}; 33774 int hit_mem_cnt = 2; 33775 33776 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) { 33777 hit_mem[0] = L3_DEFIP_HIT_ONLYm; 33778 hit_mem_cnt = 1; 33779 } 33780 33781 if (ipv6) { 33782 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 33783 hit_entry[i] = soc_mem_table_idx_to_pointer(unit, 33784 hit_mem[i], 33785 defip_hit_only_entry_t *, 33786 lpm_hit_only_tbl_ptr[i], 33787 idx - idx_start); 33788 hit |= soc_mem_field32_get(unit, hit_mem[i], 33789 hit_entry[i], HIT0f); 33790 } 33791 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit); 33792 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 33793 hit |= soc_mem_field32_get(unit, hit_mem[i], 33794 hit_entry[i], HIT1f); 33795 } 33796 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT1f, hit); 33797 } else { 33798 for (i = 0, hit = 0; i < hit_mem_cnt; i++) { 33799 hit_entry[i] = soc_mem_table_idx_to_pointer(unit, 33800 hit_mem[i], 33801 defip_hit_only_entry_t *, 33802 lpm_hit_only_tbl_ptr[i], 33803 idx - idx_start); 33804 hit |= soc_mem_field32_get(unit, hit_mem[i], 33805 hit_entry[i], 33806 tmp_idx ? HIT1f : HIT0f); 33807 } 33808 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit); 33809 } 33810 } 33811 #endif /* BCM_TRIDENT_SUPPORT */ 33812 33813 /* Zero destination buffer first. */ 33814 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 33815 33816 /* Parse the entry. */ 33817 rv = _bcm_fb_lpm_ent_parse(unit, &lpm_cfg, &nh_ecmp_idx, (uint32 *)lpm_entry, NULL); 33818 if (BCM_FAILURE(rv)) { 33819 LOG_ERROR(BSL_LS_BCM_L3, 33820 (BSL_META_U(unit, 33821 "_bcm_fb_lpm_ent_parse failed\n"))); 33822 goto free_table; 33823 } 33824 lpm_cfg.defip_index = idx; 33825 33826 /* If protocol doesn't match skip the entry. */ 33827 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 33828 continue; 33829 } 33830 #ifdef BCM_TRIDENT3_SUPPORT 33831 if (tmp_idx) { 33832 /* Continue if V4 entry using double wide view */ 33833 if (soc_feature(unit, soc_feature_flex_flow) && 33834 lpm_cfg.defip_flow_handle != 0) { 33835 soc_mem_t view_id; 33836 BCM_IF_ERROR_RETURN( 33837 soc_flow_db_ffo_to_mem_view_id_get(unit, 33838 lpm_cfg.defip_flow_handle, 33839 lpm_cfg.defip_flow_option_handle, 33840 SOC_FLOW_DB_FUNC_L3_ROUTE_ID, 33841 (uint32 *)&view_id)); 33842 if (SOC_MEM_FIELD_VALID(unit, view_id, DWf)) { 33843 continue; 33844 } 33845 } 33846 } 33847 #endif 33848 /* Fill entry ip address & subnet mask. */ 33849 _bcm_fb_lpm_ent_get_key(unit, &lpm_cfg, lpm_entry); 33850 33851 /* Execute operation routine if any. */ 33852 if (trv_data->op_cb) { 33853 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 33854 (void *)&lpm_cfg, 33855 (void *)&nh_ecmp_idx, &cmp_result); 33856 if (rv < 0) { 33857 goto free_table; 33858 } 33859 } 33860 #ifdef BCM_WARM_BOOT_SUPPORT 33861 need_reinit = 1; 33862 #endif 33863 } 33864 #ifdef BCM_WARM_BOOT_SUPPORT 33865 if (SOC_WARM_BOOT(unit) && need_reinit) { 33866 rv = soc_fb_lpm_reinit(unit, idx, (uint32 *)&lpm_entry_tmp); 33867 if (rv < 0) { 33868 goto free_table; 33869 } 33870 } 33871 #endif /* BCM_WARM_BOOT_SUPPORT */ 33872 } 33873 33874 #ifdef BCM_WARM_BOOT_SUPPORT 33875 if (SOC_WARM_BOOT(unit)) { 33876 rv = soc_fb_lpm_reinit_done(unit, ipv6); 33877 if (rv < 0) { 33878 goto free_table; 33879 } 33880 } 33881 #endif /* BCM_WARM_BOOT_SUPPORT */ 33882 33883 free_table: 33884 if (lpm_tbl_ptr != NULL) { 33885 soc_cm_sfree(unit, lpm_tbl_ptr); 33886 } 33887 #ifdef BCM_TRIDENT_SUPPORT 33888 if (lpm_hit_only_tbl_ptr[0] != NULL) { 33889 soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[0]); 33890 } 33891 if (lpm_hit_only_tbl_ptr[1] != NULL) { 33892 soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[1]); 33893 } 33894 #endif 33895 33896 return (rv); 33897 } 33898 33899 /* 33900 * Function: 33901 * _bcm_fbx_lpm_get 33902 * Purpose: 33903 * Get an entry from DEFIP table. 33904 * Parameters: 33905 * unit - (IN)SOC unit number. 33906 * lpm_cfg - (IN)Buffer to fill defip information. 33907 * nh_ecmp_idx - (IN)Next hop or ecmp group index 33908 * Returns: 33909 * BCM_E_XXX 33910 */ 33911 STATIC int 33912 _bcm_fbx_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 33913 { 33914 soc_mem_t mem = L3_DEFIPm; 33915 #if defined(BCM_KATANA_SUPPORT) 33916 soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit); 33917 #endif 33918 33919 /* Input parameters check */ 33920 if (NULL == lpm_cfg) { 33921 return (BCM_E_PARAM); 33922 } 33923 33924 #if defined(BCM_TRX_SUPPORT) 33925 if (SOC_IS_TRX(unit)) { 33926 BCM_IF_ERROR_RETURN 33927 (_bcm_trx_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 33928 lpm_cfg->defip_sub_len, &mem)); 33929 } 33930 #endif /* BCM_TRX_SUPPORT */ 33931 33932 33933 switch (mem) { 33934 #if defined(BCM_TRIUMPH_SUPPORT) 33935 case EXT_IPV6_128_DEFIPm: 33936 case EXT_IPV6_64_DEFIPm: 33937 case EXT_IPV4_DEFIPm: 33938 return _bcm_tr_ext_lpm_match(unit, lpm_cfg, nh_ecmp_idx); 33939 #endif /* BCM_TRIUMPH_SUPPORT */ 33940 #if defined(BCM_TRX_SUPPORT) 33941 case L3_DEFIP_128m: 33942 #if defined(BCM_KATANA_SUPPORT) 33943 if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) { 33944 return _bcm_kt_defip_pair128_get(unit, lpm_cfg, nh_ecmp_idx); 33945 } else 33946 #endif 33947 { 33948 return _bcm_trx_defip_128_get(unit, lpm_cfg, nh_ecmp_idx); 33949 } 33950 #endif /* BCM_TRX_SUPPORT */ 33951 default: 33952 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 33953 if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) || 33954 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) { 33955 return _bcm_hu2_lpm_get(unit, lpm_cfg, nh_ecmp_idx); 33956 } else 33957 #endif /* BCM_HURRICANE2_SUPPORT||BCM_GREYHOUND_SUPPORT */ 33958 { 33959 return _bcm_fb_lpm_get(unit, lpm_cfg, nh_ecmp_idx); 33960 } 33961 } 33962 return (BCM_E_INTERNAL); /* Never reached. */ 33963 } 33964 33965 /* 33966 * Function: 33967 * _bcm_fbx_lpm_add 33968 * Purpose: 33969 * Add an entry to DEFIP table. 33970 * Parameters: 33971 * unit - (IN)SOC unit number. 33972 * lpm_cfg - (IN)Buffer to fill defip information. 33973 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 33974 * Returns: 33975 * BCM_E_XXX 33976 */ 33977 STATIC int 33978 _bcm_fbx_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 33979 { 33980 soc_mem_t mem = L3_DEFIPm; 33981 #if defined(BCM_KATANA_SUPPORT) 33982 soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit); 33983 #endif 33984 33985 /* Input parameters check */ 33986 if (NULL == lpm_cfg) { 33987 return (BCM_E_PARAM); 33988 } 33989 33990 #if defined(BCM_TRX_SUPPORT) 33991 if (SOC_IS_TRX(unit)) { 33992 BCM_IF_ERROR_RETURN 33993 (_bcm_trx_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 33994 lpm_cfg->defip_sub_len, &mem)); 33995 } 33996 #endif /* BCM_TRX_SUPPORT */ 33997 33998 switch (mem) { 33999 #if defined(BCM_TRIUMPH_SUPPORT) 34000 case EXT_IPV6_128_DEFIPm: 34001 case EXT_IPV6_64_DEFIPm: 34002 case EXT_IPV4_DEFIPm: 34003 return _bcm_tr_ext_lpm_add(unit, lpm_cfg, nh_ecmp_idx); 34004 #endif /* BCM_TRIUMPH_SUPPORT */ 34005 #if defined(BCM_TRX_SUPPORT) 34006 case L3_DEFIP_128m: 34007 #if defined(BCM_KATANA_SUPPORT) 34008 if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) { 34009 return _bcm_kt_defip_pair128_add(unit, lpm_cfg, nh_ecmp_idx); 34010 } else 34011 #endif 34012 { 34013 return _bcm_trx_defip_128_add(unit, lpm_cfg, nh_ecmp_idx); 34014 } 34015 #endif /* BCM_TRX_SUPPORT */ 34016 default: 34017 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 34018 if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) || 34019 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) { 34020 return _bcm_hu2_lpm_add(unit, lpm_cfg, nh_ecmp_idx); 34021 } else 34022 #endif /* BCM_HURRICANE2_SUPPORT */ 34023 { 34024 return _bcm_fb_lpm_add(unit, lpm_cfg, nh_ecmp_idx); 34025 } 34026 } 34027 return (BCM_E_INTERNAL); /* Never reached. */ 34028 } 34029 34030 /* 34031 * Function: 34032 * _bcm_fbx_lpm_del 34033 * Purpose: 34034 * Delete an entry from DEFIP table. 34035 * Parameters: 34036 * unit - (IN)SOC unit number. 34037 * lpm_cfg - (IN)Buffer to fill defip information. 34038 * Returns: 34039 * BCM_E_XXX 34040 */ 34041 STATIC int 34042 _bcm_fbx_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 34043 { 34044 soc_mem_t mem = L3_DEFIPm; 34045 #if defined(BCM_KATANA_SUPPORT) 34046 soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit); 34047 #endif 34048 34049 /* Input parameters check */ 34050 if (NULL == lpm_cfg) { 34051 return (BCM_E_PARAM); 34052 } 34053 34054 #if defined(BCM_TRX_SUPPORT) 34055 if (SOC_IS_TRX(unit)) { 34056 BCM_IF_ERROR_RETURN 34057 (_bcm_trx_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 34058 lpm_cfg->defip_sub_len, &mem)); 34059 } 34060 #endif /* BCM_TRX_SUPPORT */ 34061 34062 switch (mem) { 34063 #if defined(BCM_TRIUMPH_SUPPORT) 34064 case EXT_IPV6_128_DEFIPm: 34065 case EXT_IPV6_64_DEFIPm: 34066 case EXT_IPV4_DEFIPm: 34067 return _bcm_tr_ext_lpm_delete(unit, lpm_cfg); 34068 #endif /* BCM_TRIUMPH_SUPPORT */ 34069 #if defined(BCM_TRX_SUPPORT) 34070 case L3_DEFIP_128m: 34071 #if defined(BCM_KATANA_SUPPORT) 34072 if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) { 34073 return _bcm_kt_defip_pair128_delete(unit, lpm_cfg); 34074 } else 34075 #endif 34076 { 34077 return _bcm_trx_defip_128_delete(unit, lpm_cfg); 34078 } 34079 #endif /* BCM_TRX_SUPPORT */ 34080 default: 34081 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 34082 if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) || 34083 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) { 34084 return _bcm_hu2_lpm_del(unit, lpm_cfg); 34085 } else 34086 #endif /* BCM_HURRICANE2_SUPPORT */ 34087 { 34088 return _bcm_fb_lpm_del(unit, lpm_cfg); 34089 } 34090 } 34091 return (BCM_E_INTERNAL); /* Never reached. */ 34092 } 34093 34094 /* 34095 * Function: 34096 * _bcm_fbx_lpm_update_match 34097 * Purpose: 34098 * Update/Delete all entries in defip table matching a certain rule. 34099 * Parameters: 34100 * unit - (IN)SOC unit number. 34101 * trv_data - (IN)Delete pattern + compare,act,notify routines. 34102 * Returns: 34103 * BCM_E_XXX 34104 */ 34105 STATIC int 34106 _bcm_fbx_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 34107 { 34108 soc_mem_t mem = L3_DEFIPm; /* Route table memory. */ 34109 int rv = BCM_E_NONE; /* Operation return status. */ 34110 #ifdef BCM_KATANA_SUPPORT 34111 soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit); 34112 #endif 34113 #if defined(BCM_TRIUMPH_SUPPORT) 34114 if (SOC_IS_TR_VL(unit)) { 34115 BCM_IF_ERROR_RETURN 34116 (_bcm_tr_l3_defip_mem_get(unit, trv_data->flags, 0, &mem)); 34117 } 34118 #endif /* BCM_TRIUMPH_SUPPORT */ 34119 34120 switch (mem) { 34121 #if defined(BCM_TRIUMPH_SUPPORT) 34122 case EXT_IPV6_128_DEFIPm: 34123 case EXT_IPV6_64_DEFIPm: 34124 case EXT_IPV4_DEFIPm: 34125 return _bcm_tr_defip_traverse(unit, trv_data); 34126 #endif /* BCM_TRIUMPH_SUPPORT */ 34127 default: 34128 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT) 34129 if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) || 34130 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) { 34131 return _bcm_hu2_lpm_update_match(unit, trv_data); 34132 } else 34133 #endif /* BCM_HURRICANE2_SUPPORT */ 34134 { 34135 rv = _bcm_fb_lpm_update_match(unit, trv_data); 34136 } 34137 } 34138 if (BCM_FAILURE(rv)) { 34139 return (rv); 34140 } 34141 34142 #if defined(BCM_KATANA_SUPPORT) 34143 if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) { 34144 if ((trv_data->flags & BCM_L3_IP6)) { 34145 rv = _bcm_trx_defip_128_update_match(unit, trv_data); 34146 rv = _bcm_kt_defip_pair128_update_match(unit, trv_data); 34147 } 34148 } else 34149 #endif /* BCM_KATANA_SUPPORT */ 34150 { 34151 #if defined(BCM_TRX_SUPPORT) 34152 if ((trv_data->flags & BCM_L3_IP6) && 34153 SOC_MEM_IS_VALID(unit, L3_DEFIP_128m)) { 34154 rv = _bcm_trx_defip_128_update_match(unit, trv_data); 34155 } 34156 #endif /* BCM_TRX_SUPPORT */ 34157 } 34158 return (rv); 34159 } 34160 34161 34162 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 34163 defined(BCM_HAWKEYE_SUPPORT) 34164 34165 /* 34166 * Function: 34167 * _bcm_rp_grp_priority_cmp 34168 * Purpose: 34169 * Compare two FP groups priorities. 34170 * Parameters: 34171 * b - (IN)first compared group. 34172 * a - (IN)second compared group. 34173 * Returns: 34174 * a<=>b 34175 */ 34176 static INLINE int 34177 _bcm_rp_grp_priority_cmp(void *a, void *b) 34178 { 34179 _bcm_rp_l3_fp_group_t first; /* First compared group. */ 34180 _bcm_rp_l3_fp_group_t second; /* Second compared group. */ 34181 34182 /* Cast group info pointers. */ 34183 first = *(_bcm_rp_l3_fp_group_t *)a; 34184 second = *(_bcm_rp_l3_fp_group_t *)b; 34185 34186 /* Compare groups priorities. */ 34187 return _bcm_xgs3_cmp_int(&first.grp_hdlr, &second.grp_hdlr); 34188 } 34189 34190 /* 34191 * Function: 34192 * _bcm_rp_l3_rule_create 34193 * Purpose: 34194 * Create L3 field processor rule & meter. 34195 * Parameters: 34196 * unit - (IN)SOC unit number. 34197 * rule_idx - (IN)Rule index. 34198 * Returns: 34199 * BCM_E_XXX 34200 */ 34201 STATIC int 34202 _bcm_rp_l3_rule_create(int unit, int rule_idx) 34203 { 34204 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34205 bcm_field_entry_t rule_hdlr; /* FP l3 rule handler. */ 34206 bcm_field_group_t grp_hdlr; /* FP l3 group handler. */ 34207 int grp_idx; /* FP l3 group index. */ 34208 bcm_field_stat_t stat_type; /* FP entry Stat type. */ 34209 int stat_id; /* FP entry Stat ID. */ 34210 34211 34212 /* Get l3 prefixes table. */ 34213 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34214 34215 grp_idx = rule_idx/(tbl_ptr->rules_per_group); 34216 grp_hdlr = (tbl_ptr->l3_grp[grp_idx]).grp_hdlr; 34217 34218 /* Create FP rule. */ 34219 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_create(unit, grp_hdlr, &rule_hdlr)); 34220 34221 /* Create packet type stat and attach to the rule */ 34222 stat_type = bcmFieldStatPackets; 34223 BCM_IF_ERROR_RETURN(bcm_esw_field_stat_create(unit, grp_hdlr, 1, 34224 &stat_type, &stat_id)); 34225 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_stat_attach(unit, rule_hdlr, 34226 stat_id)); 34227 /* Preserve rule handler. */ 34228 (tbl_ptr->l3_arr[rule_idx]).rule_hdlr = rule_hdlr; 34229 34230 return (BCM_E_NONE); 34231 } 34232 34233 /* 34234 * Function: 34235 * _bcm_rp_l3_rule_destroy 34236 * Purpose: 34237 * Destroy L3 field processor rule. 34238 * Parameters: 34239 * unit - (IN)SOC unit number. 34240 * rule_idx - (IN)Rule index. 34241 * Returns: 34242 * BCM_E_XXX 34243 */ 34244 STATIC int 34245 _bcm_rp_l3_rule_destroy(int unit, int rule_idx) 34246 { 34247 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34248 bcm_field_entry_t rule_hdlr; /* FP l3 rule handler. */ 34249 int stat_id; /* FP entry Stat ID. */ 34250 34251 /* Get l3 prefixes table. */ 34252 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34253 34254 /* Get Rule Handler. */ 34255 rule_hdlr = (tbl_ptr->l3_arr[rule_idx]).rule_hdlr; 34256 34257 /* If entry is valid -> remove it from HW. */ 34258 if (tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID) { 34259 /* Uinstall fp entry from hw. */ 34260 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_remove(unit, rule_hdlr)); 34261 } 34262 34263 /* Delete match Stat ID. */ 34264 BCM_IF_ERROR_RETURN 34265 (bcm_esw_field_entry_stat_get(unit, rule_hdlr, &stat_id)); 34266 34267 BCM_IF_ERROR_RETURN 34268 (bcm_esw_field_entry_stat_detach(unit, rule_hdlr, stat_id)); 34269 34270 /* Uinstall fp entry from sw. */ 34271 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_destroy(unit, rule_hdlr)); 34272 34273 return (BCM_E_NONE); 34274 } 34275 /* 34276 * Function: 34277 * _bcm_rp_l3_usage_cntr_set 34278 * Purpose: 34279 * Copy usage counter from one l3 entry rule to another. 34280 * or reset usage counter if second entry is invalid. 34281 * Parameters: 34282 * unit - (IN)SOC unit number. 34283 * dst_idx - (IN)Destination counter entry index. 34284 * src_idx - (IN)Counter entry index. 34285 * flags - (IN)BCM_L3_HIT. 34286 * Returns: 34287 * BCM_E_XXX 34288 */ 34289 STATIC int 34290 _bcm_rp_l3_usage_cntr_set(int unit, int dst_idx, int src_idx, uint32 flags) 34291 { 34292 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34293 uint64 usage_cntr; /* Entry usage counter. */ 34294 bcm_field_stat_t stat_type; /* FP entry Stat type. */ 34295 int stat_id; /* FP entry Stat ID. */ 34296 34297 /* Get l3 prefixes table. */ 34298 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34299 34300 if(BCM_XGS3_L3_INVALID_INDEX != src_idx) 34301 { 34302 /* Get the Stat ID. */ 34303 BCM_IF_ERROR_RETURN 34304 (bcm_esw_field_entry_stat_get(unit, 34305 tbl_ptr->l3_arr[src_idx].rule_hdlr, 34306 &stat_id)); 34307 34308 /* Read Stat value. */ 34309 stat_type = bcmFieldStatPackets; 34310 BCM_IF_ERROR_RETURN 34311 (bcm_esw_field_stat_get(unit, stat_id, stat_type, &usage_cntr)); 34312 } else { 34313 sal_memset(&usage_cntr, 0, sizeof usage_cntr); 34314 if (flags & BCM_L3_HIT) { 34315 COMPILER_64_ADD_32(usage_cntr, 1); 34316 } 34317 } 34318 34319 /* Get the Stat ID. */ 34320 BCM_IF_ERROR_RETURN 34321 (bcm_esw_field_entry_stat_get(unit, tbl_ptr->l3_arr[dst_idx].rule_hdlr, 34322 &stat_id)); 34323 34324 /* Set Stat value. */ 34325 stat_type = bcmFieldStatPackets; 34326 return bcm_esw_field_stat_set(unit, stat_id, stat_type, 34327 usage_cntr); 34328 } 34329 34330 /* 34331 * Function: 34332 * _bcm_rp_l3_entry_add 34333 * Purpose: 34334 * Add L3 rule to field processor. 34335 * Parameters: 34336 * unit - (IN)SOC unit number. 34337 * rule_idx - (IN)FP entry rule index. 34338 * l3_entry - (IN)Added L3 entry information. 34339 * Returns: 34340 * BCM_E_XXX 34341 */ 34342 STATIC int 34343 _bcm_rp_l3_entry_add(int unit, int rule_idx, _bcm_rp_l3_entry_t *l3_entry) 34344 { 34345 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34346 bcm_ip6_t ip6_mask; /* IPv6 destination mask. */ 34347 bcm_ip_t ip4_mask; /* IPv4 destination mask. */ 34348 bcm_field_entry_t rule_hdlr; /* L3 rule handler. */ 34349 bcm_ip6_t ip6; /* IPv6 address. */ 34350 int ip_type; /* QualifyIpType value. */ 34351 int rule_priority; /* Rule prioiry. */ 34352 int nh_idx; /* Next hop index. */ 34353 34354 34355 /* Get l3 prefixes table. */ 34356 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34357 34358 /* Preserve rule handler. */ 34359 rule_hdlr = tbl_ptr->l3_arr[rule_idx].rule_hdlr; 34360 34361 /* Copy FP rule info. */ 34362 tbl_ptr->l3_arr[rule_idx] = *l3_entry; 34363 34364 /* Restore rule handler. */ 34365 tbl_ptr->l3_arr[rule_idx].rule_hdlr = rule_hdlr; 34366 34367 /* Get next hop index for the rule. */ 34368 nh_idx = l3_entry->nh_idx; 34369 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 34370 if (l3_entry->flags & BCM_L3_MULTIPATH) { 34371 nh_idx += BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 34372 } else { 34373 nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit); 34374 } 34375 } 34376 34377 /* Set rule qualification criterias. */ 34378 #if defined(BCM_MIRAGE_SUPPORT) 34379 if (soc_feature(unit, soc_feature_fp_routing_mirage)) { 34380 BCM_IF_ERROR_RETURN(bcm_esw_field_qualify_DstPort(unit, rule_hdlr, 34381 0, 0, BCM_MIRAGE_L3_PORT, BCM_MIRAGE_L3_PORT)); 34382 } else 34383 #endif /* BCM_MIRAGE_SUPPORT */ 34384 { 34385 /* Add unknown unicast. */ 34386 BCM_IF_ERROR_RETURN 34387 (bcm_esw_field_qualify_L3Routable(unit, rule_hdlr, 34388 0x1, 0x1)); 34389 34390 } 34391 if (l3_entry->flags & BCM_L3_IP6) { 34392 /* Set to protocol ipv6. */ 34393 BCM_IF_ERROR_RETURN 34394 (bcm_esw_field_qualify_IpType(unit, rule_hdlr, 34395 bcmFieldIpTypeIpv6)); 34396 34397 /* Calculate subnet mask. */ 34398 bcm_ip6_mask_create(ip6_mask, l3_entry->prefixlen); 34399 34400 /* Rule priority. */ 34401 rule_priority = l3_entry->prefixlen; 34402 34403 /* Copy address. */ 34404 sal_memcpy(ip6, l3_entry->addr.ip6, sizeof(bcm_ip6_t)); 34405 } else { 34406 34407 #if defined(BCM_XGS3_L3_FORWARD_IPV4_WITH_OPTIONS) 34408 ip_type = bcmFieldIpTypeIpv4Any; 34409 #else /* BCM_XGS3_L3_FORWARD_IPV4_WITH_OPTIONS */ 34410 ip_type = bcmFieldIpTypeIpv4NoOpts; 34411 #endif /* BCM_XGS3_L3_FORWARD_IPV4_WITH_OPTIONS */ 34412 #if defined(BCM_MIRAGE_SUPPORT) 34413 if (soc_feature(unit, soc_feature_fp_routing_mirage)) { 34414 ip_type = bcmFieldIpTypeIpv4Any; 34415 } 34416 #endif /* BCM_MIRAGE_SUPPORT */ 34417 34418 /* Set to protocol ipv4. */ 34419 BCM_IF_ERROR_RETURN 34420 (bcm_esw_field_qualify_IpType(unit, rule_hdlr, ip_type)); 34421 34422 /* Calculate subnet mask. */ 34423 ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(l3_entry->prefixlen); 34424 BCM_XGS3_L3_CP_V4_ADDR_TO_V6(ip6_mask, ip4_mask); 34425 34426 /* Rule priority. */ 34427 if(l3_entry->prefixlen) { 34428 /* This code comes to avoid extra shifts for host v4 entries. */ 34429 rule_priority = l3_entry->prefixlen + 34430 (BCM_XGS3_L3_IPV6_PREFIX_LEN - BCM_XGS3_L3_IPV4_PREFIX_LEN); 34431 } else { 34432 rule_priority = l3_entry->prefixlen; 34433 } 34434 34435 /* Set address. */ 34436 BCM_XGS3_L3_CP_V4_ADDR_TO_V6(ip6, l3_entry->addr.ip4); 34437 } 34438 34439 /* Add destination ip. */ 34440 BCM_IF_ERROR_RETURN 34441 (bcm_esw_field_qualify_DstIp6(unit, rule_hdlr, ip6, ip6_mask)); 34442 34443 /* Set entry priority. */ 34444 BCM_IF_ERROR_RETURN 34445 (bcm_esw_field_entry_prio_set(unit, rule_hdlr, rule_priority)); 34446 34447 34448 /* Add route action */ 34449 BCM_IF_ERROR_RETURN(bcm_esw_field_action_add(unit, rule_hdlr, 34450 bcmFieldActionL3Switch, 34451 nh_idx, 0)); 34452 34453 /* Install entry to hw. */ 34454 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_install(unit, rule_hdlr)); 34455 34456 /* Mark entry as valid. */ 34457 tbl_ptr->l3_arr[rule_idx].flags |= BCM_XGS3_L3_ENT_VALID; 34458 34459 /* Reset entry counter. */ 34460 BCM_IF_ERROR_RETURN 34461 (_bcm_rp_l3_usage_cntr_set(unit, rule_idx, 34462 BCM_XGS3_L3_INVALID_INDEX, l3_entry->flags)); 34463 34464 return (BCM_E_NONE); 34465 } 34466 34467 34468 /* 34469 * Function: 34470 * _bcm_rp_l3_entry_delete 34471 * Purpose: 34472 * Remove L3 rule from field processor. 34473 * Parameters: 34474 * unit - (IN)SOC unit number. 34475 * rule_idx - (IN)FP entry rule index. 34476 * Returns: 34477 * BCM_E_XXX 34478 */ 34479 STATIC int 34480 _bcm_rp_l3_entry_delete(int unit, int rule_idx) 34481 { 34482 _bcm_rp_l3_entry_t *l3_entry; /* L3 entry to be removed. */ 34483 34484 /* Get l3 entry. */ 34485 l3_entry = &(BCM_XGS3_L3_TBL(unit, rp_prefix)).l3_arr[rule_idx]; 34486 34487 /* Uinstall entry from hw. */ 34488 BCM_IF_ERROR_RETURN(bcm_esw_field_entry_remove(unit, l3_entry->rule_hdlr)); 34489 34490 /* Remove all actions from the entry */ 34491 BCM_IF_ERROR_RETURN 34492 (bcm_esw_field_action_remove_all(unit, l3_entry->rule_hdlr)); 34493 34494 /* Mark entry as invalid. */ 34495 l3_entry->flags &= ~BCM_XGS3_L3_ENT_VALID; 34496 34497 return (BCM_E_NONE); 34498 } 34499 34500 /* 34501 * Function: 34502 * _bcm_rp_l3_sw_entry_swap 34503 * Purpose: 34504 * Swap to entries in host/route sw image. 34505 * Parameters: 34506 * unit - (IN)SOC unit number. 34507 * dst_idx - (IN)Destination entry rule index. 34508 * src_idx - (IN)Original entry rule index. 34509 * Returns: 34510 * void 34511 */ 34512 STATIC INLINE void 34513 _bcm_rp_l3_entry_swap(int unit, int dst_idx, int src_idx) 34514 { 34515 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34516 _bcm_rp_l3_entry_t l3_temp; /* Entry swap buffer. */ 34517 34518 /* Get l3 prefixes table. */ 34519 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34520 34521 /* Preserve source entry. */ 34522 l3_temp = tbl_ptr->l3_arr[src_idx]; 34523 34524 /* Write destination to the source. */ 34525 tbl_ptr->l3_arr[src_idx] = tbl_ptr->l3_arr[dst_idx]; 34526 34527 /* Write souce to the destination. */ 34528 tbl_ptr->l3_arr[dst_idx] = l3_temp; 34529 return; 34530 } 34531 34532 /* 34533 * Function: 34534 * _bcm_rp_l3_entry_shift 34535 * Purpose: 34536 * Copy l3 entry rule from one index to another. 34537 * NOTE: Should be called with protection mutex locked. 34538 * Parameters: 34539 * unit - (IN)SOC unit number. 34540 * dst_idx - (IN)Destination entry rule index. 34541 * src_idx - (IN)Original entry rule index. 34542 * Returns: 34543 * BCM_E_XXX 34544 */ 34545 STATIC int 34546 _bcm_rp_l3_entry_shift(int unit, int dst_idx, int src_idx) 34547 { 34548 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34549 34550 /* Get l3 prefixes table. */ 34551 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34552 34553 /* 34554 * If destination & source sitting in the same FP group just swap 34555 * software images. (This saves extra hw updates). 34556 */ 34557 if ((dst_idx/tbl_ptr->rules_per_group) == 34558 (src_idx/tbl_ptr->rules_per_group)) { 34559 _bcm_rp_l3_entry_swap(unit, dst_idx, src_idx); 34560 return (BCM_E_NONE); 34561 } 34562 34563 /* 34564 * Rules are in the different groups we have to move/pack them. 34565 * Add shifted rule new group and remove it from original one. 34566 */ 34567 BCM_IF_ERROR_RETURN 34568 (_bcm_rp_l3_entry_add(unit, dst_idx, &tbl_ptr->l3_arr[src_idx])); 34569 34570 /* Copy rule usage counter. */ 34571 BCM_IF_ERROR_RETURN(_bcm_rp_l3_usage_cntr_set(unit, dst_idx, src_idx, 0)); 34572 34573 /* Uinstall original entry from hw. */ 34574 if (BCM_XGS3_L3_RP_HOST_ENTRY((&tbl_ptr->l3_arr[src_idx]))) { 34575 /* Remove host entry. */ 34576 return _bcm_rp_l3_entry_delete(unit, src_idx); 34577 } 34578 34579 /* Remove route entry. */ 34580 return _bcm_rp_lpm_entry_remove(unit, src_idx); 34581 } 34582 34583 /* 34584 * Function: 34585 * _bcm_rp_grp_rules_num_get 34586 * Purpose: 34587 * Get number rules in group. 34588 * Parameters: 34589 * unit - (IN)SOC unit number. 34590 * rules - (OUT)Interface table size. 34591 * Returns: 34592 * BCM_E_XXX 34593 */ 34594 STATIC int 34595 _bcm_rp_grp_rules_num_get(int unit, int *rules) 34596 { 34597 int tcam_sz; /* FP tcam size. */ 34598 int tcam_slices; /* Number of FP slices. */ 34599 34600 /* Get tcam size. */ 34601 tcam_sz = soc_mem_index_count(unit, FP_TCAMm); 34602 34603 /* Note tcam_slices only counts internal slices. */ 34604 if (soc_feature(unit, soc_feature_field_slices2)) { 34605 tcam_slices = 2; 34606 } else if (soc_feature(unit, soc_feature_field_slices4)) { 34607 tcam_slices = 4; 34608 } else { 34609 tcam_slices = soc_feature(unit, soc_feature_field_slices8) ? 8 : 16; 34610 } 34611 34612 /* Get number of rules */ 34613 *rules = (tcam_sz / tcam_slices) - 1; 34614 34615 return (BCM_E_NONE); 34616 } 34617 34618 /* 34619 * Function: 34620 * _bcm_rp_lpm_group_update 34621 * Purpose: 34622 * Update FP group properties (min/max) prefix length location. 34623 * Parameters: 34624 * unit - (IN)SOC unit number. 34625 * grp_id - (IN)FP group id. 34626 * Returns: 34627 * void 34628 */ 34629 STATIC void 34630 _bcm_rp_lpm_group_update(int unit, int grp_id) 34631 { 34632 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34633 int max_pfx_len_idx; /* Max prefix length rule idx in group */ 34634 int min_pfx_len_idx; /* Max prefix length rule idx in group */ 34635 int idx; /* Iteration index. */ 34636 34637 /* Initialization. */ 34638 max_pfx_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34639 min_pfx_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34640 34641 /* Get l3 prefixes table. */ 34642 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34643 34644 /* Get l3 prefixes table. */ 34645 /* Set min & max to first entry. */ 34646 for (idx = grp_id * tbl_ptr->rules_per_group; 34647 ((idx < ((grp_id + 1) * tbl_ptr->rules_per_group)) && 34648 (idx <= tbl_ptr->route_maxused_rule_id)); idx ++) { 34649 34650 /* Check only valid entries. */ 34651 if (!(tbl_ptr->l3_arr[idx].flags & BCM_XGS3_L3_ENT_VALID)) { 34652 continue; 34653 } 34654 34655 /* Set minimum & maximum to the first valid entry. */ 34656 if(max_pfx_len_idx == BCM_XGS3_L3_INVALID_INDEX) { 34657 max_pfx_len_idx = min_pfx_len_idx = idx; 34658 continue; 34659 } 34660 34661 /* Check if entry prefix length is less than minimum. */ 34662 if (tbl_ptr->l3_arr[idx].prefixlen < 34663 tbl_ptr->l3_arr[min_pfx_len_idx].prefixlen){ 34664 min_pfx_len_idx = idx; 34665 } 34666 34667 /* Check if entry prefix length is greater than maximum. */ 34668 if (tbl_ptr->l3_arr[idx].prefixlen > 34669 tbl_ptr->l3_arr[max_pfx_len_idx].prefixlen){ 34670 max_pfx_len_idx = idx; 34671 } 34672 } 34673 /* Preserve group max/min prefix length indexes. */ 34674 tbl_ptr->l3_grp[grp_id].max_prefix_len_idx = max_pfx_len_idx; 34675 tbl_ptr->l3_grp[grp_id].min_prefix_len_idx = min_pfx_len_idx; 34676 return; 34677 } 34678 34679 /* 34680 * Function: 34681 * _bcm_rp_lpm_group_add_del 34682 * Purpose: 34683 * Insert prefixlen to the group and 34684 * update (min/max) prefix length location. 34685 * Parameters: 34686 * unit - (IN)SOC unit number. 34687 * rule_idx - (IN)FP prefix rule idx. 34688 * prefixlen - (IN)Prefix length. 34689 * Returns: 34690 * void 34691 */ 34692 STATIC void 34693 _bcm_rp_lpm_group_add_del(int unit, int rule_idx, int prefixlen) 34694 { 34695 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34696 int *max_pfx_len_idx; /* Max prefix length rule idx in group */ 34697 int *min_pfx_len_idx; /* Min prefix length rule idx in group */ 34698 int grp_id; /* FP l3 group index. */ 34699 34700 /* Get l3 prefixes table. */ 34701 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34702 34703 /* Get group id. */ 34704 grp_id = rule_idx/(tbl_ptr->rules_per_group); 34705 34706 /* Get group min & max prefix length indexes. */ 34707 max_pfx_len_idx = &tbl_ptr->l3_grp[grp_id].max_prefix_len_idx; 34708 min_pfx_len_idx = &tbl_ptr->l3_grp[grp_id].min_prefix_len_idx; 34709 34710 /* If first group entry added set min & max idx to it. */ 34711 if (BCM_XGS3_L3_INVALID_INDEX != prefixlen) { 34712 if(0 == tbl_ptr->l3_grp[grp_id].rule_count) { 34713 *max_pfx_len_idx = *min_pfx_len_idx = rule_idx; 34714 } else { 34715 /* Update group max & min indexes if necessary. */ 34716 if (prefixlen < tbl_ptr->l3_arr[*min_pfx_len_idx].prefixlen) { 34717 *min_pfx_len_idx = rule_idx; 34718 } 34719 if (prefixlen > tbl_ptr->l3_arr[*max_pfx_len_idx].prefixlen) { 34720 *max_pfx_len_idx = rule_idx; 34721 } 34722 } 34723 /* Increment number of valid rules. */ 34724 tbl_ptr->l3_grp[grp_id].rule_count++; 34725 } else { 34726 /* Prefix deleted from the group. */ 34727 /* If first group entry added set min & max idx to it. */ 34728 if(1 == tbl_ptr->l3_grp[grp_id].rule_count) { 34729 *max_pfx_len_idx = *min_pfx_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34730 } else { 34731 if ((rule_idx == *max_pfx_len_idx) || 34732 (rule_idx == *min_pfx_len_idx)) { 34733 /* Update group max & min indexes. */ 34734 _bcm_rp_lpm_group_update(unit, grp_id); 34735 } 34736 } 34737 /* Decrement number of valid rules. */ 34738 tbl_ptr->l3_grp[grp_id].rule_count--; 34739 } 34740 } 34741 34742 /* 34743 * Function: 34744 * _bcm_rp_l3_deinit 34745 * Purpose: 34746 * Deinitialize L3 functionality on Raptor 6530x devices. 34747 * Parameters: 34748 * unit - (IN)SOC unit number. 34749 * Returns: 34750 * BCM_E_XXX 34751 */ 34752 STATIC int 34753 _bcm_rp_l3_deinit(int unit) 34754 { 34755 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34756 int idx; /* Iteration index. */ 34757 int rv = BCM_E_NONE; /* Operation return status. */ 34758 int first_error = BCM_E_NONE; /* First error occured. */ 34759 34760 /* Get l3 prefixes table. */ 34761 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34762 34763 /* If table was not initialized just return. */ 34764 if ((NULL == tbl_ptr->l3_arr) || (NULL == tbl_ptr->l3_grp)) { 34765 return (BCM_E_NONE); 34766 } 34767 34768 /* Iterate over all rules & delete them. */ 34769 if (0 == SOC_HW_ACCESS_DISABLE(unit)) { 34770 for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) { 34771 if (!tbl_ptr->l3_arr[idx].rule_hdlr) { 34772 continue; 34773 } 34774 rv = _bcm_rp_l3_rule_destroy(unit, idx); 34775 if ((rv < 0) && (first_error == BCM_E_NONE)) { 34776 first_error = rv; 34777 } 34778 } 34779 34780 /* Delete allocated FP groups. */ 34781 for (idx = 0; idx < tbl_ptr->l3_group_num; idx ++) { 34782 if (!tbl_ptr->l3_grp[idx].grp_hdlr) { 34783 continue; 34784 } 34785 rv = bcm_esw_field_group_destroy(unit, 34786 (tbl_ptr->l3_grp[idx]).grp_hdlr); 34787 if ((rv < 0) && (first_error == BCM_E_NONE)) { 34788 first_error = rv; 34789 } 34790 } 34791 } 34792 34793 /* Free allocated memory. */ 34794 if (tbl_ptr->l3_grp) { 34795 sal_free(tbl_ptr->l3_grp); 34796 } 34797 if (tbl_ptr->l3_arr) { 34798 sal_free(tbl_ptr->l3_arr); 34799 } 34800 34801 /* Reset l3 control structure. */ 34802 sal_memset(tbl_ptr, 0, sizeof(_bcm_rp_l3_data_t)); 34803 return (rv); 34804 } 34805 34806 #ifdef BCM_WARM_BOOT_SUPPORT 34807 /* 34808 * Function: 34809 * _bcm_hk_l3_field_init 34810 * Purpose: 34811 * Allocate FP group and entries on Hakweye device. 34812 * Parameters: 34813 * unit - (IN)SOC unit number. 34814 * Returns: 34815 * BCM_E_XXX 34816 */ 34817 STATIC int 34818 _bcm_hk_l3_field_init(int unit) 34819 { 34820 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34821 bcm_field_qset_t qset; /* FP qualifiers set. */ 34822 int idx; /* Iteration index. */ 34823 int rv = BCM_E_NONE; /* Operation return status. */ 34824 34825 /* Get l3 prefixes table. */ 34826 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34827 34828 /* Create qualifiers set. */ 34829 BCM_FIELD_QSET_INIT(qset); 34830 34831 /* Add qualifier fields. */ 34832 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyIpType); 34833 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL2Format); 34834 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyVlanFormat); 34835 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstIp6); 34836 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL3Routable); 34837 34838 /* Add FP groups. */ 34839 for (idx = 0; idx < tbl_ptr->l3_group_num; idx++) { 34840 /* Create FP group. */ 34841 if (tbl_ptr->l3_grp[idx].grp_hdlr) { 34842 /* This group has been created. */ 34843 continue; 34844 } 34845 34846 rv = bcm_esw_field_group_create(unit, qset, BCM_FIELD_GROUP_PRIO_ANY, 34847 &tbl_ptr->l3_grp[idx].grp_hdlr); 34848 if (rv < 0) { 34849 return rv; 34850 } 34851 /* Set max & min prefix length indexes. */ 34852 tbl_ptr->l3_grp[idx].max_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34853 tbl_ptr->l3_grp[idx].min_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34854 } 34855 34856 /* Sort groups by priority. */ 34857 _shr_sort(tbl_ptr->l3_grp, tbl_ptr->l3_group_num, 34858 sizeof(_bcm_rp_l3_fp_group_t), _bcm_rp_grp_priority_cmp); 34859 34860 /* Allocate rule handlers. */ 34861 for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) { 34862 if (tbl_ptr->l3_arr[idx].rule_hdlr) { 34863 /* This entry has been created. */ 34864 continue; 34865 } 34866 rv = _bcm_rp_l3_rule_create(unit, idx); 34867 if (rv < 0) { 34868 return rv; 34869 } 34870 } 34871 return (BCM_E_NONE); 34872 } 34873 #endif /* BCM_WARM_BOOT_SUPPORT */ 34874 34875 /* 34876 * Function: 34877 * _bcm_rp_l3_init 34878 * Purpose: 34879 * Initialize l3 functionality on Raptor 6530x device. 34880 * Parameters: 34881 * unit - (IN)SOC unit number. 34882 * Returns: 34883 * BCM_E_XXX 34884 */ 34885 STATIC int 34886 _bcm_rp_l3_init(int unit) 34887 { 34888 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 34889 bcm_field_qset_t qset; /* FP qualifiers set. */ 34890 int mem_sz; /* Allocated memory size. */ 34891 int idx; /* Iteration index. */ 34892 int rv = BCM_E_NONE; /* Operation return status. */ 34893 #ifdef BCM_WARM_BOOT_SUPPORT 34894 int group_idx = 0; 34895 #endif 34896 /* If number of prefixes is 0 - L3 functionality is disabled.*/ 34897 /* 34898 * COVERITY 34899 * 34900 * The operands don't affect result. It is kept intentionally as 34901 * a defensive default for future development. 34902 */ 34903 /* coverity[result_independent_of_operands] */ 34904 if(!BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) { 34905 /* coverity[dead_error_line : FALSE] */ 34906 return (BCM_E_NONE); 34907 } 34908 34909 /* If fp rules & groups already present remove them first. */ 34910 if(BCM_XGS3_L3_INITIALIZED(unit)) { 34911 _bcm_rp_l3_deinit(unit); 34912 } 34913 34914 /* Get l3 prefixes table. */ 34915 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 34916 34917 /* Set min used host index & max used route index. */ 34918 tbl_ptr->route_maxused_rule_id = -1; 34919 tbl_ptr->host_minused_rule_id = BCM_XGS3_L3_RP_MAX_PREFIXES(unit); 34920 34921 /* Get number of rules per group. */ 34922 _bcm_rp_grp_rules_num_get(unit, &tbl_ptr->rules_per_group); 34923 34924 /* Get number of groups. */ 34925 tbl_ptr->l3_group_num = 34926 BCM_XGS3_L3_RP_MAX_PREFIXES(unit)/tbl_ptr->rules_per_group; 34927 if (BCM_XGS3_L3_RP_MAX_PREFIXES(unit) % tbl_ptr->rules_per_group) { 34928 tbl_ptr->l3_group_num++; 34929 } 34930 34931 /* FP group handlers. */ 34932 mem_sz = tbl_ptr->l3_group_num * sizeof(_bcm_rp_l3_fp_group_t); 34933 BCM_XGS3_L3_ALLOC(tbl_ptr->l3_grp, mem_sz, "l3_fp_groups"); 34934 if (NULL == tbl_ptr->l3_grp) { 34935 _bcm_rp_l3_deinit(unit); 34936 return (BCM_E_MEMORY); 34937 } 34938 34939 /* FP rule handlers. */ 34940 mem_sz = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) * sizeof(_bcm_rp_l3_entry_t); 34941 BCM_XGS3_L3_ALLOC(tbl_ptr->l3_arr, mem_sz, "l3_fp_rules"); 34942 if (NULL == tbl_ptr->l3_arr) { 34943 _bcm_rp_l3_deinit(unit); 34944 return (BCM_E_MEMORY); 34945 } 34946 34947 /* Create qualifiers set. */ 34948 BCM_FIELD_QSET_INIT(qset); 34949 34950 /* Add qualifier fields. */ 34951 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyIpType); 34952 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL2Format); 34953 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyVlanFormat); 34954 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstIp6); 34955 #if defined(BCM_MIRAGE_SUPPORT) 34956 if (soc_feature(unit, soc_feature_fp_routing_mirage)) { 34957 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstPort); 34958 } else 34959 #endif /* BCM_MIRAGE_SUPPORT */ 34960 { 34961 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL3Routable); 34962 } 34963 34964 #ifdef BCM_WARM_BOOT_SUPPORT 34965 if (SOC_IS_HAWKEYE(unit)) { 34966 if (SOC_WARM_BOOT(unit)) { 34967 rv = bcm_esw_field_group_traverse(unit, 34968 _bcm_rp_l3_group_reload, 34969 &group_idx); 34970 /* Init is done if nothing recovered. */ 34971 if (tbl_ptr->route_maxused_rule_id == -1 && 34972 tbl_ptr->host_minused_rule_id == BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) { 34973 return BCM_E_NONE; 34974 } 34975 rv = _bcm_hk_l3_field_init(unit); 34976 return (rv); 34977 } 34978 return BCM_E_NONE; 34979 } 34980 #endif 34981 34982 /* Add FP groups. */ 34983 for (idx = 0; idx < tbl_ptr->l3_group_num; idx++) { 34984 /* Create FP group. */ 34985 rv = bcm_esw_field_group_create(unit, qset, BCM_FIELD_GROUP_PRIO_ANY, 34986 &tbl_ptr->l3_grp[idx].grp_hdlr); 34987 if (rv < 0) { 34988 goto RP_INIT_ERR; 34989 } 34990 /* Set max & min prefix length indexes. */ 34991 tbl_ptr->l3_grp[idx].max_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34992 tbl_ptr->l3_grp[idx].min_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX; 34993 } 34994 34995 /* Sort groups by priority. */ 34996 _shr_sort(tbl_ptr->l3_grp, tbl_ptr->l3_group_num, 34997 sizeof(_bcm_rp_l3_fp_group_t), _bcm_rp_grp_priority_cmp); 34998 34999 /* Allocate rule handlers. */ 35000 for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) { 35001 rv = _bcm_rp_l3_rule_create(unit, idx); 35002 if (rv < 0) { 35003 goto RP_INIT_ERR; 35004 } 35005 } 35006 return (BCM_E_NONE); 35007 35008 RP_INIT_ERR: 35009 _bcm_rp_l3_deinit(unit); 35010 return rv; 35011 } 35012 35013 /* 35014 * Function: 35015 * _bcm_rp_l3_entry_idx_get 35016 * Purpose: 35017 * Get host entry index. 35018 * Parameters: 35019 * unit - (IN)SOC unit number. 35020 * l3cfg - (IN)Host lookup key. 35021 * rule_idx - (OUT) Entry index. 35022 * Returns: 35023 * BCM_E_XXX 35024 */ 35025 STATIC int 35026 _bcm_rp_l3_entry_idx_get(int unit, _bcm_l3_cfg_t *l3cfg, int *rule_idx) 35027 { 35028 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35029 _bcm_rp_l3_entry_t *l3_entry; /* L3 host entry. */ 35030 int ipv6; /* Entry family. */ 35031 int idx; /* Iteration index. */ 35032 35033 /* Get l3 prefixes table. */ 35034 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35035 35036 /* Get entry type. */ 35037 ipv6 = l3cfg->l3c_flags & BCM_L3_IP6; 35038 35039 /* Iterate over all host rules try to match passed address. */ 35040 for (idx = tbl_ptr->host_minused_rule_id; 35041 idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) { 35042 35043 l3_entry = &tbl_ptr->l3_arr[idx]; 35044 /* Skip family mismatch and invalid entries. */ 35045 if (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID) || 35046 ((l3_entry->flags & BCM_L3_IP6) != ipv6)) { 35047 continue; 35048 } 35049 35050 /* Compare requested address with entry address. */ 35051 if (ipv6) { 35052 if(sal_memcmp(l3_entry->addr.ip6, 35053 l3cfg->l3c_ip6, sizeof(bcm_ip6_t))) { 35054 continue; 35055 } 35056 } else { 35057 if (l3_entry->addr.ip4 != l3cfg->l3c_ip_addr) { 35058 continue; 35059 } 35060 } 35061 /* Entry Found. */ 35062 *rule_idx = idx; 35063 return (BCM_E_NONE); 35064 } 35065 /* Passed over all the entries & didn't find the match. */ 35066 return (BCM_E_NOT_FOUND); 35067 } 35068 35069 /* 35070 * Function: 35071 * _bcm_rp_l3_ent_parse 35072 * Purpose: 35073 * Service routine used to parse l3 entry to api format. 35074 * Parameters: 35075 * unit - (IN)SOC unit number. 35076 * l3cfg - (OUT)l3 entry lookup key & search result. 35077 * nh_idx - (OUT)Next hop index. 35078 * rule_idx - (IN)Rule index. 35079 * Returns: 35080 * void 35081 */ 35082 STATIC void 35083 _bcm_rp_l3_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int rule_idx) 35084 { 35085 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35086 int ipv6; /* Entry is IPv6 flag. */ 35087 uint64 usage_cntr; /* Entry usage counter. */ 35088 int rv; /* Operation return status. */ 35089 bcm_field_stat_t stat_type; /* FP entry Stat type. */ 35090 int stat_id; /* FP entry Stat ID. */ 35091 35092 /* Get l3 prefixes table. */ 35093 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35094 35095 /* Get lookup type. */ 35096 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 35097 35098 /* Reset entry flags first. */ 35099 l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0; 35100 35101 /* Set entry hw index. */ 35102 l3cfg->l3c_hw_index = rule_idx; 35103 35104 /* Set vrf id to default. */ 35105 l3cfg->l3c_vrf = BCM_L3_VRF_DEFAULT; 35106 35107 35108 /* Get the Stat ID. */ 35109 rv = bcm_esw_field_entry_stat_get(unit, tbl_ptr->l3_arr[rule_idx].rule_hdlr, 35110 &stat_id); 35111 if (BCM_SUCCESS(rv)) { 35112 /* Get entry Stat value. */ 35113 stat_type = bcmFieldStatPackets; 35114 rv = bcm_esw_field_stat_get(unit, stat_id, stat_type, &usage_cntr); 35115 if ((rv >= 0) && (!COMPILER_64_IS_ZERO(usage_cntr))) { 35116 l3cfg->l3c_flags |= BCM_L3_HIT; 35117 } 35118 } 35119 35120 /* Get next hop index. */ 35121 if(nh_idx) { 35122 *nh_idx = tbl_ptr->l3_arr[rule_idx].nh_idx; 35123 } 35124 35125 return; 35126 } 35127 35128 /* 35129 * Function: 35130 * _bcm_rp_l3_pack 35131 * Purpose: 35132 * Pack l3 entries & free space for routes. 35133 * Parameters: 35134 * unit - (IN)SOC unit number. 35135 * Returns: 35136 * BCM_E_NONE - If pack succeeded. 35137 * BCM_E_FULL - Otherwise. 35138 */ 35139 STATIC int 35140 _bcm_rp_l3_pack(int unit) 35141 { 35142 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35143 int rule_idx; /* Entry index to write. */ 35144 35145 /* Get l3 prefixes table. */ 35146 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35147 35148 /* Try to find unused index. */ 35149 for(rule_idx = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) - 1; 35150 rule_idx > tbl_ptr->route_maxused_rule_id; rule_idx--) { 35151 if(!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID)) { 35152 break; 35153 } 35154 } 35155 35156 /* If failed to allocated a new index -> table is full. */ 35157 if (rule_idx == tbl_ptr->route_maxused_rule_id) { 35158 return (BCM_E_FULL); 35159 } 35160 35161 /* Shift last entry into an empty slot. */ 35162 _bcm_rp_l3_entry_shift(unit, rule_idx, tbl_ptr->host_minused_rule_id); 35163 35164 /* Update host minused rule id. */ 35165 rule_idx = tbl_ptr->host_minused_rule_id; 35166 while (!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID) && 35167 rule_idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) { 35168 rule_idx++; 35169 } 35170 tbl_ptr->host_minused_rule_id = rule_idx; 35171 35172 return (BCM_E_NONE); 35173 } 35174 35175 /* 35176 * Function: 35177 * _bcm_rp_l3_get 35178 * Purpose: 35179 * Get an entry from L3 table. 35180 * Parameters: 35181 * unit - (IN)SOC unit number. 35182 * l3cfg - (IN/OUT)l3 entry lookup key & search result. 35183 * nh_index - (OUT)Next hop index. 35184 * Returns: 35185 * BCM_E_XXX 35186 */ 35187 STATIC int 35188 _bcm_rp_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx) 35189 { 35190 int clear_hit; /* Clear hit bit indicator. */ 35191 int rule_idx; /* Array entry index. */ 35192 int rv; /* Operation return status. */ 35193 35194 /* Preserve clear_hit value. */ 35195 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 35196 35197 /* Lookup hosts table for match. */ 35198 rv = _bcm_rp_l3_entry_idx_get(unit, l3cfg, &rule_idx); 35199 if(rv >= 0) { 35200 /* Entry Found - parse it. */ 35201 _bcm_rp_l3_ent_parse(unit, l3cfg, nh_idx, rule_idx); 35202 35203 /* Clear the HIT bit */ 35204 if (clear_hit) { 35205 rv = _bcm_rp_l3_usage_cntr_set(unit, rule_idx, 35206 BCM_XGS3_L3_INVALID_INDEX, 0); 35207 } 35208 } 35209 35210 return (rv); 35211 } 35212 35213 /* 35214 * Function: 35215 * _bcm_rp_l3_add 35216 * Purpose: 35217 * Add an entry to L3 table. 35218 * Parameters: 35219 * unit - (IN)SOC unit number. 35220 * l3cfg - (IN)l3 entry information. 35221 * nh_idx - (IN)Next hop index. 35222 * Returns: 35223 * BCM_E_XXX 35224 */ 35225 STATIC int 35226 _bcm_rp_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 35227 { 35228 _bcm_rp_l3_entry_t l3_entry; /* Host entry information. */ 35229 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35230 int rule_idx; /* Entry index to write. */ 35231 int rv; /* Operation return status. */ 35232 35233 /* Initialization. */ 35234 sal_memset(&l3_entry, 0, sizeof(_bcm_rp_l3_entry_t)); 35235 35236 /* Get l3 prefixes table. */ 35237 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35238 #ifdef BCM_WARM_BOOT_SUPPORT 35239 /* Initialize field if necessary. */ 35240 if (SOC_IS_HAWKEYE(unit)) { 35241 if ( tbl_ptr->route_maxused_rule_id == -1 && 35242 tbl_ptr->host_minused_rule_id == BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) { 35243 rv = _bcm_hk_l3_field_init(unit); 35244 if (BCM_FAILURE(rv)) { 35245 return (rv); 35246 } 35247 } 35248 } 35249 #endif 35250 /* Fill the entry info. */ 35251 35252 /* Set family . */ 35253 l3_entry.flags = l3cfg->l3c_flags & BCM_L3_IP6; 35254 35255 /* Set hit bit. */ 35256 l3_entry.flags |= l3cfg->l3c_flags & BCM_L3_HIT; 35257 35258 /* Set next hop index. */ 35259 l3_entry.nh_idx = nh_idx; 35260 35261 /* Set address and prefix length. */ 35262 if (l3_entry.flags & BCM_L3_IP6) { 35263 l3_entry.prefixlen = BCM_XGS3_L3_IPV6_PREFIX_LEN; 35264 sal_memcpy(l3_entry.addr.ip6, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 35265 } else { 35266 l3_entry.prefixlen = BCM_XGS3_L3_IPV4_PREFIX_LEN; 35267 l3_entry.addr.ip4 = l3cfg->l3c_ip_addr; 35268 } 35269 35270 /* Handle replacement if hw index already known, write directly. */ 35271 if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) { 35272 rule_idx = l3cfg->l3c_hw_index; 35273 35274 /* Remove original entry & actions */ 35275 _bcm_rp_l3_entry_delete(unit, rule_idx); 35276 } else { 35277 /* Allocate a new index otherwise. */ 35278 for(rule_idx = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) - 1; 35279 rule_idx > tbl_ptr->route_maxused_rule_id; rule_idx--) { 35280 if(!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID)) { 35281 break; 35282 } 35283 } 35284 /* If failed to allocated a new index -> table is full. */ 35285 if (rule_idx == tbl_ptr->route_maxused_rule_id) { 35286 return (BCM_E_FULL); 35287 } 35288 } 35289 35290 /* Add rule to FP. */ 35291 rv = _bcm_rp_l3_entry_add(unit, rule_idx, &l3_entry); 35292 35293 /* Write status check. */ 35294 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 35295 /* Update host entry count. */ 35296 (l3_entry.flags & BCM_L3_IP6) ? \ 35297 BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++; 35298 35299 /* Update host min used index. */ 35300 if (rule_idx < tbl_ptr->host_minused_rule_id) { 35301 tbl_ptr->host_minused_rule_id = rule_idx; 35302 } 35303 } 35304 35305 return (rv); 35306 } 35307 35308 /* 35309 * Function: 35310 * _bcm_rp_l3_del 35311 * Purpose: 35312 * Delete an entry from L3 table. 35313 * Parameters: 35314 * unit - (IN)SOC unit number. 35315 * l3cfg - (IN)l3 entry deletion key. 35316 * Returns: 35317 * BCM_E_XXX 35318 */ 35319 STATIC int 35320 _bcm_rp_l3_del(int unit, _bcm_l3_cfg_t *l3cfg) 35321 { 35322 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35323 int rule_idx; /* L3 entry rule index. */ 35324 int rv; /* Operation return status. */ 35325 35326 /* Get l3 prefixes table. */ 35327 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35328 35329 /* Lookup hosts table for match. */ 35330 rv = _bcm_rp_l3_entry_idx_get(unit, l3cfg, &rule_idx); 35331 BCM_IF_ERROR_RETURN(rv); 35332 35333 /* Delete the entry.*/ 35334 rv = _bcm_rp_l3_entry_delete(unit, rule_idx); 35335 35336 /* Write status check. */ 35337 if (rv >= 0) { 35338 /* Update host entry count. */ 35339 (l3cfg->l3c_flags & BCM_L3_IP6) ? \ 35340 BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--; 35341 35342 /* Update host min used index. */ 35343 if (rule_idx == tbl_ptr->host_minused_rule_id) { 35344 while (!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID) && 35345 rule_idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) { 35346 rule_idx++; 35347 } 35348 tbl_ptr->host_minused_rule_id = rule_idx; 35349 } 35350 } 35351 35352 return (rv); 35353 } 35354 35355 /* 35356 * Function: 35357 * _bcm_rp_l3_get_by_idx 35358 * Purpose: 35359 * Get an entry from L3 table by index. 35360 * Parameters: 35361 * unit - (IN)SOC unit number. 35362 * dma_ptr - (IN)NOT USED 35363 * idx - (IN)Index to read. 35364 * l3cfg - (OUT)l3 entry search result. 35365 * nh_index - (OUT)Next hop index. 35366 * Returns: 35367 * BCM_E_XXX 35368 */ 35369 STATIC int 35370 _bcm_rp_l3_get_by_idx(int unit, void *dma_ptr, int idx, 35371 _bcm_l3_cfg_t *l3cfg, int *nh_idx) 35372 { 35373 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35374 _bcm_rp_l3_entry_t *l3_entry; /* L3 host entry. */ 35375 int clear_hit; /* Clear hit bit indicator. */ 35376 int rule_idx; /* Array entry index. */ 35377 int ipv6; /* Entry family to read. */ 35378 int rv = BCM_E_NONE; /* Operation return status. */ 35379 35380 /* Get entry type. */ 35381 ipv6 = l3cfg->l3c_flags & BCM_L3_IP6; 35382 35383 /* Get l3 prefixes table. */ 35384 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35385 35386 /* Preserve clear_hit value. */ 35387 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 35388 35389 /* Calculate rule index. */ 35390 rule_idx = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) - idx; 35391 if (rule_idx < 0) { 35392 return (BCM_E_NOT_FOUND); 35393 } 35394 35395 l3_entry = &tbl_ptr->l3_arr[rule_idx]; 35396 35397 /* Make sure entry is a host & valid. */ 35398 if ((rule_idx < tbl_ptr->host_minused_rule_id) || 35399 (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID))) { 35400 return (BCM_E_NOT_FOUND); 35401 } 35402 35403 /* Get entry protocol. */ 35404 l3cfg->l3c_flags = l3_entry->flags & BCM_L3_IP6; 35405 35406 /* If protocol doesn't match the request return. */ 35407 if ((l3_entry->flags & BCM_L3_IP6) != ipv6) { 35408 return (BCM_E_NONE); 35409 } 35410 35411 /* Get entry address. */ 35412 if (ipv6) { 35413 sal_memcpy(l3cfg->l3c_ip6, l3_entry->addr.ip6, sizeof(bcm_ip6_t)); 35414 } else { 35415 l3cfg->l3c_ip_addr = l3_entry->addr.ip4; 35416 } 35417 35418 /* Parset entry flags. */ 35419 _bcm_rp_l3_ent_parse(unit, l3cfg, nh_idx, rule_idx); 35420 35421 /* Clear the HIT bit */ 35422 if (clear_hit) { 35423 rv = _bcm_rp_l3_usage_cntr_set(unit, rule_idx, 35424 BCM_XGS3_L3_INVALID_INDEX, 0); 35425 } 35426 35427 /* Set index to l3cfg. */ 35428 l3cfg->l3c_hw_index = idx; 35429 35430 return (rv); 35431 } 35432 35433 /* 35434 * Function: 35435 * _bcm_rp_lpm_ent_parse 35436 * Purpose: 35437 * Service routine used to parse l3 entry to api format. 35438 * Parameters: 35439 * unit - (IN)SOC unit number. 35440 * lpm_cfg - (IN/OUT)l3 entry lookup key & search result. 35441 * nh_idx - (OUT)Next hop index. 35442 * rule_idx - (IN)Rule index. 35443 * Returns: 35444 * void 35445 */ 35446 STATIC void 35447 _bcm_rp_lpm_ent_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 35448 int *nh_idx, int rule_idx) 35449 { 35450 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35451 int ipv6; /* Entry is IPv6 flag. */ 35452 uint64 usage_cntr; /* Entry usage counter. */ 35453 int rv; /* Operation return status. */ 35454 bcm_field_stat_t stat_type; /* FP entry Stat type. */ 35455 int stat_id; /* FP entry Stat ID. */ 35456 35457 /* Get l3 prefixes table. */ 35458 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35459 35460 /* Get lookup type. */ 35461 ipv6 = (lpm_cfg->defip_flags & BCM_L3_IP6); 35462 35463 /* Reset entry flags first. */ 35464 lpm_cfg->defip_flags = (ipv6) ? BCM_L3_IP6 : 0; 35465 35466 /* Set entry ecmp flag. */ 35467 lpm_cfg->defip_flags |= 35468 (tbl_ptr->l3_arr[rule_idx].flags & BCM_L3_MULTIPATH); 35469 35470 /* Set vrf id to default. */ 35471 lpm_cfg->defip_vrf = BCM_L3_VRF_DEFAULT; 35472 35473 /* Set index of the defip table entry */ 35474 lpm_cfg->defip_index = rule_idx; 35475 35476 /* Get the Stat ID. */ 35477 rv = bcm_esw_field_entry_stat_get(unit, 35478 tbl_ptr->l3_arr[rule_idx].rule_hdlr, 35479 &stat_id); 35480 if (BCM_SUCCESS(rv)) { 35481 /* Get entry Stat value. */ 35482 stat_type = bcmFieldStatPackets; 35483 rv = bcm_esw_field_stat_get(unit, stat_id, stat_type, &usage_cntr); 35484 if ((rv >= 0) && (!COMPILER_64_IS_ZERO(usage_cntr))) { 35485 lpm_cfg->defip_flags |= BCM_L3_HIT; 35486 } 35487 } 35488 35489 /* Get next hop index. */ 35490 if(nh_idx) { 35491 *nh_idx = tbl_ptr->l3_arr[rule_idx].nh_idx; 35492 } 35493 35494 return; 35495 } 35496 35497 /* 35498 * Function: 35499 * _bcm_rp_lpm_entry_idx_get 35500 * Purpose: 35501 * Get route entry rule index. 35502 * Parameters: 35503 * unit - (IN)SOC unit number. 35504 * lpm_cfg - (IN)Route lookup key. 35505 * rule_idx - (OUT) Entry index. 35506 * Returns: 35507 * BCM_E_XXX 35508 */ 35509 STATIC int 35510 _bcm_rp_lpm_entry_idx_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *rule_idx) 35511 { 35512 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35513 _bcm_rp_l3_entry_t *l3_entry; /* L3 route entry. */ 35514 int ipv6; /* Entry family. */ 35515 int idx; /* Iteration index. */ 35516 35517 /* Get l3 prefixes table. */ 35518 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35519 35520 /* Get entry type. */ 35521 ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 35522 35523 /* Iterate over all host rules try to match passed address. */ 35524 for (idx = 0; idx <= tbl_ptr->route_maxused_rule_id; idx++) { 35525 35526 l3_entry = &tbl_ptr->l3_arr[idx]; 35527 /* Skip family mismatch/prefix length mismatch and invalid entries. */ 35528 if (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID) || 35529 ((l3_entry->flags & BCM_L3_IP6) != ipv6) || 35530 (l3_entry->prefixlen != lpm_cfg->defip_sub_len)) { 35531 continue; 35532 } 35533 35534 /* Compare requested address with entry address. */ 35535 if (ipv6) { 35536 if(sal_memcmp(l3_entry->addr.ip6, 35537 lpm_cfg->defip_ip6_addr, sizeof(bcm_ip6_t))) { 35538 continue; 35539 } 35540 } else { 35541 if (l3_entry->addr.ip4 != lpm_cfg->defip_ip_addr) { 35542 continue; 35543 } 35544 } 35545 /* Entry Found. */ 35546 *rule_idx = idx; 35547 return (BCM_E_NONE); 35548 } 35549 /* Passed over all the entries & didn't find the match. */ 35550 return (BCM_E_NOT_FOUND); 35551 } 35552 35553 /* 35554 * Function: 35555 * _bcm_rp_lpm_entry_insert 35556 * Purpose: 35557 * Allocate rule index and write route to FP. 35558 * Function invoked recursively if there is no room in destination 35559 * group & rules shift is required. Max prefix length rule in each 35560 * group shifted one group ahead. 35561 * Parameters: 35562 * unit - (IN)SOC unit number. 35563 * lpm_cfg - (IN)Buffer to fill defip information. 35564 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 35565 * Returns: 35566 * BCM_E_XXX 35567 */ 35568 STATIC int 35569 _bcm_rp_lpm_entry_insert(int unit, _bcm_rp_l3_entry_t *l3_entry, int shift_idx) 35570 { 35571 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35572 int max_prefix_len_idx; /* Max prefix length rule idx in group */ 35573 int *max_rt_idx; /* Last route rule index. */ 35574 int grp_idx; /* FP group index. */ 35575 int insert_idx = BCM_XGS3_L3_INVALID_INDEX; /* Rule insertion index. */ 35576 35577 /* Get l3 prefixes table. */ 35578 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35579 35580 /* Get max used route rule index. */ 35581 max_rt_idx = &tbl_ptr->route_maxused_rule_id; 35582 35583 if(BCM_XGS3_L3_INVALID_INDEX == shift_idx) { 35584 /* Attempt to insert into the first group. */ 35585 grp_idx = 0; 35586 } else { 35587 /* 35588 * Group is full shift required - move maximum prefix 35589 * length rule to the next group (group + 1). 35590 */ 35591 grp_idx = (shift_idx/tbl_ptr->rules_per_group) + 1; 35592 } 35593 35594 /* Iterate over all the group & try to find free rule idx. */ 35595 for(; grp_idx < tbl_ptr->l3_group_num; grp_idx++) { 35596 /* Get group longet prefix rule index. */ 35597 max_prefix_len_idx = tbl_ptr->l3_grp[grp_idx].max_prefix_len_idx; 35598 35599 /* Check if group has an empty slot. NOTE: max_rt_idx is 0 based.*/ 35600 if((grp_idx + 1) * tbl_ptr->rules_per_group > (*max_rt_idx + 1)) { 35601 35602 /* Make sure we are not overwriting host entries. */ 35603 if((*max_rt_idx) + 1 == tbl_ptr->host_minused_rule_id) { 35604 /* Attempt to pack host entries. */ 35605 BCM_IF_ERROR_RETURN(_bcm_rp_l3_pack(unit)); 35606 } 35607 35608 /* Set write index to max used + 1 */ 35609 insert_idx = ++(*max_rt_idx); 35610 break; 35611 35612 /* Check if prefix length belongs to the group & there */ 35613 } else if(tbl_ptr->l3_arr[max_prefix_len_idx].prefixlen > 35614 l3_entry->prefixlen) { 35615 35616 /* If this is last group - we can't shift rules anymore. */ 35617 if (grp_idx == tbl_ptr->l3_group_num - 1) { 35618 break; 35619 } 35620 35621 /* 35622 * Shift max prefix length entry to the next group. 35623 * Write new entry into max prefix length entry place. 35624 */ 35625 insert_idx = max_prefix_len_idx; 35626 BCM_IF_ERROR_RETURN 35627 (_bcm_rp_lpm_entry_insert(unit,&tbl_ptr->l3_arr[insert_idx], 35628 insert_idx)); 35629 break; 35630 } 35631 } 35632 35633 /* If failed to allocate an index - table is full. */ 35634 if (insert_idx == BCM_XGS3_L3_INVALID_INDEX) { 35635 return (BCM_E_FULL); 35636 } 35637 35638 /* Write entry to FP & update group properties. */ 35639 BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_add(unit, insert_idx, l3_entry)); 35640 35641 /* Update group max/min prefix location. */ 35642 _bcm_rp_lpm_group_add_del(unit, insert_idx, l3_entry->prefixlen); 35643 35644 /* If entry was shifted -> delete original entry. */ 35645 if(BCM_XGS3_L3_INVALID_INDEX != shift_idx) { 35646 /* Remove shifted rule. */ 35647 BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_delete(unit, shift_idx)); 35648 35649 /* Decrement number of rules in original group */ 35650 _bcm_rp_lpm_group_add_del(unit, shift_idx, BCM_XGS3_L3_INVALID_INDEX); 35651 } 35652 return (BCM_E_NONE); 35653 } 35654 35655 /* 35656 * Function: 35657 * _bcm_rp_lpm_entry_remove 35658 * Purpose: 35659 * Free rule index and delete route rule from FP. 35660 * Function fills gaps rule array. And invoked recursively 35661 * if there are rules in higher groups - which need to be 35662 * shifted to to lower group which currently has an empty space. 35663 * Parameters: 35664 * unit - (IN)SOC unit number. 35665 * rule_idx - (IN)Route entry rule for deletion. 35666 * Returns: 35667 * BCM_E_XXX 35668 */ 35669 STATIC int 35670 _bcm_rp_lpm_entry_remove(int unit, int rule_idx) 35671 { 35672 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35673 int *max_rt_idx; /* Last route rule index. */ 35674 int shift_idx; /* Shifted entry rule index. */ 35675 int grp_idx; /* FP group index. */ 35676 35677 /* Get l3 prefixes table. */ 35678 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35679 35680 /* Get max used route rule index. */ 35681 max_rt_idx = &tbl_ptr->route_maxused_rule_id; 35682 35683 /* Get FP group index. */ 35684 grp_idx = (rule_idx/tbl_ptr->rules_per_group); 35685 35686 /* Remove the rule from FP. */ 35687 BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_delete(unit, rule_idx)); 35688 35689 /* Update group prefix count & min/max locations. */ 35690 _bcm_rp_lpm_group_add_del(unit, rule_idx, BCM_XGS3_L3_INVALID_INDEX); 35691 35692 /* If last entry was removed just decrement max used route index. */ 35693 if (rule_idx == (*max_rt_idx)) { 35694 /* Last entry was removed update max route index. */ 35695 (*max_rt_idx)--; 35696 return (BCM_E_NONE); 35697 } 35698 35699 /* 35700 * If all the routes are in the same group, take the last one 35701 * and write to the location of the deleted one. 35702 * If routes are spread across the groups, shift min prefixlen 35703 * route in each group one group down. 35704 */ 35705 if((grp_idx + 1) * tbl_ptr->rules_per_group > (*max_rt_idx)) { 35706 35707 /* Last group. */ 35708 shift_idx = (*max_rt_idx); 35709 35710 /* Swap last entry with deleted one. */ 35711 _bcm_rp_l3_entry_swap(unit, rule_idx, shift_idx); 35712 35713 /* If maximum prefix length entry shifted update index. */ 35714 if (shift_idx == tbl_ptr->l3_grp[grp_idx].max_prefix_len_idx) { 35715 tbl_ptr->l3_grp[grp_idx].max_prefix_len_idx = rule_idx; 35716 } 35717 35718 /* If minimum prefix length entry shifted update index. */ 35719 if (shift_idx == tbl_ptr->l3_grp[grp_idx].min_prefix_len_idx) { 35720 tbl_ptr->l3_grp[grp_idx].min_prefix_len_idx = rule_idx; 35721 } 35722 35723 /* Since we are shifting last entry decrement max route index. */ 35724 (*max_rt_idx)--; 35725 } else { 35726 35727 /* Shift min prefix length entry from the next group if any. */ 35728 shift_idx = tbl_ptr->l3_grp[grp_idx + 1].min_prefix_len_idx; 35729 35730 /* Perform rule shift operation. */ 35731 BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_shift(unit, rule_idx, shift_idx)); 35732 35733 /* Add shifted rule prefix length to the destination group. */ 35734 _bcm_rp_lpm_group_add_del(unit, rule_idx, 35735 tbl_ptr->l3_arr[shift_idx].prefixlen); 35736 } 35737 return (BCM_E_NONE); 35738 } 35739 35740 35741 /* 35742 * Function: 35743 * _bcm_rp_lpm_get 35744 * Purpose: 35745 * Get an entry from DEFIP table. 35746 * Parameters: 35747 * unit - (IN)SOC unit number. 35748 * lpm_cfg - (IN)Buffer to fill defip information. 35749 * nh_ecmp_idx - (IN)Next hop or ecmp group index 35750 * Returns: 35751 * BCM_E_XXX 35752 */ 35753 STATIC int 35754 _bcm_rp_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 35755 { 35756 int clear_hit; /* Clear hit bit indicator. */ 35757 int rule_idx; /* Array entry index. */ 35758 int rv; /* Operation return status. */ 35759 35760 /* Preserve clear_hit value. */ 35761 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 35762 35763 /* Lookup hosts table for match. */ 35764 rv = _bcm_rp_lpm_entry_idx_get(unit, lpm_cfg, &rule_idx); 35765 if(rv >= 0) { 35766 /* Entry Found - parse it. */ 35767 _bcm_rp_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, rule_idx); 35768 35769 /* Clear the HIT bit */ 35770 if (clear_hit) { 35771 rv = _bcm_rp_l3_usage_cntr_set(unit, rule_idx, 35772 BCM_XGS3_L3_INVALID_INDEX, 0); 35773 } 35774 } 35775 35776 return (rv); 35777 } 35778 35779 /* 35780 * Function: 35781 * _bcm_rp_lpm_add 35782 * Purpose: 35783 * Add an entry to route table. 35784 * Parameters: 35785 * unit - (IN)SOC unit number. 35786 * lpm_cfg - (IN)Buffer to fill defip information. 35787 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 35788 * Returns: 35789 * BCM_E_XXX 35790 */ 35791 STATIC int 35792 _bcm_rp_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 35793 { 35794 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35795 _bcm_rp_l3_entry_t l3_entry; /* Route entry. */ 35796 int rule_idx; /* Entry index to write. */ 35797 int rv; /* Operation return status. */ 35798 35799 /* Get l3 prefixes table. */ 35800 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35801 35802 #ifdef BCM_WARM_BOOT_SUPPORT 35803 /* Initialize field if necessary. */ 35804 if (SOC_IS_HAWKEYE(unit)) { 35805 if ( tbl_ptr->route_maxused_rule_id == -1 && 35806 tbl_ptr->host_minused_rule_id == BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) { 35807 rv = _bcm_hk_l3_field_init(unit); 35808 if (BCM_FAILURE(rv)) { 35809 return (rv); 35810 } 35811 } 35812 } 35813 #endif 35814 /* Fill the entry info. */ 35815 /* Set family and prefix length. */ 35816 l3_entry.flags = lpm_cfg->defip_flags & BCM_L3_IP6; 35817 35818 /* Set hit bit. */ 35819 l3_entry.flags |= lpm_cfg->defip_flags & BCM_L3_HIT; 35820 35821 /* Set ecmp bit. */ 35822 l3_entry.flags |= lpm_cfg->defip_flags & BCM_L3_MULTIPATH; 35823 35824 /* Set prefix length. */ 35825 l3_entry.prefixlen = lpm_cfg->defip_sub_len; 35826 35827 /* Set subnet address */ 35828 if (l3_entry.flags & BCM_L3_IP6) { 35829 sal_memcpy(l3_entry.addr.ip6, lpm_cfg->defip_ip6_addr, sizeof(bcm_ip6_t)); 35830 } else { 35831 l3_entry.addr.ip4 = lpm_cfg->defip_ip_addr; 35832 } 35833 35834 /* Set next hop index. */ 35835 l3_entry.nh_idx = nh_ecmp_idx; 35836 35837 /* Handle replacement if hw index already known, write directly. */ 35838 if (BCM_XGS3_L3_INVALID_INDEX != lpm_cfg->defip_index) { 35839 35840 rule_idx = lpm_cfg->defip_index; 35841 35842 /* Remove original entry & actions */ 35843 _bcm_rp_l3_entry_delete(unit, rule_idx); 35844 35845 /* Only next hop update is supported. */ 35846 tbl_ptr->l3_arr[rule_idx].nh_idx = nh_ecmp_idx; 35847 35848 /* Write rule to FP. */ 35849 rv = _bcm_rp_l3_entry_add(unit, rule_idx, &tbl_ptr->l3_arr[rule_idx]); 35850 35851 return (rv); 35852 } 35853 35854 /* Add rule to FP. */ 35855 rv = _bcm_rp_lpm_entry_insert(unit, &l3_entry, BCM_XGS3_L3_INVALID_INDEX); 35856 35857 /* Increment number of routes. */ 35858 if (rv >= 0) { 35859 BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 35860 } 35861 35862 return (rv); 35863 } 35864 35865 /* 35866 * Function: 35867 * _bcm_rp_lpm_del 35868 * Purpose: 35869 * Delete an entry from route table. 35870 * Parameters: 35871 * unit - (IN)SOC unit number. 35872 * lpm_cfg - (IN)Buffer to fill defip information. 35873 * Returns: 35874 * BCM_E_XXX 35875 */ 35876 STATIC int 35877 _bcm_rp_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 35878 { 35879 int rule_idx; /* Array entry index. */ 35880 int rv; /* Operation return status. */ 35881 35882 /* Lookup hosts table for match. */ 35883 rv = _bcm_rp_lpm_entry_idx_get(unit, lpm_cfg, &rule_idx); 35884 BCM_IF_ERROR_RETURN(rv); 35885 35886 /* Remove the route rule from FP. */ 35887 rv = _bcm_rp_lpm_entry_remove(unit, rule_idx); 35888 35889 /* Decrement number of routes. */ 35890 if (rv >= 0) { 35891 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 35892 } 35893 35894 return (rv); 35895 } 35896 35897 /* 35898 * Function: 35899 * _bcm_rp_lpm_update_match 35900 * Purpose: 35901 * Update/Delete all entries in defip table matching a certain rule. 35902 * Parameters: 35903 * unit - (IN)SOC unit number. 35904 * trv_data - (IN)Delete pattern + compare,act,notify routines. 35905 * Returns: 35906 * BCM_E_XXX 35907 */ 35908 STATIC int 35909 _bcm_rp_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 35910 { 35911 _bcm_rp_l3_data_t *tbl_ptr; /* L3 sw table address. */ 35912 _bcm_rp_l3_entry_t *l3_entry; /* L3 route entry. */ 35913 _bcm_rp_l3_entry_t *rt_tbl; /* L3 route table shadow. */ 35914 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info.*/ 35915 int nh_ecmp_idx; /* Next hop/Ecmp group index.*/ 35916 int cmp_result; /* Test routine result. */ 35917 int tbl_sz; /* L3 route table size. */ 35918 int ipv6; /* Entry family. */ 35919 int idx; /* Iteration index. */ 35920 int rv = BCM_E_NOT_FOUND; /* Operation return status. */ 35921 35922 /* Get l3 prefixes table. */ 35923 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 35924 35925 /* Create shaddow image. */ 35926 35927 tbl_sz= (tbl_ptr->route_maxused_rule_id + 1) * sizeof(_bcm_rp_l3_entry_t); 35928 35929 /* Allocate memory for shadow image. */ 35930 rt_tbl = sal_alloc(tbl_sz, "rp_routes_shadow"); 35931 if (NULL == rt_tbl) { 35932 return (BCM_E_MEMORY); 35933 } 35934 35935 /* Copy all the routes. */ 35936 sal_memcpy(rt_tbl, tbl_ptr->l3_arr, tbl_sz); 35937 35938 /* Preserve route table size. */ 35939 tbl_sz = tbl_ptr->route_maxused_rule_id + 1; 35940 35941 /* Get requested entry type. */ 35942 ipv6 = trv_data->flags & BCM_L3_IP6; 35943 35944 /* Iterate over all host rules try to match passed address. */ 35945 for (idx = 0; idx < tbl_sz; idx++) { 35946 35947 l3_entry = rt_tbl + idx; 35948 35949 35950 /* Skip family mismatch/prefix length mismatch and invalid entries. */ 35951 if (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID) || 35952 ((l3_entry->flags & BCM_L3_IP6) != ipv6)) { 35953 continue; 35954 } 35955 35956 /* Zero destination buffer first. */ 35957 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 35958 35959 /* Set entry flags. */ 35960 lpm_cfg.defip_flags = l3_entry->flags & BCM_L3_IP6; 35961 35962 /* Fill entry ip address & prefix length. */ 35963 if (ipv6) { 35964 sal_memcpy(lpm_cfg.defip_ip6_addr, l3_entry->addr.ip6, 35965 sizeof(bcm_ip6_t)); 35966 } else { 35967 lpm_cfg.defip_ip_addr = l3_entry->addr.ip4; 35968 } 35969 lpm_cfg.defip_sub_len = l3_entry->prefixlen; 35970 35971 /* Get entry flags & info . */ 35972 _bcm_rp_lpm_get(unit, &lpm_cfg, &nh_ecmp_idx); 35973 35974 /* Execute operation routine if any. */ 35975 if (trv_data->op_cb) { 35976 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 35977 (void *)&lpm_cfg, 35978 (void *)&nh_ecmp_idx, &cmp_result); 35979 if (rv < 0) { 35980 sal_free(rt_tbl); 35981 return rv; 35982 } 35983 } 35984 } 35985 /* Free shadow image. */ 35986 sal_free(rt_tbl); 35987 return (BCM_E_NONE); 35988 } 35989 35990 #ifdef BCM_WARM_BOOT_SUPPORT 35991 /* 35992 * Function: 35993 * _bcm_rp_l3_group_reload 35994 * Purpose: 35995 * Restore l3 route entries from FP. 35996 * Parameters: 35997 * unit - (IN)SOC unit number. 35998 * Returns: 35999 * BCM_E_XXX 36000 */ 36001 static int _bcm_rp_l3_group_reload(int unit, bcm_field_group_t group, 36002 void *user_data) 36003 { 36004 int idx, pfx_len, rule_idx, rv, nh_index, update_grp_idx = 0; 36005 int *grp_idx; 36006 int entry_count, entry_num; 36007 bcm_field_IpType_t iptype; 36008 bcm_ip6_t data; 36009 bcm_ip6_t mask; 36010 bcm_ip_t ip_mask; 36011 _bcm_rp_l3_data_t *tbl_ptr; 36012 int alloc_sz; 36013 bcm_field_entry_t *entry_array, entry_id; 36014 uint32 param0, param1; 36015 36016 BCM_IF_ERROR_RETURN 36017 (bcm_esw_field_entry_multi_get(unit, group, 0, NULL, &entry_num)); 36018 36019 if (entry_num == 0) { 36020 return BCM_E_PARAM; 36021 } 36022 36023 alloc_sz = sizeof(bcm_field_entry_t) * entry_num; 36024 entry_array = sal_alloc(alloc_sz, "Field IDs"); 36025 if (NULL == entry_array) { 36026 return BCM_E_MEMORY; 36027 } 36028 sal_memset(entry_array, 0, alloc_sz); 36029 36030 rv = bcm_esw_field_entry_multi_get(unit, group, entry_num, 36031 entry_array, &entry_count); 36032 36033 if (BCM_FAILURE(rv)) { 36034 sal_free(entry_array); 36035 return rv; 36036 } 36037 36038 if (entry_count != entry_num) { 36039 /* Why didn't we get the number of ID's we were told existed? */ 36040 sal_free(entry_array); 36041 return BCM_E_INTERNAL; 36042 } 36043 36044 grp_idx = (int *)user_data; 36045 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix); 36046 36047 for (idx = 0; idx < entry_num; idx++) { 36048 entry_id = entry_array[idx]; 36049 rv = bcm_esw_field_action_get(unit, entry_id, 36050 bcmFieldActionL3Switch, 36051 ¶m0, ¶m1); 36052 if (BCM_SUCCESS(rv)) { 36053 if (*grp_idx >= tbl_ptr->l3_group_num) { 36054 sal_free(entry_array); 36055 return (BCM_E_NONE); 36056 } 36057 tbl_ptr->l3_grp[*grp_idx].grp_hdlr = group; 36058 nh_index = param0; 36059 } else { 36060 continue; 36061 } 36062 36063 rv = bcm_esw_field_qualify_IpType_get(unit, entry_id, &iptype); 36064 if (BCM_FAILURE(rv)) { 36065 continue; 36066 } 36067 36068 rv = bcm_esw_field_qualify_DstIp6_get(unit, entry_id, &data, &mask); 36069 if (BCM_FAILURE(rv)) { 36070 continue; 36071 } 36072 36073 update_grp_idx = 1; 36074 36075 if (iptype == bcmFieldIpTypeIpv6) { 36076 pfx_len = bcm_ip6_mask_length(mask); 36077 if (pfx_len == BCM_XGS3_L3_IPV6_PREFIX_LEN) { 36078 /* Assume this is host entry. */ 36079 tbl_ptr->host_minused_rule_id--; 36080 rule_idx = tbl_ptr->host_minused_rule_id; 36081 BCM_XGS3_L3_IP6_CNT(unit)++; 36082 } else { 36083 /* Assume this is route entry. */ 36084 tbl_ptr->route_maxused_rule_id++; 36085 rule_idx = tbl_ptr->route_maxused_rule_id; 36086 BCM_XGS3_L3_DEFIP_CNT_INC(unit, TRUE); 36087 tbl_ptr->l3_grp[*grp_idx].rule_count++; 36088 } 36089 sal_memcpy(tbl_ptr->l3_arr[rule_idx].addr.ip6, data, sizeof(bcm_ip6_t)); 36090 tbl_ptr->l3_arr[rule_idx].prefixlen = pfx_len; 36091 tbl_ptr->l3_arr[rule_idx].flags |= BCM_L3_IP6; 36092 } else { 36093 sal_memcpy(&ip_mask, 36094 (uint8 *)mask + BCM_XGS3_V4_IN_V6_OFFSET, 36095 sizeof(bcm_ip_t)); 36096 pfx_len = bcm_ip_mask_length(ip_mask); 36097 if (pfx_len == BCM_XGS3_L3_IPV4_PREFIX_LEN) { 36098 /* Assume this is host entry. */ 36099 tbl_ptr->host_minused_rule_id--; 36100 rule_idx = tbl_ptr->host_minused_rule_id; 36101 BCM_XGS3_L3_IP4_CNT(unit)++; 36102 36103 } else { 36104 /* Assume this is route entry. */ 36105 tbl_ptr->route_maxused_rule_id++; 36106 rule_idx = tbl_ptr->route_maxused_rule_id; 36107 BCM_XGS3_L3_DEFIP_CNT_INC(unit, FALSE); 36108 tbl_ptr->l3_grp[*grp_idx].rule_count++; 36109 } 36110 sal_memcpy(&tbl_ptr->l3_arr[rule_idx].addr.ip4, 36111 (uint8 *)data + BCM_XGS3_V4_IN_V6_OFFSET, 36112 sizeof(bcm_ip_t)); 36113 tbl_ptr->l3_arr[rule_idx].prefixlen = pfx_len; 36114 } 36115 tbl_ptr->l3_arr[rule_idx].rule_hdlr = entry_id; 36116 tbl_ptr->l3_arr[rule_idx].nh_idx = nh_index; 36117 tbl_ptr->l3_arr[rule_idx].flags |= BCM_XGS3_L3_ENT_VALID; 36118 } 36119 36120 if (update_grp_idx) { 36121 if (tbl_ptr->route_maxused_rule_id != -1 && 36122 *grp_idx < tbl_ptr->l3_group_num) { 36123 _bcm_rp_lpm_group_update(unit, *grp_idx); 36124 } 36125 *grp_idx = *grp_idx+1; 36126 } 36127 36128 if (rv == BCM_E_NOT_FOUND) { 36129 rv = BCM_E_NONE; /* Do not propagate this error */ 36130 } 36131 36132 sal_free(entry_array); 36133 return BCM_E_NONE; 36134 } 36135 #endif /* BCM_WARM_BOOT_SUPPORT */ 36136 36137 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 36138 36139 #endif /* BCM_FIREBOLT_SUPPORT */ 36140 36141 /* 36142 * Function: 36143 * _bcm_xgs3_l3_hw_call_init 36144 * Purpose: 36145 * Initialize L3 hardware operations memories & callbacks. 36146 * Parameters: 36147 * unit - (IN)SOC unit number. 36148 * Returns: 36149 * BCM_E_XXX 36150 */ 36151 STATIC int 36152 _bcm_xgs3_l3_hw_call_init(int unit) 36153 { 36154 #ifdef BCM_FIREBOLT_SUPPORT 36155 static _bcm_l3_hw_calls_t fb_hw_call[BCM_MAX_NUM_UNITS]; /* FBX hw calls . */ 36156 static _bcm_l3_intf_fields_t fb_l3_intf_fields; /* L3 intf fields. */ 36157 static _bcm_l3_nh_fields_t fb_nh_fields; /* NH table fields. */ 36158 static _bcm_l3_fields_t fb_l3_v4_fields; /* L3 ipv4 table fields. */ 36159 static _bcm_l3_fields_t fb_l3_v6_fields; /* L3 ipv6 table fields. */ 36160 #endif /* BCM_FIREBOLT_SUPPORT */ 36161 #if defined (BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 36162 defined(BCM_HAWKEYE_SUPPORT) 36163 static _bcm_l3_hw_calls_t rp_hw_call[BCM_MAX_NUM_UNITS]; /* Raptor/Raven hw calls. */ 36164 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 36165 #if defined(BCM_TRIUMPH_SUPPORT) 36166 static _bcm_l3_hw_calls_t tr_hw_call[BCM_MAX_NUM_UNITS]; /* Triumph hw calls. */ 36167 static _bcm_l3_fields_t tr_l3_v6_fields; /* Truimph l3 ipv6 fields.*/ 36168 #endif /* BCM_TRIUMPH_SUPPORT */ 36169 #if defined(BCM_TRX_SUPPORT) 36170 static _bcm_l3_nh_fields_t trx_nh_fields; /* NH table fields. */ 36171 #endif /* BCM_TRX_SUPPORT */ 36172 #if defined(BCM_TRIDENT_SUPPORT) 36173 static _bcm_l3_hw_calls_t td_hw_call[BCM_MAX_NUM_UNITS]; /* Trident hw calls. */ 36174 #endif /* BCM_TRIDENT_SUPPORT */ 36175 #if defined(BCM_TRIUMPH2_SUPPORT) 36176 static _bcm_l3_hw_calls_t tr2_hw_call[BCM_MAX_NUM_UNITS]; /* Triumph2 hw calls. */ 36177 #endif /* BCM_TRIUMPH2_SUPPORT */ 36178 #if defined(BCM_TRIDENT2_SUPPORT) 36179 static _bcm_l3_hw_calls_t td2_hw_call[BCM_MAX_NUM_UNITS]; /* Trident2 hw calls. */ 36180 static _bcm_l3_fields_t td2_l3_v4_fields; /* Trident2 l3 ipv4 fields.*/ 36181 static _bcm_l3_fields_t td2_l3_v4_2_fields; /* Trident2 l3 ext ipv4 fields.*/ 36182 static _bcm_l3_fields_t td2_l3_v6_fields; /* Trident2 l3 ipv6 fields.*/ 36183 static _bcm_l3_fields_t td2_l3_v6_4_fields; /* Trident2 l3 ext ipv6 fields.*/ 36184 static _bcm_l3_intf_fields_t td2_l3_intf_fields; /* L3 intf fields. */ 36185 #endif /* BCM_TRIDENT2_SUPPORT */ 36186 #if defined(BCM_TRIUMPH3_SUPPORT) 36187 static _bcm_l3_hw_calls_t tr3_hw_call[BCM_MAX_NUM_UNITS]; /* Triumph3 hw calls. */ 36188 static _bcm_l3_fields_t tr3_l3_v4_fields; /* Truimph l3 ipv4 fields.*/ 36189 static _bcm_l3_fields_t tr3_l3_v4_2_fields; /* Truimph l3 ext ipv4 fields.*/ 36190 static _bcm_l3_fields_t tr3_l3_v6_fields; /* Truimph l3 ipv6 fields.*/ 36191 static _bcm_l3_fields_t tr3_l3_v6_4_fields; /* Truimph l3 ext ipv6 fields.*/ 36192 static _bcm_l3_fields_t tr3_l3_v4esm_fields; /* Truimph l3 ipv4 esm fields.*/ 36193 static _bcm_l3_fields_t tr3_l3_v4esm_w_fields; /* Truimph l3 ext esm ipv4 fields.*/ 36194 static _bcm_l3_fields_t tr3_l3_v6esm_fields; /* Truimph l3 ipv6 esm fields.*/ 36195 static _bcm_l3_fields_t tr3_l3_v6esm_w_fields; /* Truimph l3 ext esm ipv6 fields.*/ 36196 static _bcm_l3_intf_fields_t tr3_l3_intf_fields; /* L3 intf fields. */ 36197 #endif /* BCM_TRIUMPH3_SUPPORT */ 36198 #if defined(BCM_KATANA2_SUPPORT) 36199 static _bcm_l3_hw_calls_t kt2_hw_call[BCM_MAX_NUM_UNITS]; /* Katana2 hw calls */ 36200 #endif /* BCM_KATANA2_SUPPORT */ 36201 static int hw_call_initialized[BCM_MAX_NUM_UNITS] = {0}; 36202 _bcm_l3_hw_calls_t tmp_hw_call; /* Common hw calls. */ 36203 36204 if (!hw_call_initialized[unit]) { 36205 /* Hw calls pointers. */ 36206 sal_memset(&tmp_hw_call, 0, sizeof(_bcm_l3_hw_calls_t)); 36207 tmp_hw_call.l3_clear_all = _bcm_xgs3_l3_clear_all; 36208 tmp_hw_call.if_get = _bcm_xgs3_l3_intf_get; 36209 tmp_hw_call.if_add = _bcm_xgs3_l3_intf_add; 36210 tmp_hw_call.if_del = _bcm_xgs3_l3_intf_del; 36211 tmp_hw_call.if_tnl_init_get = _bcm_xgs3_l3_intf_tnl_init_get; 36212 tmp_hw_call.if_tnl_init_set = _bcm_xgs3_l3_intf_tnl_init_set; 36213 tmp_hw_call.if_tnl_init_reset = _bcm_xgs3_l3_intf_tnl_init_reset; 36214 tmp_hw_call.nh_get = _bcm_xgs3_nh_get; 36215 tmp_hw_call.nh_del = _bcm_xgs3_nh_del; 36216 tmp_hw_call.nh_update_match = _bcm_xgs3_nh_update_match; 36217 tmp_hw_call.tnl_term_get = _bcm_xgs3_l3_tnl_term_get; 36218 tmp_hw_call.tnl_term_add = _bcm_xgs3_l3_tnl_term_add; 36219 tmp_hw_call.tnl_term_del = _bcm_xgs3_l3_tnl_term_del; 36220 tmp_hw_call.tnl_term_traverse = _bcm_xgs3_l3_tnl_term_traverse; 36221 tmp_hw_call.tnl_init_get = _bcm_xgs3_l3_tnl_init_get; 36222 tmp_hw_call.tnl_init_add = _bcm_xgs3_l3_tnl_init_add; 36223 tmp_hw_call.tnl_init_del = _bcm_xgs3_l3_tnl_init_del; 36224 tmp_hw_call.tnl_dscp_get = _bcm_xgs3_l3_tnl_dscp_get; 36225 tmp_hw_call.tnl_dscp_set = _bcm_xgs3_l3_tnl_dscp_set; 36226 36227 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 36228 defined(BCM_HAWKEYE_SUPPORT) 36229 /* Hw calls pointers. */ 36230 sal_memcpy(&rp_hw_call[unit], &tmp_hw_call, sizeof(_bcm_l3_hw_calls_t)); 36231 rp_hw_call[unit].nh_add = _bcm_fb_nh_add; 36232 rp_hw_call[unit].l3_get = _bcm_rp_l3_get; 36233 rp_hw_call[unit].l3_add = _bcm_rp_l3_add; 36234 rp_hw_call[unit].l3_del = _bcm_rp_l3_del; 36235 rp_hw_call[unit].l3_get_by_idx = _bcm_rp_l3_get_by_idx; 36236 rp_hw_call[unit].l3_traverse = _bcm_xgs3_l3_traverse; 36237 rp_hw_call[unit].l3_del_match = _bcm_xgs3_l3_del_match; 36238 rp_hw_call[unit].lpm_get = _bcm_rp_lpm_get; 36239 rp_hw_call[unit].lpm_add = _bcm_rp_lpm_add; 36240 rp_hw_call[unit].lpm_del = _bcm_rp_lpm_del; 36241 rp_hw_call[unit].lpm_update_match = _bcm_rp_lpm_update_match; 36242 if (soc_feature(unit, soc_feature_fp_routing_mirage)) { 36243 rp_hw_call[unit].ecmp_grp_get = _bcm_xgs3_ecmp_grp_get; 36244 rp_hw_call[unit].ecmp_grp_add = _bcm_xgs3_ecmp_grp_add; 36245 rp_hw_call[unit].ecmp_grp_del = _bcm_xgs3_ecmp_grp_del; 36246 } 36247 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 36248 #ifdef BCM_FIREBOLT_SUPPORT 36249 /* Hw calls pointers. */ 36250 sal_memcpy(&fb_hw_call[unit], &tmp_hw_call, sizeof(_bcm_l3_hw_calls_t)); 36251 fb_hw_call[unit].nh_add = _bcm_fb_nh_add; 36252 fb_hw_call[unit].ecmp_grp_get = _bcm_xgs3_ecmp_grp_get; 36253 fb_hw_call[unit].ecmp_grp_add = _bcm_xgs3_ecmp_grp_add; 36254 fb_hw_call[unit].ecmp_grp_del = _bcm_xgs3_ecmp_grp_del; 36255 fb_hw_call[unit].l3_get = _bcm_xgs3_l3_get; 36256 fb_hw_call[unit].l3_add = _bcm_xgs3_l3_add; 36257 fb_hw_call[unit].l3_del = _bcm_xgs3_l3_del; 36258 fb_hw_call[unit].l3_get_by_idx = _bcm_xgs3_l3_get_by_idx; 36259 fb_hw_call[unit].l3_traverse = _bcm_xgs3_l3_traverse; 36260 fb_hw_call[unit].l3_del_match = _bcm_xgs3_l3_del_match; 36261 fb_hw_call[unit].l3_bucket_get = _bcm_xgs3_l3_bucket_get; 36262 fb_hw_call[unit].ipmc_get = _bcm_fb_l3_ipmc_get; 36263 fb_hw_call[unit].ipmc_add = _bcm_fb_l3_ipmc_add; 36264 fb_hw_call[unit].ipmc_del = _bcm_fb_l3_ipmc_del; 36265 fb_hw_call[unit].ipmc_get_by_idx = _bcm_fb_l3_ipmc_get_by_idx; 36266 fb_hw_call[unit].lpm_get = _bcm_fbx_lpm_get; 36267 fb_hw_call[unit].lpm_add = _bcm_fbx_lpm_add; 36268 fb_hw_call[unit].lpm_del = _bcm_fbx_lpm_del; 36269 fb_hw_call[unit].lpm_update_match = _bcm_fbx_lpm_update_match; 36270 if(!(SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit))) { 36271 fb_hw_call[unit].if_vrf_get = _bcm_fb_l3_intf_vrf_get; 36272 fb_hw_call[unit].if_vrf_bind = _bcm_fb_l3_intf_vrf_bind; 36273 fb_hw_call[unit].if_vrf_unbind = _bcm_fb_l3_intf_vrf_unbind; 36274 } 36275 #if defined(BCM_TRIUMPH_SUPPORT) 36276 sal_memcpy(&tr_hw_call[unit], &fb_hw_call[unit], sizeof(_bcm_l3_hw_calls_t)); 36277 tr_hw_call[unit].ipmc_get = _bcm_tr_l3_ipmc_get; 36278 tr_hw_call[unit].ipmc_add = _bcm_tr_l3_ipmc_add; 36279 tr_hw_call[unit].ipmc_del = _bcm_tr_l3_ipmc_del; 36280 tr_hw_call[unit].ipmc_get_by_idx = _bcm_tr_l3_ipmc_get_by_idx; 36281 tr_hw_call[unit].ing_intf_add = _bcm_tr_l3_ingress_interface_set; 36282 tr_hw_call[unit].ing_intf_del = _bcm_tr_l3_ingress_interface_clr; 36283 tr_hw_call[unit].ing_intf_get = _bcm_tr_l3_ingress_interface_get; 36284 tr_hw_call[unit].ing_intf_update_match = _bcm_xgs3_ing_intf_update_match; 36285 #endif /* BCM_TRIUMPH_SUPPORT */ 36286 #if defined(BCM_TRIUMPH2_SUPPORT) 36287 sal_memcpy(&tr2_hw_call[unit], &tr_hw_call[unit], sizeof(_bcm_l3_hw_calls_t)); 36288 tr2_hw_call[unit].ecmp_grp_get = _bcm_tr2_l3_ecmp_grp_get; 36289 tr2_hw_call[unit].ecmp_grp_add = _bcm_tr2_l3_ecmp_grp_add; 36290 tr2_hw_call[unit].ecmp_grp_del = _bcm_tr2_l3_ecmp_grp_del; 36291 #endif /* BCM_TRIUMPH2_SUPPORT */ 36292 #if defined(BCM_TRIDENT_SUPPORT) 36293 sal_memcpy(&td_hw_call[unit], &tr_hw_call[unit], sizeof(_bcm_l3_hw_calls_t)); 36294 td_hw_call[unit].ecmp_grp_get = _bcm_td_l3_ecmp_grp_get; 36295 td_hw_call[unit].ecmp_grp_add = _bcm_td_l3_ecmp_grp_add; 36296 td_hw_call[unit].ecmp_grp_del = _bcm_td_l3_ecmp_grp_del; 36297 #endif /* BCM_TRIDENT_SUPPORT */ 36298 #if defined(BCM_TRIDENT2_SUPPORT) 36299 sal_memcpy(&td2_hw_call[unit], &td_hw_call[unit], sizeof(_bcm_l3_hw_calls_t)); 36300 td2_hw_call[unit].l3_add = _bcm_td2_l3_add; 36301 td2_hw_call[unit].l3_get = _bcm_td2_l3_get; 36302 td2_hw_call[unit].l3_del = _bcm_td2_l3_del; 36303 td2_hw_call[unit].l3_traverse = _bcm_td2_l3_traverse; 36304 td2_hw_call[unit].l3_del_match = _bcm_td2_l3_del_match; 36305 td2_hw_call[unit].l3_get_by_idx = _bcm_td2_l3_get_by_idx; 36306 36307 td2_hw_call[unit].lpm_get = _bcm_l3_lpm_get; 36308 td2_hw_call[unit].lpm_add = _bcm_l3_lpm_add; 36309 td2_hw_call[unit].lpm_del = _bcm_l3_lpm_del; 36310 td2_hw_call[unit].lpm_update_match = _bcm_l3_lpm_update_match; 36311 36312 #ifdef ALPM_ENABLE 36313 /* If ALPM is enabled */ 36314 if (soc_feature(unit, soc_feature_alpm) && 36315 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 36316 #if defined(BCM_TOMAHAWK_SUPPORT) 36317 if (soc_feature(unit, soc_feature_alpm2)) { 36318 if (SOC_IS_TOMAHAWK3(unit)) { 36319 td2_hw_call[unit].lpm_add = bcm_th3_alpm_add; 36320 td2_hw_call[unit].lpm_get = bcm_th3_alpm_get; 36321 td2_hw_call[unit].lpm_del = bcm_th3_alpm_del; 36322 td2_hw_call[unit].lpm_update_match = 36323 bcm_th3_alpm_update_match; 36324 } else { 36325 td2_hw_call[unit].lpm_add = bcm_th_alpm_add; 36326 td2_hw_call[unit].lpm_get = bcm_th_alpm_get; 36327 td2_hw_call[unit].lpm_del = bcm_th_alpm_del; 36328 td2_hw_call[unit].lpm_update_match = 36329 bcm_th_alpm_update_match; 36330 } 36331 } else 36332 #endif 36333 { 36334 td2_hw_call[unit].lpm_add = _bcm_td2_alpm_add; 36335 td2_hw_call[unit].lpm_get = _bcm_td2_alpm_get; 36336 td2_hw_call[unit].lpm_del = _bcm_td2_alpm_del; 36337 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 36338 td2_hw_call[unit].lpm_update_match = _bcm_td2_alpm_update_match; 36339 } else { 36340 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 36341 td2_hw_call[unit].lpm_update_match = _bcm_th_alpm_update_match; 36342 #endif 36343 } 36344 } 36345 } 36346 #endif 36347 36348 td2_hw_call[unit].ipmc_get = _bcm_td2_l3_ipmc_get; 36349 td2_hw_call[unit].ipmc_add = _bcm_td2_l3_ipmc_add; 36350 td2_hw_call[unit].ipmc_del = _bcm_td2_l3_ipmc_del; 36351 td2_hw_call[unit].ipmc_get_by_idx = _bcm_td2_l3_ipmc_get_by_idx; 36352 36353 td2_hw_call[unit].proxy_nh_add = _bcm_td2_proxy_nh_add; 36354 td2_hw_call[unit].proxy_nh_get = _bcm_td2_proxy_nh_get; 36355 36356 #endif /* BCM_TRIDENT2_SUPPORT */ 36357 #if defined(BCM_TRIUMPH3_SUPPORT) 36358 sal_memcpy(&tr3_hw_call[unit], &td_hw_call[unit], sizeof(_bcm_l3_hw_calls_t)); 36359 tr3_hw_call[unit].l3_add = _bcm_tr3_l3_add; 36360 tr3_hw_call[unit].l3_get = _bcm_tr3_l3_get; 36361 tr3_hw_call[unit].l3_del = _bcm_tr3_l3_del; 36362 tr3_hw_call[unit].l3_traverse = _bcm_tr3_l3_traverse; 36363 tr3_hw_call[unit].l3_del_match = _bcm_tr3_l3_del_match; 36364 tr3_hw_call[unit].l3_get_by_idx = _bcm_tr3_l3_get_by_idx; 36365 tr3_hw_call[unit].ipmc_get = _bcm_tr3_l3_ipmc_get; 36366 tr3_hw_call[unit].ipmc_add = _bcm_tr3_l3_ipmc_add; 36367 tr3_hw_call[unit].ipmc_del = _bcm_tr3_l3_ipmc_del; 36368 tr3_hw_call[unit].ecmp_grp_get = _bcm_tr3_l3_ecmp_grp_get; 36369 tr3_hw_call[unit].ecmp_grp_add = _bcm_tr3_l3_ecmp_grp_add; 36370 tr3_hw_call[unit].ecmp_grp_del = _bcm_tr3_l3_ecmp_grp_del; 36371 tr3_hw_call[unit].lpm_get = _bcm_tr3_l3_lpm_get; 36372 tr3_hw_call[unit].lpm_add = _bcm_tr3_l3_lpm_add; 36373 tr3_hw_call[unit].lpm_del = _bcm_tr3_l3_lpm_del; 36374 tr3_hw_call[unit].lpm_update_match = _bcm_tr3_l3_lpm_update_match; 36375 tr3_hw_call[unit].ipmc_get_by_idx = _bcm_tr3_l3_ipmc_get_by_idx; 36376 tr3_hw_call[unit].nh_update_match = _bcm_tr3_nh_update_match; 36377 #endif /* BCM_TRIUMPH3_SUPPORT */ 36378 #if defined(BCM_KATANA2_SUPPORT) 36379 sal_memcpy(&kt2_hw_call[unit], &td_hw_call[unit], sizeof(_bcm_l3_hw_calls_t)); 36380 kt2_hw_call[unit].lpm_get = _bcm_kt2_l3_lpm_get; 36381 kt2_hw_call[unit].lpm_add = _bcm_kt2_l3_lpm_add; 36382 kt2_hw_call[unit].lpm_del = _bcm_kt2_l3_lpm_del; 36383 kt2_hw_call[unit].lpm_update_match = _bcm_kt2_l3_lpm_update_match; 36384 #endif /* BCM_KATANA2_SUPPORT */ 36385 /* Interface table common fields. */ 36386 fb_l3_intf_fields.vlan_id = VIDf; 36387 fb_l3_intf_fields.mac_addr = MAC_ADDRESSf; 36388 fb_l3_intf_fields.ttl = TTL_THRESHOLDf; 36389 fb_l3_intf_fields.tnl_id = TUNNEL_INDEXf; 36390 fb_l3_intf_fields.l2_switch = L2_SWITCHf; 36391 #if defined(BCM_KATANA2_SUPPORT) 36392 fb_l3_intf_fields.class_id = CLASS_IDf; 36393 #endif /* BCM_KATANA2_SUPPORT */ 36394 36395 /* Next hop table common fields. */ 36396 fb_nh_fields.mac_addr = MAC_ADDRESSf; 36397 fb_nh_fields.module = MODULE_IDf; 36398 fb_nh_fields.port_tgid = PORT_TGIDf; 36399 fb_nh_fields.ifindex = INTF_NUMf; 36400 #if defined(BCM_TRIDENT3_SUPPORT) 36401 fb_nh_fields.dest = DESTINATIONf; 36402 #endif 36403 /* L3 ipv4 table common fields. */ 36404 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 36405 defined(BCM_TRX_SUPPORT) 36406 fb_l3_v4_fields.vrf = VRF_IDf; 36407 #else /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 36408 fb_l3_v4_fields.vrf = INVALIDf; 36409 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */ 36410 fb_l3_v4_fields.hit = HITf; 36411 fb_l3_v4_fields.rpe = RPEf; 36412 fb_l3_v4_fields.dst_discard = DST_DISCARDf; 36413 fb_l3_v4_fields.priority = PRIf; 36414 fb_l3_v4_fields.nh_idx = NEXT_HOP_INDEXf; 36415 #if defined(BCM_TRIDENT3_SUPPORT) 36416 if (SOC_IS_TRIDENT3X(unit)) { 36417 fb_l3_v4_fields.valid = BASE_VALIDf; 36418 } else 36419 #endif 36420 { 36421 fb_l3_v4_fields.valid = VALIDf; 36422 } 36423 fb_l3_v4_fields.l3mc_index = L3MC_INDEXf; 36424 fb_l3_v4_fields.v6_entry = V6f; 36425 fb_l3_v4_fields.ipmc_entry = IPMCf; 36426 fb_l3_v4_fields.vlan_id = VLAN_IDf; 36427 #if defined(BCM_TRX_SUPPORT) 36428 fb_l3_v4_fields.class_id = CLASS_IDf; 36429 #endif /* BCM_TRX_SUPPORT */ 36430 36431 /* L3 ipv6 table common fields. */ 36432 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 36433 defined(BCM_SCORPION_SUPPORT) 36434 fb_l3_v6_fields.vrf = VRF_ID_0f; 36435 #else /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT*/ 36436 fb_l3_v6_fields.vrf = INVALIDf; 36437 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT*/ 36438 fb_l3_v6_fields.hit = HIT_0f; 36439 fb_l3_v6_fields.rpe = RPE_0f; 36440 fb_l3_v6_fields.dst_discard = DST_DISCARD_0f; 36441 fb_l3_v6_fields.priority = PRI_0f; 36442 fb_l3_v6_fields.nh_idx = NEXT_HOP_INDEX_0f; 36443 #if defined(BCM_TRX_SUPPORT) 36444 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 36445 fb_l3_v6_fields.valid = BASE_VALID_0f; 36446 } else 36447 #endif 36448 { 36449 fb_l3_v6_fields.valid = VALID_0f; 36450 } 36451 fb_l3_v6_fields.l3mc_index = L3MC_INDEX_0f; 36452 fb_l3_v6_fields.v6_entry = V6_0f; 36453 fb_l3_v6_fields.ipmc_entry = IPMC_0f; 36454 fb_l3_v6_fields.vlan_id = VLAN_ID_0f; 36455 #if defined(BCM_SCORPION_SUPPORT) 36456 fb_l3_v6_fields.class_id = CLASS_ID_0f; 36457 #endif /* BCM_SCORPION_SUPPORT */ 36458 36459 #endif /* BCM_FIREBOLT_SUPPORT */ 36460 /* Next hop table common fields. */ 36461 #ifdef BCM_TRX_SUPPORT 36462 trx_nh_fields.mac_addr = MAC_ADDRESSf; 36463 trx_nh_fields.module = MODULE_IDf; 36464 trx_nh_fields.port_tgid = PORT_NUMf; 36465 trx_nh_fields.ifindex = INTF_NUMf; 36466 #ifdef BCM_TRIDENT3_SUPPORT 36467 trx_nh_fields.dest = DESTINATIONf; 36468 #endif 36469 #endif /* BCM_TRX_SUPPORT */ 36470 #if defined(BCM_TRIDENT3_SUPPORT) 36471 if (SOC_IS_TRIDENT3X(unit)) { 36472 trx_nh_fields.dest = DESTINATIONf; 36473 trx_nh_fields.mac_addr = L3__MAC_ADDRESSf; 36474 trx_nh_fields.ifindex = L3__INTF_NUMf; 36475 } 36476 #endif 36477 36478 #if defined(BCM_TRIUMPH_SUPPORT) 36479 /* L3 ipv6 table fields. */ 36480 tr_l3_v6_fields.vrf = VRF_IDf; 36481 tr_l3_v6_fields.hit = HIT_0f; 36482 tr_l3_v6_fields.rpe = RPEf; 36483 tr_l3_v6_fields.dst_discard = DST_DISCARDf; 36484 tr_l3_v6_fields.priority = PRIf; 36485 tr_l3_v6_fields.nh_idx = NEXT_HOP_INDEXf; 36486 tr_l3_v6_fields.valid = VALID_0f; 36487 tr_l3_v6_fields.l3mc_index = INVALIDf; 36488 tr_l3_v6_fields.v6_entry = V6_0f; 36489 tr_l3_v6_fields.ipmc_entry = IPMC_0f; 36490 tr_l3_v6_fields.vlan_id = INVALIDf; 36491 tr_l3_v6_fields.class_id = CLASS_IDf; 36492 #endif /* BCM_TRIUMPH_SUPPORT */ 36493 36494 #if defined(BCM_TRIUMPH3_SUPPORT) 36495 /* v4 */ 36496 tr3_l3_v4_fields.vrf = IPV4UC__VRF_IDf; 36497 tr3_l3_v4_fields.rpe = IPV4UC__RPEf; 36498 tr3_l3_v4_fields.dst_discard = IPV4UC__DST_DISCARDf; 36499 tr3_l3_v4_fields.class_id = IPV4UC__CLASS_IDf; 36500 tr3_l3_v4_fields.priority = IPV4UC__PRIf; 36501 tr3_l3_v4_fields.nh_idx = IPV4UC__NEXT_HOP_INDEXf; 36502 tr3_l3_v4_fields.hit = HIT_1f; 36503 tr3_l3_v4_fields.valid = VALIDf; 36504 tr3_l3_v4_fields.ip4 = IPV4UC__IP_ADDRf; 36505 tr3_l3_v4_fields.key_type = KEY_TYPEf; 36506 tr3_l3_v4_fields.local_addr = IPV4UC__LOCAL_ADDRESSf; 36507 /* v4_2 */ 36508 tr3_l3_v4_2_fields.vrf = IPV4UC__VRF_IDf; 36509 tr3_l3_v4_2_fields.rpe = IPV4UC__RPEf; 36510 tr3_l3_v4_2_fields.dst_discard = IPV4UC__DST_DISCARDf; 36511 tr3_l3_v4_2_fields.class_id = IPV4UC__CLASS_IDf; 36512 tr3_l3_v4_2_fields.priority = IPV4UC__PRIf; 36513 tr3_l3_v4_2_fields.l3_intf = IPV4UC__L3_INTF_NUMf; 36514 tr3_l3_v4_2_fields.mac_addr = IPV4UC__MAC_ADDRf; 36515 tr3_l3_v4_2_fields.hit = HIT_1f; 36516 tr3_l3_v4_2_fields.valid = VALID_0f; 36517 tr3_l3_v4_2_fields.ip4 = IPV4UC__IP_ADDRf; 36518 tr3_l3_v4_2_fields.key_type = KEY_TYPE_0f; 36519 tr3_l3_v4_2_fields.l3_oif = IPV4UC__L3_OIFf; 36520 tr3_l3_v4_2_fields.glp = IPV4UC__GLPf; 36521 tr3_l3_v4_2_fields.local_addr = IPV4UC__LOCAL_ADDRESSf; 36522 /* v6 */ 36523 tr3_l3_v6_fields.vrf = IPV6UC__VRF_IDf; 36524 tr3_l3_v6_fields.rpe = IPV6UC__RPEf; 36525 tr3_l3_v6_fields.dst_discard = IPV6UC__DST_DISCARDf; 36526 tr3_l3_v6_fields.class_id = IPV6UC__CLASS_IDf; 36527 tr3_l3_v6_fields.priority = IPV6UC__PRIf; 36528 tr3_l3_v6_fields.nh_idx = IPV6UC__NEXT_HOP_INDEXf; 36529 tr3_l3_v6_fields.mac_addr = IPV6UC__MAC_ADDRf; 36530 tr3_l3_v6_fields.hit = HIT_1f; 36531 tr3_l3_v6_fields.valid = VALID_0f; 36532 tr3_l3_v6_fields.key_type = KEY_TYPE_0f; 36533 tr3_l3_v6_fields.local_addr = IPV6UC__LOCAL_ADDRESSf; 36534 /* v6_4 */ 36535 tr3_l3_v6_4_fields.vrf = IPV6UC__VRF_IDf; 36536 tr3_l3_v6_4_fields.rpe = IPV6UC__RPEf; 36537 tr3_l3_v6_4_fields.l3_intf = IPV6UC__L3_INTF_NUMf; 36538 tr3_l3_v6_4_fields.mac_addr = IPV6UC__MAC_ADDRf; 36539 tr3_l3_v6_4_fields.dst_discard = IPV6UC__DST_DISCARDf; 36540 tr3_l3_v6_4_fields.class_id = IPV6UC__CLASS_IDf; 36541 tr3_l3_v6_4_fields.priority = IPV6UC__PRIf; 36542 tr3_l3_v6_4_fields.hit = HIT_1f; 36543 tr3_l3_v6_4_fields.valid = VALID_0f; 36544 tr3_l3_v6_4_fields.key_type = KEY_TYPE_0f; 36545 tr3_l3_v6_4_fields.l3_oif = IPV6UC__L3_OIFf; 36546 tr3_l3_v6_4_fields.glp = IPV6UC__GLPf; 36547 tr3_l3_v6_4_fields.local_addr = IPV6UC__LOCAL_ADDRESSf; 36548 /* v4_esm */ 36549 tr3_l3_v4esm_fields.vrf = VRF_IDf; 36550 tr3_l3_v4esm_fields.rpe = RPEf; 36551 tr3_l3_v4esm_fields.dst_discard = DST_DISCARDf; 36552 tr3_l3_v4esm_fields.class_id = CLASS_IDf; 36553 tr3_l3_v4esm_fields.priority = PRIf; 36554 tr3_l3_v4esm_fields.nh_idx = NEXT_HOP_INDEXf; 36555 tr3_l3_v4esm_fields.hit = SRC_HITf; 36556 tr3_l3_v4esm_fields.ip4 = IP_ADDRf; 36557 tr3_l3_v4esm_fields.local_addr = LOCAL_ADDRESSf; 36558 /* v4_esm_wide */ 36559 tr3_l3_v4esm_w_fields.vrf = VRF_IDf; 36560 tr3_l3_v4esm_w_fields.rpe = RPEf; 36561 tr3_l3_v4esm_w_fields.dst_discard = DST_DISCARDf; 36562 tr3_l3_v4esm_w_fields.class_id = CLASS_IDf; 36563 tr3_l3_v4esm_w_fields.priority = PRIf; 36564 tr3_l3_v4esm_w_fields.l3_intf = L3_INTF_NUMf; 36565 tr3_l3_v4esm_w_fields.mac_addr = MAC_ADDRf; 36566 tr3_l3_v4esm_w_fields.hit = SRC_HITf; 36567 tr3_l3_v4esm_w_fields.ip4 = IP_ADDRf; 36568 tr3_l3_v4esm_w_fields.l3_oif = L3_OIFf; 36569 tr3_l3_v4esm_w_fields.glp = GLPf; 36570 tr3_l3_v4esm_w_fields.local_addr = LOCAL_ADDRESSf; 36571 /* v6_esm */ 36572 tr3_l3_v6esm_fields.vrf = VRF_IDf; 36573 tr3_l3_v6esm_fields.rpe = RPEf; 36574 tr3_l3_v6esm_fields.dst_discard = DST_DISCARDf; 36575 tr3_l3_v6esm_fields.class_id = CLASS_IDf; 36576 tr3_l3_v6esm_fields.priority = PRIf; 36577 tr3_l3_v6esm_fields.nh_idx = NEXT_HOP_INDEXf; 36578 tr3_l3_v6esm_fields.hit = SRC_HITf; 36579 tr3_l3_v6esm_fields.local_addr = LOCAL_ADDRESSf; 36580 /* v6_esm_wide */ 36581 tr3_l3_v6esm_w_fields.vrf = VRF_IDf; 36582 tr3_l3_v6esm_w_fields.rpe = RPEf; 36583 tr3_l3_v6esm_w_fields.l3_intf = L3_INTF_NUMf; 36584 tr3_l3_v6esm_w_fields.mac_addr = MAC_ADDRf; 36585 tr3_l3_v6esm_w_fields.dst_discard = DST_DISCARDf; 36586 tr3_l3_v6esm_w_fields.class_id = CLASS_IDf; 36587 tr3_l3_v6esm_w_fields.priority = PRIf; 36588 tr3_l3_v6esm_w_fields.hit = SRC_HITf; 36589 tr3_l3_v6esm_w_fields.l3_oif = L3_OIFf; 36590 tr3_l3_v6esm_w_fields.glp = GLPf; 36591 tr3_l3_v6esm_w_fields.local_addr = LOCAL_ADDRESSf; 36592 /* intf fields */ 36593 tr3_l3_intf_fields.vlan_id = VIDf; 36594 tr3_l3_intf_fields.mac_addr = MAC_ADDRESSf; 36595 tr3_l3_intf_fields.ttl = TTL_THRESHOLDf; 36596 tr3_l3_intf_fields.tnl_id = TUNNEL_INDEXf; 36597 tr3_l3_intf_fields.l2_switch = L2_SWITCHf; 36598 tr3_l3_intf_fields.class_id = CLASS_IDf; 36599 36600 #endif /* BCM_TRIUMPH3_SUPPORT */ 36601 #if defined(BCM_TRIDENT2_SUPPORT) 36602 /* v4 */ 36603 td2_l3_v4_fields.vrf = IPV4UC__VRF_IDf; 36604 td2_l3_v4_fields.rpe = IPV4UC__RPEf; 36605 td2_l3_v4_fields.dst_discard = IPV4UC__DST_DISCARDf; 36606 td2_l3_v4_fields.class_id = IPV4UC__CLASS_IDf; 36607 td2_l3_v4_fields.priority = IPV4UC__PRIf; 36608 /* td2_l3_v4_fields.mac_addr = IPV4UC__MAC_ADDRf; */ 36609 td2_l3_v4_fields.nh_idx = IPV4UC__NEXT_HOP_INDEXf; 36610 td2_l3_v4_fields.hit = HITf; 36611 td2_l3_v4_fields.valid = VALIDf; 36612 td2_l3_v4_fields.ip4 = IPV4UC__IP_ADDRf; 36613 td2_l3_v4_fields.key_type = KEY_TYPEf; 36614 td2_l3_v4_fields.local_addr = IPV4UC__LOCAL_ADDRESSf; 36615 #ifdef BCM_MONTEREY_SUPPORT 36616 td2_l3_v4_fields.roe_decap = IPV4UC__ROE_DECAPf; 36617 #endif 36618 /* v4_2 */ 36619 td2_l3_v4_2_fields.vrf = IPV4UC_EXT__VRF_IDf; 36620 td2_l3_v4_2_fields.rpe = RPEf; 36621 td2_l3_v4_2_fields.dst_discard = IPV4UC_EXT__DST_DISCARDf; 36622 td2_l3_v4_2_fields.class_id = IPV4UC_EXT__CLASS_IDf; 36623 td2_l3_v4_2_fields.priority = IPV4UC_EXT__PRIf; 36624 td2_l3_v4_2_fields.l3_intf = IPV4UC_EXT__L3_INTF_NUMf; 36625 td2_l3_v4_2_fields.mac_addr = IPV4UC_EXT__MAC_ADDRf; 36626 td2_l3_v4_2_fields.hit = HIT_1f; 36627 td2_l3_v4_2_fields.valid = VALID_0f; 36628 td2_l3_v4_2_fields.ip4 = IPV4UC_EXT__IP_ADDRf; 36629 td2_l3_v4_2_fields.key_type = KEY_TYPE_0f; 36630 td2_l3_v4_2_fields.glp = IPV4UC_EXT__GLPf; 36631 td2_l3_v4_2_fields.local_addr = IPV4UC_EXT__LOCAL_ADDRESSf; 36632 td2_l3_v4_2_fields.eh_tag_type = IPV4UC_EXT__EH_TAG_TYPEf; 36633 td2_l3_v4_2_fields.eh_queue_tag = IPV4UC_EXT__EH_QUEUE_TAGf; 36634 td2_l3_v4_2_fields.copy_to_cpu = IPV4UC_EXT__COPY_TO_CPUf; 36635 #ifdef BCM_TOMAHAWK_SUPPORT 36636 td2_l3_v4_2_fields.macda_low = IPV4UC_EXT__MAC_DA_LOWf; 36637 td2_l3_v4_2_fields.dst_vif = IPV4UC_EXT__VNTAG_DST_VIFf; 36638 td2_l3_v4_2_fields.oui_profile_id = IPV4UC_EXT__MAC_DA_OUI_PROFILE_IDf; 36639 td2_l3_v4_2_fields.vntag_etag_profile_id = IPV4UC_EXT__VNTAG_ETAG_PROFILE_IDf; 36640 #endif 36641 #ifdef BCM_TRIDENT3_SUPPORT 36642 if (SOC_IS_TRIDENT3X(unit)) { 36643 td2_l3_v4_2_fields.macda_low = IPV4UC_EXT__MACDA_LSBf; 36644 td2_l3_v4_2_fields.dst_vif = IPV4UC_EXT__NIV_DEST_VIFf; 36645 td2_l3_v4_2_fields.oui_profile_id = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf; 36646 td2_l3_v4_2_fields.vntag_etag_profile_id = IPV4UC_EXT__VNTAG_ETAG_PROFILE_IDf; 36647 td2_l3_v4_2_fields.glp = IPV4UC_EXT__DESTINATIONf; 36648 td2_l3_v4_2_fields.key_type = KEY_TYPEf; 36649 } 36650 #endif 36651 #ifdef BCM_MONTEREY_SUPPORT 36652 td2_l3_v4_2_fields.roe_decap = IPV4MC__ROE_DECAPf; 36653 #endif 36654 36655 #ifdef BCM_TRIDENT2PLUS_SUPPORT 36656 td2_l3_v4_2_fields.dest_type = IPV4UC_EXT__DEST_TYPEf; 36657 td2_l3_v4_2_fields.destination = IPV4UC_EXT__DESTINATIONf; 36658 td2_l3_v4_2_fields.macda_lsb = IPV4UC_EXT__MACDA_LSBf; 36659 td2_l3_v4_2_fields.oui_profile_index = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf; 36660 td2_l3_v4_2_fields.oui_profile_valid = IPV4UC_EXT__MACDA_OUI_PROFILE_VALIDf; 36661 #endif 36662 /* v6 */ 36663 td2_l3_v6_fields.vrf = VRF_IDf; 36664 td2_l3_v6_fields.rpe = RPEf; 36665 td2_l3_v6_fields.dst_discard = DST_DISCARDf; 36666 td2_l3_v6_fields.class_id = CLASS_IDf; 36667 td2_l3_v6_fields.priority = PRIf; 36668 td2_l3_v6_fields.nh_idx = NEXT_HOP_INDEXf; 36669 td2_l3_v6_fields.mac_addr = MAC_ADDRf; 36670 td2_l3_v6_fields.hit = HIT_1f; 36671 td2_l3_v6_fields.valid = VALID_0f; 36672 td2_l3_v6_fields.key_type = KEY_TYPE_0f; 36673 td2_l3_v6_fields.local_addr = LOCAL_ADDRESSf; 36674 #ifdef BCM_MONTEREY_SUPPORT 36675 td2_l3_v6_fields.roe_decap = ROE_DECAPf; 36676 #endif 36677 /* v6_4 */ 36678 td2_l3_v6_4_fields.vrf = IPV6UC_EXT__VRF_IDf; 36679 td2_l3_v6_4_fields.rpe = IPV6UC_EXT__RPEf; 36680 td2_l3_v6_4_fields.l3_intf = IPV6UC_EXT__L3_INTF_NUMf; 36681 td2_l3_v6_4_fields.mac_addr = IPV6UC_EXT__MAC_ADDRf; 36682 td2_l3_v6_4_fields.dst_discard = IPV6UC_EXT__DST_DISCARDf; 36683 td2_l3_v6_4_fields.class_id = IPV6UC_EXT__CLASS_IDf; 36684 td2_l3_v6_4_fields.priority = IPV6UC_EXT__PRIf; 36685 td2_l3_v6_4_fields.hit = HIT_1f; 36686 td2_l3_v6_4_fields.valid = VALID_0f; 36687 td2_l3_v6_4_fields.key_type = KEY_TYPE_0f; 36688 td2_l3_v6_4_fields.glp = IPV6UC_EXT__GLPf; 36689 td2_l3_v6_4_fields.local_addr = IPV6UC_EXT__LOCAL_ADDRESSf; 36690 td2_l3_v6_4_fields.eh_tag_type = IPV6UC_EXT__EH_TAG_TYPEf; 36691 td2_l3_v6_4_fields.eh_queue_tag = IPV6UC_EXT__EH_QUEUE_TAGf; 36692 td2_l3_v6_4_fields.copy_to_cpu = IPV6UC_EXT__COPY_TO_CPUf; 36693 #ifdef BCM_TOMAHAWK_SUPPORT 36694 td2_l3_v6_4_fields.macda_low = IPV6UC_EXT__MAC_DA_LOWf; 36695 td2_l3_v6_4_fields.dst_vif = IPV6UC_EXT__VNTAG_DST_VIFf; 36696 td2_l3_v6_4_fields.oui_profile_id = IPV6UC_EXT__MAC_DA_OUI_PROFILE_IDf; 36697 td2_l3_v6_4_fields.vntag_etag_profile_id = IPV6UC_EXT__VNTAG_ETAG_PROFILE_IDf; 36698 #endif 36699 #ifdef BCM_TRIDENT3_SUPPORT 36700 if (SOC_IS_TRIDENT3X(unit)) { 36701 td2_l3_v6_4_fields.macda_low = IPV6UC_EXT__MACDA_LSBf; 36702 td2_l3_v6_4_fields.dst_vif = IPV6UC_EXT__NIV_DEST_VIFf; 36703 td2_l3_v6_4_fields.oui_profile_id = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf; 36704 td2_l3_v6_4_fields.vntag_etag_profile_id = IPV6UC_EXT__VNTAG_ETAG_PROFILE_IDf; 36705 td2_l3_v6_4_fields.glp = IPV6UC_EXT__DESTINATIONf; 36706 td2_l3_v6_4_fields.key_type = KEY_TYPEf; 36707 } 36708 #endif 36709 #ifdef BCM_MONTEREY_SUPPORT 36710 td2_l3_v6_4_fields.roe_decap = IPV6MC__ROE_DECAPf; 36711 #endif 36712 36713 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 36714 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 36715 fb_nh_fields.mac_addr = L3__MAC_ADDRESSf; 36716 fb_nh_fields.ifindex = L3__INTF_NUMf; 36717 td2_l3_v4_fields.valid = BASE_VALIDf; 36718 td2_l3_v4_2_fields.base_valid0 = BASE_VALID_0f; 36719 td2_l3_v4_2_fields.base_valid1 = BASE_VALID_1f; 36720 td2_l3_v4_2_fields.valid = BASE_VALID_0f; 36721 td2_l3_v6_fields.valid = BASE_VALID_0f; 36722 td2_l3_v6_fields.base_valid0 = BASE_VALID_0f; 36723 td2_l3_v6_fields.base_valid1 = BASE_VALID_1f; 36724 td2_l3_v6_4_fields.valid = BASE_VALID_0f; 36725 td2_l3_v6_fields.base_valid0 = BASE_VALID_0f; 36726 td2_l3_v6_fields.base_valid1 = BASE_VALID_1f; 36727 } 36728 36729 if (SOC_IS_TRIDENT3X(unit)) { 36730 td2_l3_v6_fields.vrf = IPV6UC__VRF_IDf; 36731 td2_l3_v4_2_fields.dest = DESTINATIONf; 36732 td2_l3_v4_fields.dest = DESTINATIONf; 36733 td2_l3_v4_2_fields.dest = IPV4UC_EXT__DESTINATIONf; 36734 td2_l3_v6_fields.dest = IPV6UC__DESTINATIONf; 36735 td2_l3_v6_4_fields.dest = IPV6UC_EXT__DESTINATIONf; 36736 td2_l3_v6_fields.rpe = IPV6UC__RPEf; 36737 td2_l3_v6_fields.local_addr = IPV6UC__LOCAL_ADDRESSf; 36738 td2_l3_v6_fields.key_type = KEY_TYPEf; 36739 td2_l3_v6_4_fields.key_type = KEY_TYPEf; 36740 td2_l3_v4_2_fields.key_type = KEY_TYPEf; 36741 td2_l3_v6_fields.class_id = IPV6UC__CLASS_IDf; 36742 td2_l3_v6_fields.priority = IPV6UC__PRIf; 36743 td2_l3_v4_2_fields.class_id = IPV4UC_EXT__CLASS_IDf; 36744 td2_l3_v4_2_fields.priority = IPV4UC_EXT__PRIf; 36745 td2_l3_v6_4_fields.class_id = IPV6UC_EXT__CLASS_IDf; 36746 td2_l3_v6_4_fields.priority = IPV6UC_EXT__PRIf; 36747 td2_l3_v6_fields.dst_discard = IPV6UC__DST_DISCARDf; 36748 } else if (SOC_IS_TOMAHAWK3(unit)) { 36749 td2_l3_v6_fields.vrf = IPV6UC__VRF_IDf; 36750 td2_l3_v6_fields.dest = IPV6UC__DESTINATIONf; 36751 td2_l3_v6_fields.rpe = IPV6UC__RPEf; 36752 td2_l3_v6_fields.local_addr = IPV6UC__LOCAL_ADDRESSf; 36753 td2_l3_v6_fields.key_type = KEY_TYPEf; 36754 td2_l3_v6_4_fields.key_type = KEY_TYPEf; 36755 td2_l3_v4_2_fields.key_type = KEY_TYPEf; 36756 td2_l3_v6_fields.class_id = IPV6UC__CLASS_IDf; 36757 td2_l3_v6_fields.priority = IPV6UC__PRIf; 36758 } 36759 36760 #endif 36761 #ifdef BCM_TRIDENT2PLUS_SUPPORT 36762 td2_l3_v6_4_fields.dest_type = IPV6UC_EXT__DEST_TYPEf; 36763 td2_l3_v6_4_fields.destination = IPV6UC_EXT__DESTINATIONf; 36764 td2_l3_v6_4_fields.macda_lsb = IPV6UC_EXT__MACDA_LSBf; 36765 td2_l3_v6_4_fields.oui_profile_index = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf; 36766 td2_l3_v6_4_fields.oui_profile_valid = IPV6UC_EXT__MACDA_OUI_PROFILE_VALIDf; 36767 #endif 36768 /* intf fields */ 36769 td2_l3_intf_fields.vlan_id = VIDf; 36770 td2_l3_intf_fields.mac_addr = MAC_ADDRESSf; 36771 td2_l3_intf_fields.ttl = TTL_THRESHOLDf; 36772 td2_l3_intf_fields.tnl_id = TUNNEL_INDEXf; 36773 td2_l3_intf_fields.l2_switch = L2_SWITCHf; 36774 td2_l3_intf_fields.class_id = CLASS_IDf; 36775 #endif /* BCM_TRIDENT2_SUPPORT */ 36776 36777 hw_call_initialized[unit] = TRUE; 36778 } 36779 36780 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 36781 #if defined(BCM_TRIDENT3_SUPPORT) 36782 if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) { 36783 if (soc_esw_ecmp_protected_enabled(unit)) { 36784 td2_hw_call[unit].ecmp_grp_get = bcm_td3x_l3_ecmp_protected_grp_get; 36785 td2_hw_call[unit].ecmp_grp_add = bcm_td3x_l3_ecmp_protected_grp_add; 36786 td2_hw_call[unit].ecmp_grp_del = bcm_td3x_l3_ecmp_protected_grp_del; 36787 } else { 36788 td2_hw_call[unit].ecmp_grp_get = _bcm_td_l3_ecmp_grp_get; 36789 td2_hw_call[unit].ecmp_grp_add = _bcm_td_l3_ecmp_grp_add; 36790 td2_hw_call[unit].ecmp_grp_del = _bcm_td_l3_ecmp_grp_del; 36791 } 36792 } 36793 #endif /* BCM_TRIDENT3_SUPPORT */ 36794 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 36795 36796 #ifdef BCM_FIREBOLT_SUPPORT 36797 if (SOC_IS_FBX(unit)) { 36798 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \ 36799 defined(BCM_HAWKEYE_SUPPORT) 36800 if (soc_feature(unit, soc_feature_fp_based_routing)) { 36801 BCM_XGS3_L3_HW_CALL(unit) = &rp_hw_call[unit]; 36802 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&fb_l3_intf_fields; 36803 BCM_XGS3_L3_MEM_FIELDS(unit, nh) = (void *)&fb_nh_fields; 36804 } else 36805 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */ 36806 36807 #ifdef BCM_TRX_SUPPORT 36808 if (SOC_IS_TRX(unit)) { 36809 #ifdef BCM_TRIUMPH2_SUPPORT 36810 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 36811 SOC_IS_VALKYRIE2(unit)){ 36812 BCM_XGS3_L3_HW_CALL(unit) = &tr2_hw_call[unit]; 36813 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&tr_l3_v6_fields; 36814 } else 36815 #endif /* BCM_TRIUMPH2_SUPPORT */ 36816 #ifdef BCM_TRIDENT_SUPPORT 36817 if (SOC_IS_TRIDENT(unit) || SOC_IS_KATANA(unit)) { 36818 BCM_XGS3_L3_HW_CALL(unit) = &td_hw_call[unit]; 36819 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&tr_l3_v6_fields; 36820 } else 36821 #endif 36822 #ifdef BCM_KATANA2_SUPPORT 36823 if (SOC_IS_KATANA2(unit)) { 36824 BCM_XGS3_L3_HW_CALL(unit) = &kt2_hw_call[unit]; 36825 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&tr_l3_v6_fields; 36826 } else 36827 #endif 36828 #ifdef BCM_TRIUMPH_SUPPORT 36829 if (SOC_IS_TR_VL(unit)) { 36830 BCM_XGS3_L3_HW_CALL(unit) = &tr_hw_call[unit]; 36831 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&tr_l3_v6_fields; 36832 } else 36833 #endif /* BCM_TRIUMPH_SUPPORT */ 36834 { 36835 BCM_XGS3_L3_HW_CALL(unit) = &fb_hw_call[unit]; 36836 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&fb_l3_v6_fields; 36837 } 36838 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&fb_l3_intf_fields; 36839 BCM_XGS3_L3_MEM_FIELDS(unit, v4) = (void *)&fb_l3_v4_fields; 36840 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4) = (void *)&fb_l3_v4_fields; 36841 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) = (void *)&fb_l3_v6_fields; 36842 BCM_XGS3_L3_MEM_FIELDS(unit, nh) = (void *)&trx_nh_fields; 36843 #ifdef BCM_TRIUMPH3_SUPPORT 36844 if (SOC_IS_TRIUMPH3(unit)) { 36845 BCM_XGS3_L3_HW_CALL(unit) = &tr3_hw_call[unit]; 36846 BCM_XGS3_L3_MEM_FIELDS(unit, v4) = (void *)&tr3_l3_v4_fields; 36847 BCM_XGS3_L3_MEM_FIELDS(unit, v4_2) = (void *)&tr3_l3_v4_2_fields; 36848 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&tr3_l3_v6_fields; 36849 BCM_XGS3_L3_MEM_FIELDS(unit, v6_4) = (void *)&tr3_l3_v6_4_fields; 36850 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&tr3_l3_intf_fields; 36851 if (soc_feature(unit, soc_feature_esm_support)) { 36852 BCM_XGS3_L3_MEM_FIELDS(unit, v4_esm) = 36853 (void *)&tr3_l3_v4esm_fields; 36854 BCM_XGS3_L3_MEM_FIELDS(unit, v4_esm_wide) = 36855 (void *)&tr3_l3_v4esm_w_fields; 36856 BCM_XGS3_L3_MEM_FIELDS(unit, v6_esm) = 36857 (void *)&tr3_l3_v6esm_fields; 36858 BCM_XGS3_L3_MEM_FIELDS(unit, v6_esm_wide) = 36859 (void *)&tr3_l3_v6esm_w_fields; 36860 } 36861 } 36862 #endif 36863 #ifdef BCM_TRIDENT2_SUPPORT 36864 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || (SOC_IS_TRIDENT3X(unit))) { 36865 BCM_XGS3_L3_HW_CALL(unit) = &td2_hw_call[unit]; 36866 BCM_XGS3_L3_MEM_FIELDS(unit, v4) = (void *)&td2_l3_v4_fields; 36867 BCM_XGS3_L3_MEM_FIELDS(unit, v4_2) = (void *)&td2_l3_v4_2_fields; 36868 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&td2_l3_v6_fields; 36869 BCM_XGS3_L3_MEM_FIELDS(unit, v6_4) = (void *)&td2_l3_v6_4_fields; 36870 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&td2_l3_intf_fields; 36871 } 36872 #endif /* BCM_TRIDENT2_SUPPORT */ 36873 } else 36874 #endif /* BCM_TRX_SUPPORT */ 36875 { 36876 BCM_XGS3_L3_HW_CALL(unit) = &fb_hw_call[unit]; 36877 BCM_XGS3_L3_MEM_FIELDS(unit, nh) = (void *)&fb_nh_fields; 36878 BCM_XGS3_L3_MEM_FIELDS(unit, v6) = (void *)&fb_l3_v6_fields; 36879 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) = (void *)&fb_l3_v6_fields; 36880 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&fb_l3_intf_fields; 36881 BCM_XGS3_L3_MEM_FIELDS(unit, v4) = (void *)&fb_l3_v4_fields; 36882 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4) = (void *)&fb_l3_v4_fields; 36883 } 36884 } 36885 #endif /* BCM_FIREBOLT_SUPPORT */ 36886 return (BCM_E_NONE); 36887 } 36888 36889 /* 36890 * Function: 36891 * _bcm_xgs3_l3_hw_op_init 36892 * Purpose: 36893 * Initialize L3 hardware operations memories & callbacks. 36894 * Parameters: 36895 * unit - SOC unit number. 36896 * Returns: 36897 * BCM_E_XXX 36898 */ 36899 STATIC int 36900 _bcm_xgs3_l3_hw_op_init(int unit) 36901 { 36902 /* Identical memories. */ 36903 /* Ecmp table. */ 36904 if (SOC_MEM_IS_VALID(unit, L3_ECMPm)) { 36905 BCM_XGS3_L3_MEM(unit, ecmp) = L3_ECMPm; 36906 BCM_XGS3_L3_ENT_SZ(unit, ecmp) = 36907 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ecmp)); 36908 } else { 36909 BCM_XGS3_L3_MEM(unit, ecmp) = INVALIDm; 36910 } 36911 36912 if (soc_feature(unit, soc_feature_l3_no_ecmp)) { 36913 BCM_XGS3_L3_MEM(unit, ecmp) = INVALIDm; 36914 } 36915 36916 if (SOC_IS_TRIDENT3X(unit)) { 36917 nh_entry_type_field[unit] = DATA_TYPEf; 36918 } else { 36919 nh_entry_type_field[unit] = ENTRY_TYPEf; 36920 } 36921 36922 BCM_XGS3_L3_MEM(unit, ing_intf) = INVALIDm; 36923 36924 /* Tunnel terminator table. */ 36925 if (SOC_MEM_IS_VALID(unit, L3_TUNNELm)) { 36926 BCM_XGS3_L3_MEM(unit, tnl_term) = L3_TUNNELm; 36927 BCM_XGS3_L3_ENT_SZ(unit, tnl_term) = 36928 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_term)); 36929 } else if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 36930 BCM_XGS3_L3_MEM(unit, tnl_term) = L3_TUNNEL_DOUBLEm; 36931 BCM_XGS3_L3_ENT_SZ(unit, tnl_term) = 36932 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_term)); 36933 } else { 36934 BCM_XGS3_L3_MEM(unit, tnl_term) = INVALIDm; 36935 } 36936 36937 /* Chip specific memories. */ 36938 #ifdef BCM_FIREBOLT_SUPPORT 36939 if (SOC_IS_FBX(unit)) { 36940 /* L3 interface table. */ 36941 BCM_XGS3_L3_MEM(unit, intf) = EGR_L3_INTFm; 36942 BCM_XGS3_L3_ENT_SZ(unit, intf) = 36943 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, intf)); 36944 36945 #if defined(BCM_TRIUMPH_SUPPORT) 36946 /* L3 ingress interface table. */ 36947 if (SOC_MEM_IS_VALID(unit, L3_IIFm)) { 36948 BCM_XGS3_L3_MEM(unit, ing_intf) = L3_IIFm; 36949 BCM_XGS3_L3_ENT_SZ(unit, ing_intf) = 36950 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ing_intf)); 36951 } else { 36952 BCM_XGS3_L3_MEM(unit, ing_intf) = INVALIDm; 36953 } 36954 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */ 36955 36956 /* L3 ipv4 table. */ 36957 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV4_UNICASTm)) { 36958 BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_IPV4_UNICASTm; 36959 BCM_XGS3_L3_ENT_SZ(unit, v4) = 36960 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4)); 36961 } else { 36962 BCM_XGS3_L3_MEM(unit, v4) = INVALIDm; 36963 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 36964 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_SINGLEm)) { 36965 BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_SINGLEm; 36966 BCM_XGS3_L3_ENT_SZ(unit, v4) = 36967 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4)); 36968 } 36969 #endif 36970 36971 } 36972 36973 /* L3 ipv6 table. */ 36974 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_UNICASTm)) { 36975 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_IPV6_UNICASTm; 36976 BCM_XGS3_L3_ENT_SZ(unit, v6) = 36977 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6)); 36978 } else { 36979 BCM_XGS3_L3_MEM(unit, v6) = INVALIDm; 36980 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 36981 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) { 36982 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_DOUBLEm; 36983 BCM_XGS3_L3_ENT_SZ(unit, v6) = 36984 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6)); 36985 } 36986 #endif 36987 } 36988 36989 /* L3 ipv4 ipmc table. */ 36990 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV4_MULTICASTm)) { 36991 BCM_XGS3_L3_MEM(unit, ipmc_v4) = L3_ENTRY_IPV4_MULTICASTm; 36992 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4) = 36993 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4)); 36994 } else { 36995 BCM_XGS3_L3_MEM(unit, ipmc_v4) = INVALIDm; 36996 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 36997 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) { 36998 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_DOUBLEm; 36999 BCM_XGS3_L3_ENT_SZ(unit, v6) = 37000 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6)); 37001 } 37002 #endif 37003 } 37004 37005 /* L3 ipv6 table. */ 37006 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_MULTICASTm)) { 37007 BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_IPV6_MULTICASTm; 37008 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) = 37009 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6)); 37010 } else { 37011 BCM_XGS3_L3_MEM(unit, ipmc_v6) = INVALIDm; 37012 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 37013 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_QUADm)) { 37014 BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_QUADm; 37015 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) = 37016 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6)); 37017 } 37018 #endif 37019 } 37020 37021 /* Defip table. */ 37022 if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) { 37023 BCM_XGS3_L3_MEM(unit, defip) = L3_DEFIPm; 37024 BCM_XGS3_L3_ENT_SZ(unit, defip) = 37025 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, defip)); 37026 } else if (SOC_MEM_IS_VALID(unit, L3_DEFIP_TCAM_LEVEL1m)) { 37027 BCM_XGS3_L3_MEM(unit, defip) = L3_DEFIP_LEVEL1m; 37028 BCM_XGS3_L3_ENT_SZ(unit, defip) = 37029 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, defip)); 37030 } else { 37031 BCM_XGS3_L3_MEM(unit, defip) = INVALIDm; 37032 } 37033 37034 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) 37035 /* IPv6 prefix map table. */ 37036 if (SOC_MEM_IS_VALID(unit, IPV4_IN_IPV6_PREFIX_MATCH_TABLEm)) { 37037 BCM_XGS3_L3_MEM(unit, v6_prefix_map) = 37038 IPV4_IN_IPV6_PREFIX_MATCH_TABLEm; 37039 BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map) = 37040 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_prefix_map)); 37041 } else if (SOC_MEM_IS_VALID(unit, PARSER1_IPV4_IN_IPV6_PREFIX_MATCH_TABLEm)) { 37042 BCM_XGS3_L3_MEM(unit, v6_prefix_map) = 37043 PARSER1_IPV4_IN_IPV6_PREFIX_MATCH_TABLEm; 37044 BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map) = 37045 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_prefix_map)); 37046 } else 37047 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */ 37048 { 37049 BCM_XGS3_L3_MEM(unit, v6_prefix_map) = INVALIDm; 37050 } 37051 37052 /* IPv4 Tunnel initiator table. */ 37053 if (SOC_MEM_IS_VALID(unit, EGR_IP_TUNNELm)) { 37054 BCM_XGS3_L3_MEM(unit, tnl_init_v4) = EGR_IP_TUNNELm; 37055 BCM_XGS3_L3_ENT_SZ(unit, tnl_init_v4) = 37056 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_init_v4)); 37057 } else { 37058 BCM_XGS3_L3_MEM(unit, tnl_init_v4) = INVALIDm; 37059 } 37060 #if defined(BCM_TRX_SUPPORT) 37061 /* IPv6 Tunnel initiator table. */ 37062 if (SOC_MEM_IS_VALID(unit, EGR_IP_TUNNEL_IPV6m)) { 37063 BCM_XGS3_L3_MEM(unit, tnl_init_v6) = EGR_IP_TUNNEL_IPV6m; 37064 BCM_XGS3_L3_ENT_SZ(unit, tnl_init_v6) = 37065 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_init_v6)); 37066 } else 37067 #endif /* BCM_TRX_SUPPORT */ 37068 { 37069 BCM_XGS3_L3_MEM(unit, tnl_init_v6) = INVALIDm; 37070 } 37071 37072 #if defined(BCM_TRX_SUPPORT) 37073 /* MPLS Tunnel initiator table. */ 37074 if (SOC_MEM_IS_VALID(unit, EGR_IP_TUNNEL_MPLSm)) { 37075 if (SOC_IS_TRIDENT3X(unit)) { 37076 BCM_XGS3_L3_MEM(unit, tnl_init_mpls) = 37077 EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm; 37078 } else { 37079 BCM_XGS3_L3_MEM(unit, tnl_init_mpls) = 37080 EGR_IP_TUNNEL_MPLSm; 37081 } 37082 BCM_XGS3_L3_ENT_SZ(unit, tnl_init_mpls) = 37083 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_init_mpls)); 37084 } else 37085 #endif /* BCM_TRX_SUPPORT */ 37086 { 37087 BCM_XGS3_L3_MEM(unit, tnl_init_mpls) = INVALIDm; 37088 } 37089 37090 /* Next hop table. */ 37091 BCM_XGS3_L3_MEM(unit, nh) = ING_L3_NEXT_HOPm; 37092 BCM_XGS3_L3_ENT_SZ(unit, nh) = 37093 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, nh)); 37094 37095 /* Egress Tunnel DSCP table. */ 37096 if (SOC_IS_TRIDENT3X(unit)) { 37097 BCM_XGS3_L3_MEM(unit, tnl_dscp) = EGR_ZONE_2_QOS_MAPPING_TABLEm; 37098 } else { 37099 BCM_XGS3_L3_MEM(unit, tnl_dscp) = EGR_DSCP_TABLEm; 37100 } 37101 37102 BCM_XGS3_L3_ENT_SZ(unit, tnl_dscp) = 37103 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_dscp)); 37104 #ifdef BCM_TRIUMPH3_SUPPORT 37105 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_1m) && 37106 SOC_MEM_IS_VALID(unit, L3_ENTRY_2m)) { 37107 BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_1m; 37108 BCM_XGS3_L3_ENT_SZ(unit, v4) = 37109 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4)); 37110 BCM_XGS3_L3_MEM(unit, v4_2) = L3_ENTRY_2m; 37111 BCM_XGS3_L3_ENT_SZ(unit, v4_2) = 37112 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_2)); 37113 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_2m; 37114 BCM_XGS3_L3_ENT_SZ(unit, v6) = 37115 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6)); 37116 BCM_XGS3_L3_MEM(unit, v6_4) = L3_ENTRY_4m; 37117 BCM_XGS3_L3_ENT_SZ(unit, v6_4) = 37118 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_4)); 37119 BCM_XGS3_L3_MEM(unit, ipmc_v4) = L3_ENTRY_2m; 37120 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4) = 37121 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4)); 37122 BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_4m; 37123 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) = 37124 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6)); 37125 } 37126 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 37127 else if (SOC_MEM_IS_VALID(unit, L3_ENTRY_SINGLEm)) { 37128 BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_SINGLEm; 37129 BCM_XGS3_L3_ENT_SZ(unit, v4) = 37130 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4)); 37131 BCM_XGS3_L3_MEM(unit, v4_2) = L3_ENTRY_DOUBLEm; 37132 BCM_XGS3_L3_ENT_SZ(unit, v4_2) = 37133 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_2)); 37134 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_DOUBLEm; 37135 BCM_XGS3_L3_ENT_SZ(unit, v6) = 37136 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6)); 37137 BCM_XGS3_L3_MEM(unit, v6_4) = L3_ENTRY_QUADm; 37138 BCM_XGS3_L3_ENT_SZ(unit, v6_4) = 37139 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_4)); 37140 BCM_XGS3_L3_MEM(unit, ipmc_v4) = L3_ENTRY_DOUBLEm; 37141 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4) = 37142 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4)); 37143 BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_QUADm; 37144 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) = 37145 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6)); 37146 } 37147 #endif 37148 37149 if (SOC_MEM_IS_VALID(unit, EXT_IPV4_UCAST_WIDEm) && 37150 SOC_MEM_IS_VALID(unit, EXT_IPV6_128_UCAST_WIDEm)) { 37151 BCM_XGS3_L3_MEM(unit, v4_esm) = EXT_IPV4_UCASTm; 37152 BCM_XGS3_L3_ENT_SZ(unit, v4_esm) = 37153 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_esm)); 37154 BCM_XGS3_L3_MEM(unit, v4_esm_wide) = EXT_IPV4_UCAST_WIDEm; 37155 BCM_XGS3_L3_ENT_SZ(unit, v4_esm_wide) = 37156 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_esm_wide)); 37157 BCM_XGS3_L3_MEM(unit, v6_esm) = EXT_IPV6_128_UCASTm; 37158 BCM_XGS3_L3_ENT_SZ(unit, v6_esm) = 37159 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_esm)); 37160 BCM_XGS3_L3_MEM(unit, v6_esm_wide) = EXT_IPV6_128_UCAST_WIDEm; 37161 BCM_XGS3_L3_ENT_SZ(unit, v6_esm_wide) = 37162 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_esm_wide)); 37163 } 37164 #endif 37165 #ifdef BCM_TRIDENT2_SUPPORT 37166 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV4_MULTICASTm)) { 37167 BCM_XGS3_L3_MEM(unit, v4_2) = L3_ENTRY_IPV4_MULTICASTm; 37168 BCM_XGS3_L3_ENT_SZ(unit, v4_2) = 37169 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_2)); 37170 } 37171 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_MULTICASTm)) { 37172 BCM_XGS3_L3_MEM(unit, v6_4) = L3_ENTRY_IPV6_MULTICASTm; 37173 BCM_XGS3_L3_ENT_SZ(unit, v6_4) = 37174 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_4)); 37175 } 37176 #endif 37177 #ifdef BCM_HURRICANE3_SUPPORT 37178 if (soc_feature(unit, soc_feature_miml_no_l3)) { 37179 /* 37180 * Buckhound doesn't support L3 feature but MiML reuses some L3 functions 37181 * for resource management. 37182 */ 37183 /* To set all L3 memories as INVALIDm except for intf and nh for MiML usage */ 37184 BCM_XGS3_L3_MEM(unit, ecmp) = INVALIDm; 37185 BCM_XGS3_L3_MEM(unit, ing_intf) = INVALIDm; 37186 BCM_XGS3_L3_MEM(unit, tnl_term) = INVALIDm; 37187 BCM_XGS3_L3_MEM(unit, v4) = INVALIDm; 37188 BCM_XGS3_L3_MEM(unit, v6) = INVALIDm; 37189 BCM_XGS3_L3_MEM(unit, ipmc_v4) = INVALIDm; 37190 BCM_XGS3_L3_MEM(unit, ipmc_v6) = INVALIDm; 37191 BCM_XGS3_L3_MEM(unit, defip) = INVALIDm; 37192 BCM_XGS3_L3_MEM(unit, v6_prefix_map) = INVALIDm; 37193 BCM_XGS3_L3_MEM(unit, tnl_init_v4) = INVALIDm; 37194 BCM_XGS3_L3_MEM(unit, tnl_init_v6) = INVALIDm; 37195 BCM_XGS3_L3_MEM(unit, tnl_init_mpls) = INVALIDm; 37196 BCM_XGS3_L3_MEM(unit, tnl_dscp) = INVALIDm; 37197 } 37198 #endif /* BCM_HURRICANE3_SUPPORT */ 37199 } 37200 #endif /* BCM_FIREBOLT_SUPPORT */ 37201 _bcm_xgs3_l3_hw_call_init(unit); 37202 return (BCM_E_NONE); 37203 } 37204 37205 void dump_ecmp_info(int unit) 37206 { 37207 _bcm_l3_tbl_t *tbl_ptr; 37208 _bcm_l3_ecmp_info_t *ptr; 37209 37210 int idx = 0; 37211 int member_count = 0; 37212 int rv; 37213 37214 LOG_CLI((BSL_META_U(unit, 37215 "Dumping ecmp_info\n"))); 37216 ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_info); 37217 if (ptr) { 37218 LOG_CLI((BSL_META_U(unit, 37219 "ecmp_max_paths - %d ecmp_inuse - %d\n"), 37220 ptr->ecmp_max_paths, ptr->ecmp_inuse)); 37221 } 37222 37223 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 37224 if (tbl_ptr) { 37225 LOG_CLI((BSL_META_U(unit, 37226 "ECMP GROUP INFO:\n"))); 37227 LOG_CLI((BSL_META_U(unit, 37228 "idx_min: %d idx_max: %d idx_maxused: %d\n"), 37229 tbl_ptr->idx_min, tbl_ptr->idx_max, 37230 tbl_ptr->idx_maxused)); 37231 LOG_CLI((BSL_META_U(unit, 37232 "HASH and REFCOUNT for each ECMP GROUP\n"))); 37233 37234 for (idx = tbl_ptr->idx_min; idx < tbl_ptr->idx_max; idx++) { 37235 if (tbl_ptr->ext_arr[idx].ref_count != 0) { 37236 LOG_CLI((BSL_META_U(unit, 37237 "[idx: %d ref: %d, hash: %d],"), idx, 37238 tbl_ptr->ext_arr[idx].ref_count, 37239 tbl_ptr->ext_arr[idx].data_hash)); 37240 if (idx % 4 == 0) { 37241 LOG_CLI((BSL_META_U(unit, 37242 "\n"))); 37243 } 37244 } 37245 } 37246 } 37247 37248 LOG_CLI((BSL_META_U(unit, 37249 "\nECMP GROUP MEMBER COUNT INFO:\n"))); 37250 for (idx = tbl_ptr->idx_min; idx < tbl_ptr->idx_maxused; idx++) { 37251 rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &member_count); 37252 LOG_CLI((BSL_META_U(unit, 37253 "groud id - %d count - %d rv - %d\n"), 37254 idx, member_count, rv)); 37255 } 37256 37257 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 37258 if (tbl_ptr) { 37259 LOG_CLI((BSL_META_U(unit, 37260 "\nECMP INFO:\n"))); 37261 LOG_CLI((BSL_META_U(unit, 37262 "idx_min: %d idx_max: %d idx_maxused: %d\n"), 37263 tbl_ptr->idx_min, tbl_ptr->idx_max, 37264 tbl_ptr->idx_maxused)); 37265 LOG_CLI((BSL_META_U(unit, 37266 "HASH and REFCOUNT for each ECMP \n"))); 37267 37268 for (idx = tbl_ptr->idx_min; idx < tbl_ptr->idx_max; idx++) { 37269 if (tbl_ptr->ext_arr[idx].ref_count != 0) { 37270 LOG_CLI((BSL_META_U(unit, 37271 "[idx: %d ref: %d, hash: %d],"), idx, 37272 tbl_ptr->ext_arr[idx].ref_count, 37273 tbl_ptr->ext_arr[idx].data_hash)); 37274 if (idx % 4 == 0) { 37275 LOG_CLI((BSL_META_U(unit, 37276 "\n"))); 37277 } 37278 } 37279 } 37280 } 37281 LOG_CLI((BSL_META_U(unit, 37282 "\n"))); 37283 } 37284 37285 int 37286 _bcm_xgs3_route_tables_resize(int unit, int arg) 37287 { 37288 int rv = BCM_E_NONE; 37289 #if defined(BCM_TRIUMPH3_SUPPORT) 37290 int cache_on = 0; 37291 #endif 37292 #ifdef ALPM_ENABLE 37293 #if defined(BCM_TOMAHAWK_SUPPORT) 37294 int hitbit_interval = 0; 37295 #endif 37296 #endif 37297 soc_mem_t defip_mem = L3_DEFIPm, defip_pair_mem = L3_DEFIP_PAIR_128m; 37298 37299 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 37300 defip_mem = L3_DEFIP_LEVEL1m; 37301 defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m; 37302 } 37303 37304 if (soc_feature(unit, soc_feature_l3_shared_defip_table)) { 37305 if (!(SOC_IS_TD2_TT2(unit) || SOC_IS_TRIUMPH3(unit))) { 37306 return BCM_E_UNAVAIL; 37307 } 37308 } else { 37309 return BCM_E_UNAVAIL; 37310 } 37311 37312 #ifdef ALPM_ENABLE 37313 #if defined(BCM_TOMAHAWK_SUPPORT) 37314 if (soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) && 37315 soc_feature(unit, soc_feature_alpm2) && ALPMC(unit) && !ALPM_HIT_SKIP(unit)) { 37316 hitbit_interval = alpm_dist_hitbit_interval_get(unit); 37317 if (hitbit_interval) { 37318 alpm_dist_hitbit_enable_set(unit, 0); 37319 } 37320 } 37321 #endif 37322 #endif 37323 /* State changed -> Delete all the routes. */ 37324 if (!(SOC_IS_TRIDENT3X(unit)) || (SOC_IS_TRIDENT3X(unit) && 37325 (BCM_XGS3_L3_INITIALIZED(unit)))) { 37326 BCM_IF_ERROR_RETURN(bcm_xgs3_defip_del_all(unit)); 37327 } 37328 37329 /* Destroy Hash/Avl quick lookup structure. */ 37330 BCM_IF_ERROR_RETURN(bcm_xgs3_l3_fbx_defip_deinit(unit)); 37331 37332 /* Lock the DEFIP tables so the SOC TCAM scanning logic doesn't 37333 * trip up on the URPF reconfiguration. 37334 */ 37335 soc_mem_lock(unit, defip_mem); 37336 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37337 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37338 soc_mem_lock(unit, defip_pair_mem); 37339 } 37340 } 37341 37342 /* resize the DEFIP table */ 37343 rv = soc_defip_tables_resize(unit, arg); 37344 if (BCM_FAILURE(rv)) { 37345 /* Must release the locks before return. */ 37346 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37347 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37348 soc_mem_unlock(unit, defip_pair_mem); 37349 } 37350 } 37351 soc_mem_unlock(unit, defip_mem); 37352 return rv; 37353 } 37354 37355 /* reallocate DEFIP table cache memory (cache and vmap) as per 37356 * calculated new indexes - TD2 it is disabled since cache is 37357 * not enabled for TD2. It is only enabled for TR3 37358 */ 37359 #if defined(BCM_TRIUMPH3_SUPPORT) 37360 if (SOC_IS_TRIUMPH3(unit)) { 37361 cache_on = 1; 37362 } else if (SOC_IS_TD2_TT2(unit)) { 37363 cache_on = soc_mem_cache_get(unit, defip_mem, MEM_BLOCK_ALL); 37364 } 37365 37366 if (cache_on) { 37367 if (SOC_MEM_IS_ENABLED(unit, defip_mem)) { 37368 if (BCM_SUCCESS(rv)) { 37369 rv = soc_mem_cache_set(unit, defip_mem, MEM_BLOCK_ALL, TRUE); 37370 } 37371 } 37372 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37373 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37374 if (BCM_SUCCESS(rv)) { 37375 rv = soc_mem_cache_set(unit, defip_pair_mem, 37376 MEM_BLOCK_ALL, TRUE); 37377 } 37378 } 37379 } 37380 } 37381 #endif 37382 37383 37384 /* Clear h/w memory before use */ 37385 if (SOC_MEM_IS_ENABLED(unit, defip_mem)) { 37386 if (BCM_SUCCESS(rv)) { 37387 rv = soc_mem_clear(unit, defip_mem, MEM_BLOCK_ALL, 0); 37388 } 37389 } 37390 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37391 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37392 if (BCM_SUCCESS(rv)) { 37393 rv = soc_mem_clear(unit, defip_pair_mem, 37394 MEM_BLOCK_ALL, 0); 37395 if (BCM_FAILURE(rv)) { 37396 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37397 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37398 soc_mem_unlock(unit, defip_pair_mem); 37399 } 37400 } 37401 soc_mem_unlock(unit, defip_mem); 37402 return rv; 37403 } 37404 } 37405 } 37406 } 37407 37408 /* Reinit Hash/Avl quick lookup structure. */ 37409 rv = bcm_xgs3_l3_fbx_defip_init(unit); 37410 if (BCM_FAILURE(rv)) { 37411 /* Must release the locks before return. */ 37412 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37413 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37414 soc_mem_unlock(unit, defip_pair_mem); 37415 } 37416 } 37417 soc_mem_unlock(unit, defip_mem); 37418 return rv; 37419 } 37420 37421 /* Now check if urpf is enable */ 37422 if (SOC_URPF_STATUS_GET(unit)) { 37423 #ifdef BCM_TRIUMPH3_SUPPORT 37424 if (SOC_IS_TRIUMPH3(unit) && 37425 !BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) { 37426 rv = _bcm_tr3_l3_defip_urpf_enable(unit, 1); 37427 } 37428 #endif 37429 37430 #ifdef BCM_TRIDENT2_SUPPORT 37431 if (BCM_SUCCESS(rv) && (SOC_IS_TRIDENT2X(unit) || 37432 SOC_IS_TOMAHAWKX(unit) || 37433 SOC_IS_TRIDENT3X(unit))) { 37434 /* BCM_SUCCESS test not needed, but likely to avoid 37435 * Coverity complaints */ 37436 rv = _bcm_l3_defip_urpf_enable(unit, 1); 37437 } 37438 #endif 37439 37440 } 37441 37442 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 37443 soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)); 37444 37445 /* Must release the locks before return. */ 37446 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 37447 if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) { 37448 soc_mem_unlock(unit, defip_pair_mem); 37449 } 37450 } 37451 soc_mem_unlock(unit, defip_mem); 37452 #ifdef ALPM_ENABLE 37453 #if defined(BCM_TOMAHAWK_SUPPORT) 37454 if (soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) && 37455 soc_feature(unit, soc_feature_alpm2) && ALPMC(unit) && !ALPM_HIT_SKIP(unit)) { 37456 if (hitbit_interval) { 37457 alpm_dist_hitbit_enable_set(unit, hitbit_interval); 37458 } 37459 } 37460 #endif 37461 #endif 37462 return rv; 37463 } 37464 37465 int 37466 _bcm_fb_lpm_defip_cfg_get(int unit, int ipv6, void *defip_lpm_entry, 37467 _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 37468 { 37469 int idx = 0; /* ipv4 entries iterator.*/ 37470 uint32 lpm_entry[SOC_MAX_MEM_WORDS]; 37471 37472 if (lpm_cfg == NULL || defip_lpm_entry == NULL) { 37473 return BCM_E_PARAM; 37474 } 37475 sal_memcpy(&lpm_entry, defip_lpm_entry, 37476 BCM_XGS3_L3_ENT_SZ(unit, defip)); 37477 37478 for (idx = 0; idx < (ipv6 ? 1 : 2); idx++) { 37479 if (idx) { 37480 /* Check second part of the entry. */ 37481 soc_fb_lpm_ip4entry1_to_0(unit, (void*)lpm_entry, 37482 (void*)lpm_entry, TRUE); 37483 } 37484 /* Parse the entry. */ 37485 BCM_IF_ERROR_RETURN( 37486 _bcm_fb_lpm_ent_parse(unit, &lpm_cfg[idx], &nh_ecmp_idx[idx], 37487 (uint32 *)lpm_entry, NULL)); 37488 BCM_IF_ERROR_RETURN( 37489 _bcm_fb_lpm_ent_get_key(unit, &lpm_cfg[idx], (uint32 *)lpm_entry)); 37490 } 37491 lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX; 37492 return SOC_E_NONE; 37493 } 37494 37495 /* 37496 * Function: 37497 * bcmi_l3_egress_multi_alloc 37498 * Purpose: 37499 * Allocates multiple egress objects. 37500 * Parameters: 37501 * unit - (IN)SOC unit number. 37502 * info - (IN)Info to allocates egress objects. 37503 * base_egress_id - (OUT) base egress object id. 37504 * Returns: 37505 * BCM_E_XXX 37506 */ 37507 int 37508 bcmi_l3_egress_multi_alloc(int unit, 37509 bcm_l3_egress_multi_info_t info, 37510 bcm_if_t *base_egress_id) 37511 { 37512 int rv = BCM_E_NONE; 37513 uint32 flags = 0; 37514 uint32 *nh_multi_count; 37515 _bcm_l3_tbl_op_t data; /* Operation data. */ 37516 bcm_l3_egress_t nh_info; 37517 _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */ 37518 int backup_min_index; 37519 ing_l3_next_hop_entry_t ing_nh; 37520 int i = 0; 37521 bcm_if_t nh_index = 0; 37522 37523 if ((info.number_of_elements < 1) || 37524 (info.number_of_elements > 4)) { 37525 return BCM_E_PARAM; 37526 } 37527 if (base_egress_id == NULL) { 37528 return BCM_E_PARAM; 37529 } 37530 37531 if (!(soc_feature(unit, soc_feature_hierarchical_protection))) { 37532 return BCM_E_UNAVAIL; 37533 } else { 37534 /* 37535 * Currently settingnumber of elements to 4. 37536 * in future if someone wants to extend this API, 37537 * then they may have to send some flag/source in 37538 * info structure and based on that allocate number of 37539 * elements. 37540 */ 37541 info.number_of_elements = _BCM_QUAD_WIDE; 37542 } 37543 37544 if (info.flags & BCM_L3_EGRESS_MULTI_WITH_ID) { 37545 if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, *base_egress_id)) { 37546 nh_index = *base_egress_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 37547 } else { 37548 nh_index = *base_egress_id - BCM_XGS3_EGRESS_IDX_MIN(unit); 37549 } 37550 37551 flags |= _BCM_L3_SHR_WITH_ID; 37552 } 37553 37554 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 37555 sal_memset(&nh_info, 0, sizeof(bcm_l3_egress_t)); 37556 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 37557 data.width = info.number_of_elements; 37558 data.oper_flags = flags | _BCM_L3_SHR_MATCH_DISABLE | 37559 _BCM_L3_SHR_WRITE_DISABLE; 37560 data.entry_buffer = (void *)(&(nh_info)); 37561 data.hash_func = _bcm_xgs3_nh_hash_calc; 37562 data.cmp_func = _bcm_xgs3_nh_ent_cmp; 37563 data.add_func = BCM_XGS3_L3_HWCALL(unit, nh_add); 37564 if (flags & _BCM_L3_SHR_WITH_ID) { 37565 data.entry_index = nh_index; 37566 } 37567 tbl_ptr = data.tbl_ptr; 37568 /* Set up the limits for indexes */ 37569 backup_min_index = tbl_ptr->idx_min; 37570 tbl_ptr->idx_min = 4; 37571 37572 37573 rv = _bcm_xgs3_tbl_add(unit, &data); 37574 if (rv != BCM_E_NONE) { 37575 tbl_ptr->idx_min = backup_min_index; 37576 return rv; 37577 } 37578 37579 *base_egress_id = data.entry_index + BCM_XGS3_EGRESS_IDX_MIN(unit); 37580 tbl_ptr->idx_min = backup_min_index; 37581 /* set up s/w state for 2-level protection */ 37582 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 37583 nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit); 37584 nh_multi_count[data.entry_index] = _BCM_QUAD_WIDE; 37585 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, 1); 37586 for (i=0; i<info.number_of_elements; i++) { 37587 rv = soc_mem_write (unit, ING_L3_NEXT_HOPm, 37588 MEM_BLOCK_ALL, data.entry_index + i, &ing_nh); 37589 if (BCM_FAILURE(rv)) { 37590 return rv; 37591 } 37592 } 37593 } 37594 return BCM_E_NONE; 37595 } 37596 37597 /* 37598 * Function: 37599 * bcmi_l3_egress_multi_free 37600 * Purpose: 37601 * Frees multiple egress objects. 37602 * Parameters: 37603 * unit - (IN)SOC unit number. 37604 * base_egress_id - (OUT) base egress object id. 37605 * Returns: 37606 * BCM_E_XXX 37607 */ 37608 int 37609 bcmi_l3_egress_multi_free(int unit, bcm_if_t base_egress_id) 37610 { 37611 37612 _bcm_l3_tbl_op_t data; /* Operation data. */ 37613 int no_of_elements = 1; /* by default set it to 1 */ 37614 uint32 *nh_multi_count; 37615 bcm_if_t base_nh_id; 37616 int i = 0; 37617 37618 /* Make sure module was initialized. */ 37619 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 37620 return (BCM_E_INIT); 37621 } 37622 37623 /* Input parameters check. */ 37624 if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, base_egress_id) && 37625 !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, base_egress_id)) { 37626 return (BCM_E_PARAM); 37627 } 37628 37629 /* Calculate next hop index. */ 37630 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, base_egress_id)) { 37631 base_nh_id = base_egress_id - BCM_XGS3_EGRESS_IDX_MIN(unit); 37632 } else { 37633 base_nh_id = base_egress_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 37634 } 37635 37636 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 37637 nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit); 37638 no_of_elements = nh_multi_count[base_nh_id];; 37639 } 37640 no_of_elements = ((no_of_elements > 1)? no_of_elements : 1); 37641 37642 /* Make sure hw call is registred. */ 37643 if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_del)) { 37644 return (BCM_E_UNAVAIL); 37645 } 37646 37647 /* Initialization */ 37648 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 37649 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 37650 data.width = _BCM_SINGLE_WIDE; 37651 /* data.oper_flags = flags;*/ 37652 data.delete_func = BCM_XGS3_L3_HWCALL(unit, nh_del); 37653 37654 for (; i < no_of_elements; i++) { 37655 37656 data.entry_index = base_nh_id + i; 37657 37658 /* Delete next hop table entry. */ 37659 if (BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, base_nh_id + i) == 1) { 37660 BCM_XGS3_L3_NH_CNT(unit)--; 37661 } 37662 37663 /* Delete next hop table entry. */ 37664 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_del(unit, &data)); 37665 } 37666 37667 return BCM_E_NONE; 37668 } 37669 37670 /* 37671 * Function: 37672 * bcmi_l3_nh_multi_count_get 37673 * Purpose: 37674 * get number of nexthop allocated at this index.. 37675 * Parameters: 37676 * unit - (IN)SOC unit number. 37677 * base_egress_id - (OUT) base egress object id. 37678 * Returns: 37679 * int 37680 */ 37681 int 37682 bcmi_l3_nh_multi_count_get(int unit, bcm_if_t nh_index) 37683 { 37684 uint32 *nh_multi_count; 37685 37686 if (nh_index < 1) { 37687 return 0; 37688 } 37689 37690 if (soc_feature(unit, soc_feature_hierarchical_protection)) { 37691 nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit); 37692 return nh_multi_count[nh_index];; 37693 } 37694 37695 return 0; 37696 } 37697 37698 #endif /* BCM_FIREBOLT_SUPPORT */ 37699 37700 #ifdef BCM_TRIDENT3_SUPPORT 37701 /* Internal function to check the validity of overlay interface id range */ 37702 37703 STATIC int 37704 _bcmi_l3_intf_overlay_valid(int unit, _bcm_l3_intf_cfg_t *intf_info) 37705 { 37706 int min_idx, max_idx; 37707 _bcm_l3_bookkeeping_t *l3_bk = L3_INFO(unit); 37708 37709 if (BCMI_L3_INTF_OVERLAY_VALID(unit)) { 37710 if (l3_bk->l3_intf_overlay_alloc_mode > 0) { 37711 min_idx = BCM_XGS3_L3_IF_TBL_SIZE(unit) - 37712 l3_bk->l3_intf_overlay_entries; 37713 max_idx = BCM_XGS3_L3_IF_TBL_SIZE(unit) - 1; 37714 } else { 37715 min_idx = 0; 37716 max_idx = l3_bk->l3_intf_overlay_entries -1; 37717 } 37718 if ((intf_info->l3i_index >= min_idx) && 37719 (intf_info->l3i_index <= max_idx)) { 37720 return BCM_E_NONE; 37721 } 37722 } 37723 return BCM_E_PARAM; 37724 } 37725 37726 /* 37727 * Function: 37728 * bcmi_l3_intf_vpn_set 37729 * Purpose: 37730 * Set the VPN on a given L3 Egress interface. 37731 * 37732 * Parameters: 37733 * unit - (IN) Unit number. 37734 * l3_intf_id - (IN) Interface ID of an egress L3 object 37735 * bcm_vpn_t - (IN) VPN_ID that needs to be set on this interface 37736 * flags - (IN) Flags for future use 37737 * Returns: 37738 * BCM_E_XXX 37739 */ 37740 int 37741 bcmi_l3_intf_vpn_set(int unit, 37742 bcm_if_t l3_intf_id, bcm_vpn_t vpn, 37743 uint32 flags) 37744 { 37745 _bcm_l3_intf_cfg_t intf_info; 37746 egr_l3_intf_entry_t if_entry; 37747 int vlan; 37748 vlan = vpn; 37749 37750 if ((vlan < BCM_VLAN_NONE) || (vlan >= BCM_VLAN_INVALID)) { 37751 /* only vlan values are allowed */ 37752 return BCM_E_PARAM; 37753 } 37754 37755 if (BCM_L3_INTF_USED_GET(unit, l3_intf_id)) { 37756 sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t)); 37757 intf_info.l3i_index = l3_intf_id; 37758 37759 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 37760 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, 37761 &intf_info)); 37762 if (_bcmi_l3_intf_overlay_valid(unit, &intf_info) != BCM_E_NONE) { 37763 return BCM_E_PARAM; 37764 } 37765 /* Allow valid Overlay Interface 37766 * on which vfi value is set, otherwise 37767 * throw error */ 37768 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info.l3i_vid)) { 37769 BCM_IF_ERROR_RETURN(READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, l3_intf_id, 37770 &if_entry)); 37771 soc_EGR_L3_INTFm_field32_set(unit, &if_entry, VIDf, vpn); 37772 37773 BCM_IF_ERROR_RETURN(WRITE_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, 37774 l3_intf_id, &if_entry)); 37775 } else { 37776 return BCM_E_PARAM; 37777 } 37778 return BCM_E_NONE; 37779 } 37780 } 37781 return BCM_E_PARAM; 37782 } 37783 37784 /* 37785 * Function: 37786 * bcmi_l3_intf_vpn_get 37787 * Purpose: 37788 * Get the VPN on a given L3 Egress interface. 37789 * 37790 * Parameters: 37791 * unit - (IN) Unit number. 37792 * l3_intf_id - (IN) Interface ID of an egress L3 object 37793 * bcm_vpn_t - (OUT) VPN_ID that needs to be set on this interface 37794 * flags - (OUT) Flags for future use 37795 * Returns: 37796 * BCM_E_XXX 37797 */ 37798 int 37799 bcmi_l3_intf_vpn_get(int unit, 37800 bcm_if_t l3_intf_id, bcm_vpn_t *vpn, 37801 uint32 *flags) 37802 { 37803 _bcm_l3_intf_cfg_t intf_info; 37804 egr_l3_intf_entry_t if_entry; 37805 37806 if (BCM_L3_INTF_USED_GET(unit, l3_intf_id)) { 37807 sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t)); 37808 intf_info.l3i_index = l3_intf_id; 37809 if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) { 37810 BCM_IF_ERROR_RETURN(BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, 37811 &intf_info)); 37812 if (_bcmi_l3_intf_overlay_valid(unit, &intf_info) == BCM_E_NONE) { 37813 BCM_IF_ERROR_RETURN(READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, 37814 l3_intf_id, &if_entry)); 37815 *vpn = soc_EGR_L3_INTFm_field32_get(unit, &if_entry, VIDf); 37816 return BCM_E_NONE; 37817 } 37818 } 37819 } 37820 return BCM_E_PARAM; 37821 } 37822 37823 /* 37824 * Function: 37825 * bcmi_ecmp_dlb_status_get 37826 * Purpose: 37827 * Check if DLB hashing is enabled on any ECMP group. 37828 * Parameters: 37829 * unit - (IN) SOC unit number. 37830 * dlb_status - (OUT) ECMP DLB hashing status 37831 * Returns: 37832 * BCM_E_xxx 37833 */ 37834 int 37835 bcmi_ecmp_dlb_status_get(int unit, int *dlb_status) 37836 { 37837 int i; 37838 uint32 rval = 0; 37839 *dlb_status = FALSE; 37840 /* Check for the global mode enhanced_hashing status */ 37841 37842 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) { 37843 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 37844 if (1 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 37845 RH_DLB_SELECTIONf)) { 37846 /* ECMP DLB hashing is not enabled chip-wide. */ 37847 return BCM_E_NONE; 37848 } 37849 } 37850 for (i = 0; i <=4095; i++) { 37851 if (ecmp_grp_enhanced_hashing[unit][i] == 1) { 37852 *dlb_status = TRUE; 37853 break; 37854 } 37855 } 37856 return BCM_E_NONE; 37857 } 37858 37859 /* 37860 * Function: 37861 * bcmi_ecmp_rh_status_get 37862 * Purpose: 37863 * Check if RH hashing is enabled on any ECMP group. 37864 * Parameters: 37865 * unit - (IN) SOC unit number. 37866 * rh_status - (OUT) ECMP RH hashing status 37867 * Returns: 37868 * BCM_E_xxx 37869 */ 37870 int 37871 bcmi_ecmp_rh_status_get(int unit, int *rh_status) 37872 { 37873 int i; 37874 uint32 rval = 0; 37875 *rh_status = FALSE; 37876 /* Check for the global mode enhanced_hashing status */ 37877 37878 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) { 37879 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 37880 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 37881 RH_DLB_SELECTIONf)) { 37882 /* ECMP RH hashing is not enabled chip-wide. */ 37883 return BCM_E_NONE; 37884 } 37885 } 37886 for (i = 0; i <=4095; i++) { 37887 if (ecmp_grp_enhanced_hashing[unit][i] == 1) { 37888 *rh_status = TRUE; 37889 break; 37890 } 37891 } 37892 return BCM_E_NONE; 37893 } 37894 #endif 37895 #ifndef BCM_SW_STATE_DUMP_DISABLE 37896 /* 37897 * Function: 37898 * _bcm_l3_sw_dump 37899 * Purpose: 37900 * Displays L3 information maintained by software. 37901 * Parameters: 37902 * unit - Device unit number 37903 * Returns: 37904 * None 37905 */ 37906 void 37907 _bcm_l3_sw_dump(int unit) 37908 { 37909 #ifdef BCM_FIREBOLT_SUPPORT 37910 37911 int i, j; 37912 _bcm_l3_tbl_t *tbl_ptr; /* Generic table pointer */ 37913 #ifdef BCM_RIOT_SUPPORT 37914 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 37915 #endif 37916 37917 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 37918 LOG_CLI((BSL_META_U(unit, 37919 "\nL3 data structure is not initialized\n"))); 37920 return; 37921 } 37922 37923 LOG_CLI((BSL_META_U(unit, 37924 "\nSW Information L3 - Unit %d\n"), unit)); 37925 LOG_CLI((BSL_META_U(unit, 37926 " Initialized : %d\n"), BCM_XGS3_L3_INITIALIZED(unit))); 37927 37928 /* Interface table */ 37929 LOG_CLI((BSL_META_U(unit, 37930 " L3 Interface Table Information -\n"))); 37931 #ifdef BCM_RIOT_SUPPORT 37932 if ((BCMI_RIOT_IS_ENABLED(unit)) 37933 && (l3_bk_info->l3_intf_overlay_entries > 0)) { 37934 if (l3_bk_info->l3_intf_overlay_alloc_mode > 0) { 37935 LOG_CLI((BSL_META_U(unit, 37936 " Overlay table size : %d (%d - %d)\n"), 37937 l3_bk_info->l3_intf_overlay_entries, 37938 BCM_XGS3_L3_IF_TBL_SIZE(unit) - 37939 l3_bk_info->l3_intf_overlay_entries + 1, 37940 BCM_XGS3_L3_IF_TBL_SIZE(unit))); 37941 LOG_CLI((BSL_META_U(unit, 37942 " Underlay table size : %d (%d - %d)\n"), 37943 (BCM_XGS3_L3_IF_TBL_SIZE(unit) - 37944 l3_bk_info->l3_intf_overlay_entries) + 1, 37945 0, 37946 BCM_XGS3_L3_IF_TBL_SIZE(unit) - 37947 l3_bk_info->l3_intf_overlay_entries)); 37948 } else { 37949 LOG_CLI((BSL_META_U(unit, 37950 " Overlay table size : %d (%d - %d)\n"), 37951 l3_bk_info->l3_intf_overlay_entries, 0, 37952 l3_bk_info->l3_intf_overlay_entries -1)); 37953 LOG_CLI((BSL_META_U(unit, 37954 " Underlay table size : %d (%d - %d)\n"), 37955 (BCM_XGS3_L3_IF_TBL_SIZE(unit) - 37956 l3_bk_info->l3_intf_overlay_entries) + 1, 37957 l3_bk_info->l3_intf_overlay_entries, 37958 BCM_XGS3_L3_IF_TBL_SIZE(unit))); 37959 } 37960 } else 37961 #endif 37962 { 37963 LOG_CLI((BSL_META_U(unit, 37964 " table size : %d\n"), BCM_XGS3_L3_IF_TBL_SIZE(unit))); 37965 } 37966 37967 LOG_CLI((BSL_META_U(unit, 37968 " count : %d\n"), BCM_XGS3_L3_IF_COUNT(unit))); 37969 37970 LOG_CLI((BSL_META_U(unit, 37971 " Used index from bk info:"))); 37972 if (BCM_XGS3_L3_IF_INUSE(unit) != NULL) { 37973 for (i = 0, j = 0; i < BCM_XGS3_L3_IF_TBL_SIZE(unit); i++) { 37974 /* If not set, skip print */ 37975 if (!BCM_L3_INTF_USED_GET(unit, i)) { 37976 continue; 37977 } 37978 if (!(j % 10)) { 37979 LOG_CLI((BSL_META_U(unit, 37980 "\n "))); 37981 } 37982 LOG_CLI((BSL_META_U(unit, 37983 " %5d"), i)); 37984 j++; 37985 } 37986 } 37987 LOG_CLI((BSL_META_U(unit, 37988 "\n"))); 37989 37990 LOG_CLI((BSL_META_U(unit, 37991 " ARL index :"))); 37992 if (BCM_XGS3_L3_IF_ADD2ARL(unit) != NULL) { 37993 for (i = 0, j = 0; i < BCM_XGS3_L3_IF_TBL_SIZE(unit); i++) { 37994 /* If not set, skip print */ 37995 if (!BCM_L3_INTF_ARL_GET(unit, i)) { 37996 continue; 37997 } 37998 if (!(j % 10)) { 37999 LOG_CLI((BSL_META_U(unit, 38000 "\n "))); 38001 } 38002 LOG_CLI((BSL_META_U(unit, 38003 " %5d"), i)); 38004 j++; 38005 } 38006 } 38007 LOG_CLI((BSL_META_U(unit, 38008 "\n"))); 38009 38010 /* Defip table */ 38011 LOG_CLI((BSL_META_U(unit, 38012 " DEF IP -\n"))); 38013 LOG_CLI((BSL_META_U(unit, 38014 " table size : %d\n"), BCM_XGS3_L3_DEFIP_TBL_SIZE(unit))); 38015 LOG_CLI((BSL_META_U(unit, 38016 " IP4 count : %d\n"), BCM_XGS3_L3_DEFIP_IP4_CNT(unit))); 38017 LOG_CLI((BSL_META_U(unit, 38018 " IP6 count : %d\n"), BCM_XGS3_L3_DEFIP_IP6_CNT(unit))); 38019 /* Skip 'strata_defip_info' since this is for Strata only */ 38020 38021 /* L3 Host table */ 38022 LOG_CLI((BSL_META_U(unit, 38023 " L3 -\n"))); 38024 LOG_CLI((BSL_META_U(unit, 38025 " table size : %d\n"), BCM_XGS3_L3_TBL_SIZE(unit))); 38026 LOG_CLI((BSL_META_U(unit, 38027 " IP4 added : %d\n"), BCM_XGS3_L3_IP4_CNT(unit))); 38028 LOG_CLI((BSL_META_U(unit, 38029 " IP6 added : %d\n"), BCM_XGS3_L3_IP6_CNT(unit))); 38030 LOG_CLI((BSL_META_U(unit, 38031 " IP4 IPMC added : %d\n"), BCM_XGS3_L3_IP4_IPMC_CNT(unit))); 38032 LOG_CLI((BSL_META_U(unit, 38033 " IP6 IPMC added : %d\n"), BCM_XGS3_L3_IP6_IPMC_CNT(unit))); 38034 38035 /* ECMP table */ 38036 LOG_CLI((BSL_META_U(unit, 38037 " ECMP table size : %d\n"), 38038 BCM_XGS3_L3_ECMP_TBL_SIZE(unit))); 38039 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 38040 LOG_CLI((BSL_META_U(unit, 38041 "\n L3 ECMP Table -\n"))); 38042 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 38043 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 38044 38045 LOG_CLI((BSL_META_U(unit, "==== Overlay table size ==== \n"))); 38046 LOG_CLI((BSL_META_U(unit, 38047 " min : %d\n"), tbl_ptr->idx_min)); 38048 LOG_CLI((BSL_META_U(unit, 38049 " max : %d\n"), tbl_ptr->split_idx - 1)); 38050 LOG_CLI((BSL_META_U(unit, 38051 " overlay max used : %d\n"), tbl_ptr->split_maxused)); 38052 38053 LOG_CLI((BSL_META_U(unit, "==== Underlay table size ==== \n"))); 38054 LOG_CLI((BSL_META_U(unit, 38055 " min : %d\n"), tbl_ptr->split_idx)); 38056 LOG_CLI((BSL_META_U(unit, 38057 " max : %d\n"), tbl_ptr->idx_max)); 38058 LOG_CLI((BSL_META_U(unit, 38059 " underlay max used : %d\n"), tbl_ptr->idx_maxused)); 38060 38061 } else 38062 #endif 38063 { 38064 38065 LOG_CLI((BSL_META_U(unit, 38066 " min : %d\n"), tbl_ptr->idx_min)); 38067 LOG_CLI((BSL_META_U(unit, 38068 " max : %d\n"), tbl_ptr->idx_max)); 38069 LOG_CLI((BSL_META_U(unit, 38070 " max used : %d\n"), tbl_ptr->idx_maxused)); 38071 } 38072 LOG_CLI((BSL_META_U(unit, 38073 " max paths : %d\n"), BCM_XGS3_L3_ECMP_MAX_PATHS(unit))); 38074 LOG_CLI((BSL_META_U(unit, 38075 " in use : %d\n"), BCM_XGS3_L3_ECMP_IN_USE(unit))); 38076 38077 if(!(tbl_ptr->idx_min == 0 && tbl_ptr->idx_max == 0)) { /* mem not valid */ 38078 LOG_CLI((BSL_META_U(unit, 38079 " table index : hash : ref_count"))); 38080 for (i = tbl_ptr->idx_min, j = 0; i <= tbl_ptr->idx_max; i++) { 38081 /* If zero, skip print */ 38082 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) { 38083 continue; 38084 } 38085 if (!(j % 4)) { 38086 LOG_CLI((BSL_META_U(unit, 38087 "\n "))); 38088 } 38089 LOG_CLI((BSL_META_U(unit, 38090 " %5d:%-5d:%-5d"), i, BCM_XGS3_L3_ENT_HASH(tbl_ptr, i), 38091 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i))); 38092 j++; 38093 } 38094 } 38095 LOG_CLI((BSL_META_U(unit, 38096 "\n"))); 38097 38098 /* Next hop table */ 38099 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop); 38100 LOG_CLI((BSL_META_U(unit, 38101 "\n L3 Next Hop Table -\n"))); 38102 #ifdef BCM_RIOT_SUPPORT 38103 if (BCMI_RIOT_IS_ENABLED(unit) 38104 && (l3_bk_info->l3_nh_overlay_entries > 0)) { 38105 if (l3_bk_info->l3_nh_overlay_alloc_mode > 0) { 38106 LOG_CLI((BSL_META_U(unit, "==== Overlay table size ==== : \n"))); 38107 LOG_CLI((BSL_META_U(unit, 38108 " min : %d\n"), tbl_ptr->split_idx)); 38109 LOG_CLI((BSL_META_U(unit, 38110 " max : %d\n"), tbl_ptr->idx_max)); 38111 LOG_CLI((BSL_META_U(unit, 38112 " overlay max used : %d\n"), tbl_ptr->idx_maxused)); 38113 38114 LOG_CLI((BSL_META_U(unit, "==== Underlay table size ==== \n"))); 38115 LOG_CLI((BSL_META_U(unit, 38116 " min : %d\n"), tbl_ptr->idx_min)); 38117 LOG_CLI((BSL_META_U(unit, 38118 " max : %d\n"), tbl_ptr->split_idx - 1)); 38119 LOG_CLI((BSL_META_U(unit, 38120 " underlay max used : %d\n"), tbl_ptr->split_maxused)); 38121 } else { 38122 LOG_CLI((BSL_META_U(unit, "==== Overlay table size ==== \n"))); 38123 LOG_CLI((BSL_META_U(unit, 38124 " min : %d\n"), tbl_ptr->idx_min)); 38125 LOG_CLI((BSL_META_U(unit, 38126 " max : %d\n"), tbl_ptr->split_idx - 1)); 38127 LOG_CLI((BSL_META_U(unit, 38128 " overlay max used : %d\n"), tbl_ptr->split_maxused)); 38129 38130 LOG_CLI((BSL_META_U(unit, "==== Underlay table size ==== : \n"))); 38131 LOG_CLI((BSL_META_U(unit, 38132 " min : %d\n"), tbl_ptr->split_idx)); 38133 LOG_CLI((BSL_META_U(unit, 38134 " max : %d\n"), tbl_ptr->idx_max)); 38135 LOG_CLI((BSL_META_U(unit, 38136 " underlay max used : %d\n"), tbl_ptr->idx_maxused)); 38137 } 38138 } else 38139 #endif 38140 { 38141 LOG_CLI((BSL_META_U(unit, 38142 " NH table size : %d\n"), BCM_XGS3_L3_NH_TBL_SIZE(unit))); 38143 LOG_CLI((BSL_META_U(unit, 38144 " NH index min : %d\n"), tbl_ptr->idx_min)); 38145 LOG_CLI((BSL_META_U(unit, 38146 " NH index max used : %d\n"), tbl_ptr->idx_maxused)); 38147 } 38148 for (i = tbl_ptr->idx_min, j = 0; i <= tbl_ptr->idx_max; i++) { 38149 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) { 38150 continue; 38151 } 38152 if (!(j % 4)) { 38153 LOG_CLI((BSL_META_U(unit, 38154 "\n "))); 38155 } 38156 LOG_CLI((BSL_META_U(unit, 38157 " %5d:%-5d:%-5d"), i, BCM_XGS3_L3_ENT_HASH(tbl_ptr, i), 38158 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i))); 38159 j++; 38160 soc_tunnel_term_sw_dump(unit); 38161 } 38162 /* Tunnel initiator table */ 38163 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init); 38164 LOG_CLI((BSL_META_U(unit, 38165 "\n L3 Tunnel Initiator Table -\n"))); 38166 LOG_CLI((BSL_META_U(unit, 38167 " min : %d\n"), tbl_ptr->idx_min)); 38168 LOG_CLI((BSL_META_U(unit, 38169 " max : %d\n"), tbl_ptr->idx_max)); 38170 LOG_CLI((BSL_META_U(unit, 38171 " total : %d\n"), BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit))); 38172 38173 if(!(tbl_ptr->idx_min == 0 && tbl_ptr->idx_max == 0)) { /* mem not valid */ 38174 LOG_CLI((BSL_META_U(unit, 38175 " use count (index:hash:count) :"))); 38176 for (i = tbl_ptr->idx_min, j = 0; i <= tbl_ptr->idx_max; i++) { 38177 /* If zero count, skip print */ 38178 if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) { 38179 continue; 38180 } 38181 if (!(j % 4)) { 38182 LOG_CLI((BSL_META_U(unit, 38183 "\n "))); 38184 } 38185 LOG_CLI((BSL_META_U(unit, 38186 " %5d:%-5d:%-5d"), i, BCM_XGS3_L3_ENT_HASH(tbl_ptr, i), 38187 BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i))); 38188 j++; 38189 } 38190 } 38191 LOG_CLI((BSL_META_U(unit, 38192 "\n"))); 38193 #ifdef BCM_TRIUMPH2_SUPPORT 38194 if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 38195 LOG_CLI((BSL_META_U(unit, 38196 "\n ECMP group id:max paths-\n"))); 38197 for (i=0, j=0; i<BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) { 38198 if (BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[i] != 0) { 38199 LOG_CLI((BSL_META_U(unit, 38200 "%d:%d "), i, 38201 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[i])); 38202 j++; 38203 if (!(j%20)) { 38204 LOG_CLI((BSL_META_U(unit, 38205 "\n"))); 38206 } 38207 } 38208 } 38209 } 38210 #endif 38211 38212 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 38213 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 38214 SHR_BITDCL *group_bitmap_ptr = NULL; 38215 int bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 38216 38217 LOG_CLI((BSL_META_U(unit, 38218 "\n ECMP group id: DLB bitmap-\n"))); 38219 for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) { 38220 group_bitmap_ptr = 38221 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, i); 38222 if (!SHR_BITNULL_RANGE(group_bitmap_ptr, 0, bitmap_width)) { 38223 LOG_CLI((BSL_META_U(unit, "%d:"), i)); 38224 for(j = 0; j < _SHR_BITDCLSIZE(bitmap_width); j++) { 38225 LOG_CLI((BSL_META_U(unit, " [%d]0x%x:"), 38226 j, group_bitmap_ptr[j])); 38227 } 38228 LOG_CLI((BSL_META_U(unit, "\n"))); 38229 } 38230 } 38231 } 38232 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */ 38233 38234 38235 #ifdef ALPM_ENABLE 38236 /* ALPM Mode */ 38237 if (soc_feature(unit, soc_feature_alpm) 38238 && soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 38239 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 38240 soc_alpm_sw_dump(unit); 38241 } 38242 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 38243 else { 38244 #if defined(BCM_TOMAHAWK_SUPPORT) 38245 if (soc_feature(unit, soc_feature_alpm2)) { 38246 bcm_esw_alpm_sw_dump(unit); 38247 } else 38248 #endif 38249 { 38250 soc_th_alpm_sw_dump(unit); 38251 } 38252 } 38253 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_APACHE_SUPPORT */ 38254 } else 38255 #endif /* ALPM_ENABLE */ 38256 { 38257 /* Prefix trackers (FB only) */ 38258 if (SOC_IS_FBX(unit)) { 38259 soc_fb_lpm_sw_dump(unit); 38260 } 38261 } 38262 #ifdef BCM_TRIUMPH3_SUPPORT 38263 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 38264 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 38265 if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) { 38266 bcm_th2_ecmp_dlb_sw_dump(unit); 38267 } else 38268 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/ 38269 { 38270 bcm_tr3_ecmp_dlb_sw_dump(unit); 38271 } 38272 } 38273 38274 if (soc_feature(unit, soc_feature_esm_support)) { 38275 _bcm_tr3_esm_host_tbl_sw_dump(unit); 38276 } 38277 #endif /* BCM_TRIUMPH3_SUPPORT */ 38278 38279 #ifdef BCM_TRIUMPH2_SUPPORT 38280 if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) || 38281 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 38282 if (!soc_feature(unit, soc_feature_l3_no_ecmp)) { 38283 bcm_tr2_l3_ecmp_defragment_buffer_sw_dump(unit); 38284 } 38285 } 38286 #endif /* BCM_TRIUMPH2_SUPPORT */ 38287 38288 #ifdef BCM_TRIDENT2_SUPPORT 38289 if (SOC_IS_TRIDENT2X(unit) && 38290 soc_feature(unit, soc_feature_ecmp_resilient_hash)) { 38291 bcm_td2_ecmp_rh_sw_dump(unit); 38292 } 38293 #endif /* BCM_TRIDENT2_SUPPORT */ 38294 38295 #ifdef BCM_TOMAHAWK_SUPPORT 38296 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) { 38297 bcm_opt_ecmp_rh_sw_dump(unit); 38298 } 38299 #endif /* BCM_TOMAHAWK_SUPPORT */ 38300 38301 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 38302 if (soc_feature(unit, soc_feature_dgm)) { 38303 bcm_th2_dgm_sw_dump(unit); 38304 } 38305 #endif 38306 38307 #endif /* BCM_FIREBOLT_SUPPORT */ 38308 38309 return; 38310 } 38311 38312 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 38313 void 38314 bcmi_l3_dependent_free_resources(int unit) 38315 { 38316 bcmi_esw_failover_dependent_free_resources(unit); 38317 return; 38318 } 38319 38320 #else /* INCLUDE_L3 */ 38321 int bcm_esw_firebolt_l3_not_empty; 38322 #endif /* INCLUDE_L3 */