l3.c (482930B)
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: Triumph3 L3 function implementations 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <soc/defs.h> 14 #if defined(INCLUDE_L3) && defined(BCM_TRIDENT2_SUPPORT) 15 16 #include <soc/drv.h> 17 #include <soc/scache.h> 18 #include <bcm/vlan.h> 19 #include <bcm/error.h> 20 21 #include <bcm/l3.h> 22 #include <soc/l3x.h> 23 #include <soc/lpm.h> 24 #ifdef ALPM_ENABLE 25 #include <soc/alpm.h> 26 #include <soc/esw/alpm_int.h> 27 #endif 28 #include <bcm/tunnel.h> 29 #include <bcm/debug.h> 30 #include <bcm/error.h> 31 #include <bcm/stack.h> 32 #include <soc/trident2.h> 33 #if defined(BCM_TOMAHAWK_SUPPORT) 34 #include <soc/tomahawk.h> 35 #endif /* BCM_TOMAHAWK_SUPPORT */ 36 #if defined(BCM_TOMAHAWK3_SUPPORT) 37 #include <soc/tomahawk3.h> 38 #endif /* BCM_TOMAHAWK3_SUPPORT */ 39 #if defined(BCM_MONTEREY_SUPPORT) 40 #include <soc/monterey.h> 41 #include <bcm_int/esw/monterey.h> 42 #endif /* BCM_MONTEREY_SUPPORT */ 43 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 44 #include <soc/trident3.h> 45 #include <bcm_int/esw/trident3.h> 46 #endif /* BCM_TRIDENT3_SUPPORT */ 47 #if defined(BCM_APACHE_SUPPORT) 48 #include <soc/apache.h> 49 #endif /* BCM_APACHE_SUPPORT */ 50 #if defined(BCM_HELIX5_SUPPORT) 51 #include <soc/helix5.h> 52 #include <bcm_int/esw/helix5.h> 53 #endif /* BCM_HELIX5_SUPPORT */ 54 #if defined(BCM_TRIDENT3_SUPPORT) 55 #include <bcm_int/esw/flow.h> 56 #include <soc/esw/flow_db.h> 57 #endif /* BCM_TRIDENT3_SUPPORT*/ 58 #include <bcm_int/esw/tomahawk.h> 59 #include <bcm_int/esw/trident2.h> 60 #include <bcm_int/esw/firebolt.h> 61 #include <bcm_int/esw/triumph.h> 62 #include <bcm_int/esw/triumph2.h> 63 #include <bcm_int/esw/stack.h> 64 #include <bcm_int/esw/flex_ctr.h> 65 #include <bcm_int/esw_dispatch.h> 66 #include <bcm_int/esw/flex_ctr.h> 67 #include <bcm_int/esw/virtual.h> 68 69 #ifdef ALPM_ENABLE 70 #include <bcm_int/esw/alpm.h> 71 #include <bcm_int/esw/alpm_util.h> 72 #endif 73 74 #if defined(BCM_TRX_SUPPORT) 75 #include <bcm_int/esw/trx.h> 76 #endif /* BCM_TRX_SUPPORT */ 77 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 78 #include <bcm_int/esw/trident2plus.h> 79 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 80 81 #define TH_IPMC_NO_SRC_CHECK_PORT 0xFF 82 83 /* NH nat id update key type*/ 84 #define _BCM_NH_UPDATE_KEY_L3_INTF 0 85 #define _BCM_NH_UPDATE_KEY_L3_IIF 1 86 #define _BCM_NH_UPDATE_KEY_VLAN 2 87 88 /* IP Options Handling */ 89 #define L3_INFO(_unit_) (&_bcm_l3_bk_info[_unit_]) 90 #define _BCM_IP_OPTION_PROFILE_CHUNK 256 91 #define _BCM_IP4_OPTIONS_LEN \ 92 (soc_mem_index_count(unit, IP_OPTION_CONTROL_PROFILE_TABLEm)/ \ 93 _BCM_IP_OPTION_PROFILE_CHUNK) 94 95 /* Add mutex semaphore to protect "L3_INFO(unit)->ip4_profiles_hw_idx" */ 96 STATIC sal_mutex_t ip4_profiles_hw_idx_lock[BCM_MAX_NUM_UNITS]; 97 98 #define HW_IDX_LOCK(unit) \ 99 do { \ 100 if (ip4_profiles_hw_idx_lock[unit] != NULL) { \ 101 sal_mutex_take(ip4_profiles_hw_idx_lock[unit], sal_mutex_FOREVER); \ 102 } \ 103 } while (0) 104 105 #define HW_IDX_UNLOCK(unit) \ 106 do { \ 107 if (ip4_profiles_hw_idx_lock[unit] != NULL) { \ 108 sal_mutex_give(ip4_profiles_hw_idx_lock[unit]); \ 109 } \ 110 } while (0) 111 112 #define GET_HW_IDX(unit, idx, id) \ 113 do { \ 114 HW_IDX_LOCK(unit); \ 115 idx = L3_INFO(unit)->ip4_profiles_hw_idx[id]; \ 116 HW_IDX_UNLOCK(unit); \ 117 } while (0) 118 119 #define SET_HW_IDX(unit, id, idx) \ 120 do { \ 121 HW_IDX_LOCK(unit); \ 122 L3_INFO(unit)->ip4_profiles_hw_idx[id] = idx; \ 123 HW_IDX_UNLOCK(unit); \ 124 } while (0) 125 126 /* 127 * IP_OPTIONS_PROFILE usage bitmap operations 128 */ 129 #define _BCM_IP4_OPTIONS_USED_GET(_u_, _identifier_) \ 130 SHR_BITGET(L3_INFO(_u_)->ip4_options_bitmap, (_identifier_)) 131 #define _BCM_IP4_OPTIONS_USED_SET(_u_, _identifier_) \ 132 SHR_BITSET(L3_INFO((_u_))->ip4_options_bitmap, (_identifier_)) 133 #define _BCM_IP4_OPTIONS_USED_CLR(_u_, _identifier_) \ 134 SHR_BITCLR(L3_INFO((_u_))->ip4_options_bitmap, (_identifier_)) 135 136 #define _BCM_IP_OPTION_REINIT_INVALID_HW_IDX 0xffff 137 138 /* Bookkeeping info for ECMP resilient hashing */ 139 typedef struct _td2_ecmp_rh_info_s { 140 int num_ecmp_rh_flowset_blocks; 141 SHR_BITDCL *ecmp_rh_flowset_block_bitmap; /* Each block corresponds to 142 64 entries, 8 for monterey */ 143 uint32 ecmp_rh_rand_seed; /* The seed for pseudo-random number generator */ 144 uint8 ecmp_block_size; /* Block size in bits 145 * 6 for TD2/+/Apache 146 * 3 for Monterey */ 147 uint8 ecmp_rand_seed_shift; 148 } _td2_ecmp_rh_info_t; 149 150 STATIC _td2_ecmp_rh_info_t *_td2_ecmp_rh_info[BCM_MAX_NUM_UNITS]; 151 152 /* per ecmp group enhanced hashing enabled info */ 153 #ifdef BCM_TRIDENT3_SUPPORT 154 extern uint8 ecmp_grp_enhanced_hashing[BCM_MAX_NUM_UNITS][4096]; 155 #endif 156 157 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \ 158 SHR_BITGET(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, _idx_) 159 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \ 160 SHR_BITSET(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, _idx_) 161 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \ 162 SHR_BITCLR(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, _idx_) 163 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \ 164 SHR_BITSET_RANGE(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, \ 165 _idx_, _count_) 166 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \ 167 SHR_BITCLR_RANGE(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, \ 168 _idx_, _count_) 169 #define _BCM_ECMP_RH_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \ 170 SHR_BITTEST_RANGE(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, \ 171 _idx_, _count_, _result_) 172 173 typedef struct _td2_ecmp_rh_member_s { 174 int nh_index; /* Next hop index of the member */ 175 int member_id; /* Member ID */ 176 int num_replica; /* Number of members with the same next hop index as 177 this member. Valid only for the first replica. */ 178 int replica_id; /* Index among members with the same next hop index as 179 this member. Valid for every replica. */ 180 int next_replica_id; /* Index of the next replica to be assigned to 181 a flow set entry containing the next hop index 182 shared by replicas. Valid only for the first 183 replica. */ 184 } _td2_ecmp_rh_member_t; 185 186 /*----- STATIC FUNCS ----- */ 187 int 188 _bcm_td2_l3_ipmc_ent_init(int unit, uint32 *buf_p, _bcm_l3_cfg_t *l3cfg); 189 190 191 /* 192 * Function: 193 * _bcm_td2_l3_ent_init 194 * Purpose: 195 * TD2 helper routine used to init l3 host entry buffer 196 * Parameters: 197 * unit - (IN) SOC unit number. 198 * mem - (IN) L3 table memory. 199 * l3cfg - (IN/OUT) l3 entry lookup key & search result. 200 * l3x_entry - (IN) hw buffer. 201 * Returns: 202 * void 203 */ 204 int 205 _bcm_td2_l3_ent_init(int unit, soc_mem_t mem, 206 _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 207 { 208 int ipv6; /* Entry is IPv6 flag. */ 209 uint32 *buf_p; /* HW buffer address. */ 210 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 211 uint32 base_valid0, base_valid1; 212 #endif 213 214 215 /* Get entry type. */ 216 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 217 218 /* Zero destination buffer. */ 219 buf_p = (uint32 *)l3x_entry; 220 sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 221 222 if (ipv6) { /* ipv6 entry */ 223 if (BCM_XGS3_L3_MEM(unit, v6) == mem) { 224 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 225 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 226 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_LWR_64f, 227 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 228 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_UPR_64f, 229 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 230 soc_mem_field32_set(unit, mem, buf_p, IPV6UC__VRF_IDf, 231 l3cfg->l3c_vrf); 232 233 } else 234 #endif 235 { 236 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f, 237 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 238 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f, 239 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 240 soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, 241 l3cfg->l3c_vrf); 242 } 243 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 244 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) 245 { 246 if (SOC_IS_TRIDENT3X(unit)) 247 { 248 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, TD3_L3_HASH_DATA_TYPE_V6UC); 249 base_valid0 = 3; 250 base_valid1 = 4; 251 } 252 else 253 { 254 base_valid0 = 1; 255 base_valid1 = 2; 256 } 257 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, TD3_L3_HASH_KEY_TYPE_V6UC); 258 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0); 259 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1); 260 } 261 else 262 #endif 263 { 264 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 265 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 266 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 2); 267 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 2); 268 } 269 } else if (BCM_XGS3_L3_MEM(unit, v6_4) == mem) { 270 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC_EXT__IP_ADDR_LWR_64f, 271 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 272 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC_EXT__IP_ADDR_UPR_64f, 273 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 274 soc_mem_field32_set(unit, mem, buf_p, IPV6UC_EXT__VRF_IDf, 275 l3cfg->l3c_vrf); 276 /* ipv6 extended host entry */ 277 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 278 if (SOC_IS_TRIDENT3X(unit)) 279 { 280 if (SOC_IS_TRIDENT3X(unit)) 281 { 282 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, TD3_L3_HASH_DATA_TYPE_V6UC_EXT); 283 } 284 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, TD3_L3_HASH_KEY_TYPE_V6UC_EXT); 285 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, 3); 286 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, 4); 287 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_2f, 7); 288 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_3f, 7); 289 } else 290 #endif 291 { 292 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 3); 293 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 3); 294 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_2f, 3); 295 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_3f, 3); 296 297 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 298 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 299 soc_mem_field32_set(unit, mem, buf_p, VALID_2f, 1); 300 soc_mem_field32_set(unit, mem, buf_p, VALID_3f, 1); 301 } 302 } else { 303 return BCM_E_NOT_FOUND; 304 } 305 } else { /* ipv4 entry */ /* if uC is still not ready, return timeout */ 306 if (BCM_XGS3_L3_MEM(unit, v4) == mem) { 307 #if defined(BCM_TOMAHAWK3_SUPPORT) 308 if (SOC_IS_TOMAHAWK3(unit)) 309 { 310 soc_mem_field32_set(unit, mem, buf_p, IPV4UC__IP_ADDRf, 311 l3cfg->l3c_ip_addr); 312 soc_mem_field32_set(unit, mem, buf_p, IPV4UC__VRF_IDf, 313 l3cfg->l3c_vrf); 314 } else 315 #endif 316 { 317 soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf, 318 l3cfg->l3c_ip_addr); 319 soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, 320 l3cfg->l3c_vrf); 321 } 322 /* ipv4 unicast */ 323 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 0); 324 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 325 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 326 soc_mem_field32_set(unit, mem, buf_p, BASE_VALIDf, 1); 327 } else 328 #endif 329 { 330 soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1); 331 } 332 } else if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) { 333 soc_mem_field32_set(unit, mem, buf_p, IPV4UC_EXT__IP_ADDRf, 334 l3cfg->l3c_ip_addr); 335 soc_mem_field32_set(unit, mem, buf_p, IPV4UC_EXT__VRF_IDf, 336 l3cfg->l3c_vrf); 337 /* ipv4 extended host entry */ 338 #ifdef BCM_TRIDENT3_SUPPORT 339 if (SOC_IS_TRIDENT3X(unit)) { 340 /* TD3 is different from previous chips. 0 in KEY_TYPE was used to distinguish regular from extended 341 * entries in previous chips. In TD3 DATA_TYPE is 1 for extended entries 342 */ 343 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, TD3_L3_HASH_KEY_TYPE_V4UC_EXT); 344 if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) { 345 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, TD3_L3_HASH_DATA_TYPE_V4UC_EXT); 346 } 347 base_valid0 = 1; 348 if (SOC_IS_TOMAHAWK3(unit)) { 349 base_valid1 = 2; 350 } else { 351 base_valid1 = 7; 352 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, 7); 353 } 354 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1); 355 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0); 356 } else 357 #endif 358 { 359 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 1); 360 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 1); 361 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 362 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 363 } 364 } else { 365 return BCM_E_NOT_FOUND; 366 } 367 } 368 return BCM_E_NONE; 369 } 370 371 /*----- STATIC FUNCS ----- */ 372 /* 373 * Function: 374 * _bcm_td2_l3_ent_parse 375 * Purpose: 376 * TD2 helper routine used to parse hw l3 entry to api format. 377 * Parameters: 378 * unit - (IN) SOC unit number. 379 * mem - (IN) L3 table memory. 380 * l3cfg - (IN/OUT) l3 entry key & parse result. 381 * nh_idx - (IN/OUT) Next hop index. 382 * l3x_entry - (IN) hw buffer. 383 * Returns: 384 * void 385 */ 386 STATIC int 387 _bcm_td2_l3_ent_parse(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, 388 int *nh_idx, void *l3x_entry, int key_type) 389 { 390 int ipv6; /* Entry is IPv6 flag. */ 391 uint32 hit = 0; /* composite hit = hit_x|hit_y */ 392 uint32 *buf_p; /* HW buffer address. */ 393 uint32 glp; /* Global port. */ 394 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 395 int embedded_nh = FALSE; 396 l3_entry_hit_only_x_entry_t hit_x; 397 l3_entry_hit_only_y_entry_t hit_y; 398 l3_entry_hit_only_entry_t hit_default; 399 int idx, idx_max, idx_offset, hit_idx_shift; 400 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f}; 401 402 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 403 buf_p = (uint32 *)l3x_entry; 404 405 #ifdef BCM_TRIDENT3_SUPPORT 406 if (soc_feature(unit, soc_feature_flex_flow) && 407 l3cfg->l3c_flow_handle != 0) { 408 409 return _bcm_td3_l3_flex_ent_parse(unit, mem, l3cfg, nh_idx, l3x_entry); 410 } 411 #endif 412 413 /* 414 * Set table fields 415 */ 416 #ifdef BCM_TOMAHAWK3_SUPPORT 417 if (SOC_IS_TOMAHAWK3(unit)) 418 { 419 BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 420 /* 421 * Check if embedded NH table is being used 422 */ 423 embedded_nh = 0; 424 425 } else 426 #endif 427 #ifdef BCM_TRIDENT3_SUPPORT 428 if (SOC_IS_TRIDENT3X(unit)) { 429 BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 430 /* Check if embedded NH table is being used */ 431 embedded_nh = (mem == L3_ENTRY_DOUBLEm && !ipv6) || 432 (mem == L3_ENTRY_QUADm && ipv6); 433 434 } else 435 #endif 436 { 437 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 438 /* Check if embedded NH table is being used */ 439 embedded_nh = (mem == L3_ENTRY_IPV4_MULTICASTm && !ipv6) || 440 (mem == L3_ENTRY_IPV6_MULTICASTm && ipv6); 441 442 } 443 444 /* Reset entry flags */ 445 l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0; 446 447 idx_max = 1; 448 idx_offset = (l3cfg->l3c_hw_index & 0x3); 449 hit_idx_shift = 2; 450 if (mem == L3_ENTRY_IPV4_MULTICASTm || 451 mem == L3_ENTRY_IPV6_UNICASTm || 452 (mem == L3_ENTRY_DOUBLEm)) { 453 idx_max = 2; 454 hit_idx_shift = 1; 455 idx_offset = (l3cfg->l3c_hw_index & 0x1) << 1; 456 } else if ((mem == L3_ENTRY_IPV6_MULTICASTm) || 457 (mem == L3_ENTRY_QUADm)) { 458 idx_max = 4; 459 hit_idx_shift = 0; 460 idx_offset = 0; 461 } 462 463 if (soc_feature(unit, soc_feature_multi_pipe_mapped_ports)) { 464 /* SOC_IS_TOMAHAWKX(unit) */ 465 /* Get info from L3 and next hop table */ 466 BCM_IF_ERROR_RETURN( 467 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm, 468 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x)); 469 470 hit = 0; 471 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 472 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm, 473 &hit_x, hitf[idx]); 474 } 475 } else if (soc_feature(unit, soc_feature_two_ingress_pipes)) { 476 /* Get info from L3 and next hop table */ 477 BCM_IF_ERROR_RETURN( 478 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Xm, 479 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x)); 480 481 BCM_IF_ERROR_RETURN( 482 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Ym, 483 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_y)); 484 485 hit = 0; 486 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 487 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Xm, 488 &hit_x, hitf[idx]); 489 } 490 491 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 492 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Ym, 493 &hit_y, hitf[idx]); 494 } 495 } else { 496 /* Get info from L3 and next hop table */ 497 BCM_IF_ERROR_RETURN( 498 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm, 499 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_default)); 500 501 hit = 0; 502 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 503 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm, 504 &hit_default, hitf[idx]); 505 } 506 } 507 508 soc_mem_field32_set(unit, mem, buf_p, fld->hit, hit); 509 510 if (hit) { 511 l3cfg->l3c_flags |= BCM_L3_HIT; 512 } 513 /* Get priority override flag. */ 514 if (soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) { 515 l3cfg->l3c_flags |= BCM_L3_RPE; 516 } 517 518 /* Get destination discard flag. */ 519 if (soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) { 520 l3cfg->l3c_flags |= BCM_L3_DST_DISCARD; 521 } 522 523 /* Get local addr bit. */ 524 if (soc_mem_field32_get(unit, mem, buf_p, fld->local_addr)) { 525 l3cfg->l3c_flags |= BCM_L3_HOST_LOCAL; 526 } 527 528 #ifdef BCM_MONTEREY_SUPPORT 529 /* Get Roe Header Decap Control */ 530 if (soc_feature(unit, soc_feature_roe) || 531 soc_feature(unit, soc_feature_roe_custom)) { 532 if (soc_mem_field32_get(unit, mem, buf_p, fld->roe_decap)) { 533 l3cfg->l3c_flags2 |= BCM_L3_FLAGS2_DECAP_ROE_HEADER; 534 } 535 } 536 #endif 537 538 /* Get classification group id. */ 539 l3cfg->l3c_lookup_class = 540 soc_mem_field32_get(unit, mem, buf_p, fld->class_id); 541 542 /* Get priority. */ 543 l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority); 544 545 /* Get virtual router id. */ 546 l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf); 547 548 if (embedded_nh) { 549 uint32 port_addr_max = 0, modid_max = 0; 550 #ifdef BCM_RIOT_SUPPORT 551 int dest_type = 0, dvp = -1; 552 #endif 553 554 l3cfg->l3c_flags |= BCM_L3_DEREFERENCED_NEXTHOP; 555 if (nh_idx) { 556 *nh_idx = BCM_XGS3_L3_INVALID_INDEX; /* Embedded NH */ 557 } 558 l3cfg->l3c_intf = soc_mem_field32_get(unit, mem, buf_p, 559 fld->l3_intf); 560 #ifdef BCM_TOMAHAWK_SUPPORT 561 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 562 BCM_IF_ERROR_RETURN 563 (_bcm_th_l3_vp_ent_parse(unit, mem, l3cfg, buf_p)); 564 } else 565 #endif 566 { 567 #if defined(BCM_RIOT_SUPPORT) 568 if ((soc_feature(unit, soc_feature_riot)) && 569 (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) { 570 /* Derive MAC address using profile table */ 571 BCM_IF_ERROR_RETURN 572 (_bcm_td2p_l3_macda_oui_profile_entry_parse(unit, mem, l3cfg, buf_p)); 573 } else 574 #endif 575 { 576 soc_mem_mac_addr_get(unit, mem, buf_p, 577 fld->mac_addr, l3cfg->l3c_mac_addr); 578 } 579 580 #ifdef BCM_TRIDENT3_SUPPORT 581 if (SOC_IS_TRIDENT3X(unit)) { 582 uint32 dtype; 583 glp = soc_mem_field32_dest_get(unit, mem, buf_p, fld->dest, &dtype); 584 dest_type = dtype; 585 } else 586 #endif 587 { 588 glp = soc_mem_field32_get(unit, mem, buf_p, fld->glp); 589 } 590 591 port_addr_max = SOC_PORT_ADDR_MAX(unit) + 1; 592 modid_max = SOC_MODID_MAX(unit) + 1; 593 594 #ifdef BCM_RIOT_SUPPORT 595 if (BCMI_RIOT_IS_ENABLED(unit)) { 596 if (SOC_IS_TRIDENT3X(unit)) { 597 if (dest_type == SOC_MEM_FIF_DEST_DVP) { 598 dvp = glp; /*glp already holds the DEST value from earlier call */ 599 _bcm_vp_encode_gport(unit, dvp, &(l3cfg->l3c_port_tgid)); 600 l3cfg->l3c_modid = 0; 601 } 602 } else { 603 604 dest_type = soc_mem_field32_get(unit, mem, buf_p, fld->dest_type); 605 if (dest_type == 1) { 606 dvp = soc_mem_field32_get(unit, mem, buf_p, fld->destination); 607 _bcm_vp_encode_gport(unit, dvp, &(l3cfg->l3c_port_tgid)); 608 l3cfg->l3c_modid = 0; 609 } 610 } 611 } 612 if (dvp == -1) 613 #endif 614 { 615 if ((glp & (port_addr_max * modid_max)) 616 #if defined(BCM_TRIDENT3_SUPPORT) 617 || (SOC_IS_TRIDENT3X(unit) && (dest_type == SOC_MEM_FIF_DEST_LAG)) 618 #endif 619 ) { 620 l3cfg->l3c_flags |= BCM_L3_TGID; 621 l3cfg->l3c_port_tgid = glp & BCM_TGID_PORT_TRUNK_MASK(unit); 622 l3cfg->l3c_modid = 0; 623 } else { 624 l3cfg->l3c_port_tgid = glp & SOC_PORT_ADDR_MAX(unit); 625 l3cfg->l3c_modid = (glp / port_addr_max) & SOC_MODID_MAX(unit); 626 } 627 } 628 629 } 630 l3cfg->l3c_eh_q_tag_type = soc_mem_field32_get(unit, mem, buf_p, 631 fld->eh_tag_type); 632 l3cfg->l3c_eh_q_tag = soc_mem_field32_get(unit, mem, buf_p, 633 fld->eh_queue_tag); 634 /* Get copy_to_cpu bit. */ 635 if (SOC_MEM_FIELD_VALID(unit, mem, fld->copy_to_cpu)) { 636 if (soc_mem_field32_get(unit, mem, buf_p, fld->copy_to_cpu)) { 637 l3cfg->l3c_flags |= BCM_L3_COPY_TO_CPU; 638 } 639 } 640 } else { 641 /* Get next hop info. */ 642 if (nh_idx) { 643 #ifdef BCM_TRIDENT3_SUPPORT 644 if (SOC_IS_TRIDENT3X(unit)) { 645 uint32 dest_type; 646 *nh_idx = soc_mem_field32_dest_get(unit, mem, buf_p, fld->dest, &dest_type); 647 if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 648 /* Mark entry as ecmp */ 649 l3cfg->l3c_ecmp = TRUE; 650 l3cfg->l3c_flags |= BCM_L3_MULTIPATH; 651 } 652 } else 653 #endif 654 { 655 *nh_idx = soc_mem_field32_get(unit, mem, buf_p, fld->nh_idx); 656 if (soc_mem_field32_get(unit, mem, buf_p, ECMPf)) { 657 /* Mark entry as ecmp */ 658 l3cfg->l3c_ecmp = TRUE; 659 l3cfg->l3c_flags |= BCM_L3_MULTIPATH; 660 } 661 } 662 } 663 #ifdef BCM_TRIDENT3_SUPPORT 664 if (!SOC_IS_TRIDENT3X(unit)) { 665 #endif 666 if (soc_mem_field32_get(unit, mem, buf_p, ECMPf)) { 667 /* Mark entry as ecmp */ 668 l3cfg->l3c_ecmp = TRUE; 669 l3cfg->l3c_flags |= BCM_L3_MULTIPATH; 670 } else { 671 l3cfg->l3c_ecmp = FALSE; 672 l3cfg->l3c_flags &= ~BCM_L3_MULTIPATH; 673 } 674 #ifdef BCM_TRIDENT3_SUPPORT 675 } 676 #endif 677 } 678 679 return BCM_E_NONE; 680 } 681 682 /* 683 * Function: 684 * _bcm_td2_l3_clear_hit 685 * Purpose: 686 * Clear hit bit on l3 entry 687 * Parameters: 688 * unit - (IN)SOC unit number. 689 * mem - (IN)L3 table memory. 690 * l3cfg - (IN)l3 entry info. 691 * l3x_entry - (IN)l3 entry filled hw buffer. 692 * Returns: 693 * BCM_E_XXX 694 */ 695 STATIC int 696 _bcm_td2_l3_clear_hit(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, 697 void *l3x_entry, int l3_entry_idx) 698 { 699 int ipv6; /* Entry is IPv6 flag. */ 700 int mcast; /* Entry is multicast flag. */ 701 uint32 *buf_p; /* HW buffer address. */ 702 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 703 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f }; 704 int idx; 705 706 /* Input parameters check */ 707 if ((NULL == l3cfg) || (NULL == l3x_entry)) { 708 return (BCM_E_PARAM); 709 } 710 711 /* Get entry type. */ 712 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 713 mcast = (l3cfg->l3c_flags & BCM_L3_IPMC); 714 715 /* Set table fields */ 716 #ifdef BCM_TOMAHAWK3_SUPPORT 717 if (SOC_IS_TOMAHAWK3(unit)) { 718 BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 719 } else 720 #endif 721 if (SOC_IS_TRIDENT3X(unit)) { 722 BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 723 } else { 724 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 725 } 726 727 /* Init memory pointers. */ 728 buf_p = (uint32 *)l3x_entry; 729 730 /* If entry was not hit there is nothing to clear */ 731 if (!(l3cfg->l3c_flags & BCM_L3_HIT)) { 732 return (BCM_E_NONE); 733 } 734 735 /* Reset hit bit. */ 736 soc_mem_field32_set(unit, mem, buf_p, fld->hit, 0); 737 738 if (ipv6 && mcast) { 739 /* IPV6 multicast entry hit reset. */ 740 for (idx = 0; idx < 4; idx++) { 741 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0); 742 } 743 } else if (ipv6 || mcast) { 744 /* Reset IPV6 unicast and IPV4 multicast hit bits. */ 745 for (idx = 0; idx < 2; idx++) { 746 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0); 747 } 748 } 749 750 /* Write entry back to hw. */ 751 return BCM_XGS3_MEM_WRITE(unit, mem, l3_entry_idx, buf_p); 752 } 753 754 /* 755 * Function: 756 * _bcm_td2_l3_entry_add 757 * Purpose: 758 * Add and entry to TD2 L3 host table. 759 * Parameters: 760 * unit - (IN) SOC unit number. 761 * l3cfg - (IN) L3 entry info. 762 * nh_idx - (IN) Next hop index. 763 * Returns: 764 * BCM_E_XXX 765 */ 766 STATIC int 767 _bcm_td2_l3_entry_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 768 { 769 770 int ipv6; 771 uint32 *bufp; /* Hardware buffer ptr */ 772 soc_mem_t mem; /* L3 table memory. */ 773 int rv = BCM_E_NONE; /* Operation status. */ 774 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 775 int embedded_nh = FALSE; 776 uint32 glp = 0, port_id = 0, modid = 0; 777 _bcm_l3_intf_cfg_t l3_intf; 778 l3_entry_ipv4_unicast_entry_t l3v4_entry; /* IPv4 */ 779 l3_entry_ipv4_multicast_entry_t l3v4_ext_entry; /* IPv4-Embedded */ 780 l3_entry_ipv6_unicast_entry_t l3v6_entry; /* IPv6 */ 781 l3_entry_ipv6_multicast_entry_t l3v6_ext_entry; /* IPv6-Embedded */ 782 uint32 port_addr_max = 0, modid_max = 0; 783 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_RIOT_SUPPORT) 784 int macda_oui_profile_index = -1; 785 #endif 786 #ifdef BCM_TOMAHAWK_SUPPORT 787 int macda_oui_profile_index1 = -1; 788 int vntag_etag_profile_index = 0; 789 int vntag_etag_profile_index1 = 0; 790 int ref_count = 0; 791 #endif 792 #ifdef BCM_RIOT_SUPPORT 793 int dvp = -1; 794 #endif 795 796 /* Get entry type. */ 797 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 798 799 /* Check if embedded NH table is being used */ 800 embedded_nh = BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx); 801 #ifdef BCM_TOMAHAWK3_SUPPORT 802 if (SOC_IS_TOMAHAWK3(unit)) 803 { 804 int ipmc = 0; 805 ipmc = (l3cfg->l3c_flags & BCM_L3_IPMC); 806 /* 807 * Get table memory. 808 */ 809 BCM_TH3_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, ipmc, mem, nh_idx); 810 811 /* 812 * Set table fields 813 */ 814 BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 815 816 /* 817 * Assign entry buf based on table being used 818 */ 819 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry); 820 } 821 else 822 #endif 823 #ifdef BCM_TRIDENT3_SUPPORT 824 if (SOC_IS_TRIDENT3X(unit)) 825 { 826 if (soc_feature(unit, soc_feature_flex_flow) && 827 (l3cfg->l3c_flow_handle != 0)) { 828 829 return _bcm_td3_l3_flex_entry_add(unit, l3cfg, nh_idx); 830 } 831 832 /* Get table memory. */ 833 BCM_TD3_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx); 834 835 /* Set table fields */ 836 BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 837 838 /* Assign entry buf based on table being used */ 839 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, 840 l3v4_entry, 841 l3v4_ext_entry, 842 l3v6_entry, 843 l3v6_ext_entry); 844 } else 845 #endif 846 { 847 /* Get table memory. */ 848 BCM_TD2_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx); 849 850 /* Set table fields */ 851 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 852 853 /* Assign entry buf based on table being used */ 854 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, 855 l3v4_entry, 856 l3v4_ext_entry, 857 l3v6_entry, 858 l3v6_ext_entry); 859 } 860 /* Prepare host entry for addition. */ 861 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, bufp)); 862 863 /* Set hit bit. */ 864 if (l3cfg->l3c_flags & BCM_L3_HIT) { 865 soc_mem_field32_set(unit, mem, bufp, fld->hit, 1); 866 } 867 868 /* Set priority override bit. */ 869 if (l3cfg->l3c_flags & BCM_L3_RPE) { 870 soc_mem_field32_set(unit, mem, bufp, fld->rpe, 1); 871 } 872 873 /* Set destination discard bit. */ 874 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 875 soc_mem_field32_set(unit, mem, bufp, fld->dst_discard, 1); 876 } 877 878 /* Set local addr bit. */ 879 if (l3cfg->l3c_flags & BCM_L3_HOST_LOCAL) { 880 soc_mem_field32_set(unit, mem, bufp, fld->local_addr, 1); 881 } 882 883 #ifdef BCM_MONTEREY_SUPPORT 884 /* Set Roe Header Decap control */ 885 if (soc_feature(unit, soc_feature_roe) || 886 soc_feature(unit, soc_feature_roe_custom)) { 887 if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) { 888 soc_mem_field32_set(unit, mem, bufp, fld->roe_decap, 1); 889 } 890 } 891 #endif 892 893 /* Set classification group id. */ 894 soc_mem_field32_set(unit, mem, bufp, fld->class_id, 895 l3cfg->l3c_lookup_class); 896 /* Set priority. */ 897 soc_mem_field32_set(unit, mem, bufp, fld->priority, l3cfg->l3c_prio); 898 899 if (embedded_nh) { 900 sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 901 BCM_XGS3_L3_INTF_IDX_SET(l3_intf, l3cfg->l3c_intf); 902 903 BCM_XGS3_L3_MODULE_LOCK(unit); 904 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf); 905 BCM_XGS3_L3_MODULE_UNLOCK(unit); 906 907 port_addr_max = SOC_PORT_ADDR_MAX(unit) + 1; 908 modid_max = SOC_MODID_MAX(unit) + 1; 909 #ifdef BCM_RIOT_SUPPORT 910 if ((BCMI_RIOT_IS_ENABLED(unit)) 911 && (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) { 912 _bcm_vp_vfi_type_vp_get(unit, l3cfg->l3c_port_tgid, &dvp); 913 } else 914 #endif 915 { 916 if (l3cfg->l3c_flags & BCM_L3_TGID) { 917 glp = (BCM_TGID_PORT_TRUNK_MASK(unit) & l3cfg->l3c_port_tgid); 918 #if defined(BCM_TRIDENT3_SUPPORT) 919 if (!SOC_IS_TRIDENT3X(unit)) { 920 glp |= (port_addr_max * modid_max); 921 } 922 #else 923 glp |= (port_addr_max * modid_max); 924 #endif 925 } else { 926 port_id = (SOC_PORT_ADDR_MAX(unit) & l3cfg->l3c_port_tgid); 927 modid = (SOC_MODID_MAX(unit) & l3cfg->l3c_modid) * port_addr_max; 928 glp = modid | port_id; 929 } 930 } 931 soc_mem_field32_set(unit, mem, bufp, fld->l3_intf, l3cfg->l3c_intf); 932 #ifdef BCM_TRIDENT3_SUPPORT 933 if (SOC_IS_TRIDENT3X(unit)) { 934 if (dvp != -1) { 935 soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 936 SOC_MEM_FIF_DEST_DVP, dvp); 937 } else { 938 uint32 dest_type; 939 if (l3cfg->l3c_flags & BCM_L3_TGID) { 940 dest_type = SOC_MEM_FIF_DEST_LAG; 941 } else { 942 dest_type = SOC_MEM_FIF_DEST_DGPP; 943 } 944 soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 945 dest_type, glp); 946 } 947 } else 948 #endif 949 { 950 #ifdef BCM_RIOT_SUPPORT 951 if (dvp != -1) { 952 soc_mem_field32_set(unit, mem, bufp, fld->dest_type, 1); 953 soc_mem_field32_set(unit, mem, bufp, fld->destination, dvp); 954 } else 955 #endif 956 { 957 soc_mem_field32_set(unit, mem, bufp, fld->glp, glp); 958 } 959 } 960 #ifdef BCM_TOMAHAWK_SUPPORT 961 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 962 if (l3cfg->l3c_flags & BCM_L3_REPLACE) { 963 /* For BCM_L3_REPLACE, get profile index for EGR_MACDA_OUI_PROFILE 964 * and EGR_VNTAG_ETAG_PROFILE table. Delete the profile entry if 965 * it's not used by any other host. 966 */ 967 rv = _bcm_th_get_extended_profile_index(unit, mem, l3cfg, 968 &macda_oui_profile_index, 969 &vntag_etag_profile_index, 970 &ref_count); 971 if (BCM_FAILURE(rv) && (rv!=BCM_E_NOT_FOUND)) { 972 return rv; 973 } 974 if (macda_oui_profile_index == -1) { 975 /* Host entry was done in regular L3_ENTRY table view */ 976 BCM_IF_ERROR_RETURN 977 (_bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp, 978 &macda_oui_profile_index1, 979 &vntag_etag_profile_index1)); 980 } else { 981 if (ref_count > 1) { 982 rv = _bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp, 983 &macda_oui_profile_index1, 984 &vntag_etag_profile_index1); 985 if (BCM_SUCCESS(rv)) { 986 BCM_IF_ERROR_RETURN 987 (_bcm_th_l3_vp_entry_del(unit, l3cfg, 988 macda_oui_profile_index, 989 vntag_etag_profile_index)); 990 } else { 991 return rv; 992 } 993 } else { 994 BCM_IF_ERROR_RETURN 995 (_bcm_th_l3_vp_entry_del(unit, l3cfg, 996 macda_oui_profile_index, 997 vntag_etag_profile_index)); 998 BCM_IF_ERROR_RETURN 999 (_bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp, 1000 &macda_oui_profile_index1, 1001 &vntag_etag_profile_index1)); 1002 1003 } 1004 } 1005 1006 } else { 1007 BCM_IF_ERROR_RETURN 1008 (_bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp, 1009 &macda_oui_profile_index1, 1010 &vntag_etag_profile_index1)); 1011 1012 } 1013 1014 } else 1015 #endif 1016 #if defined(BCM_RIOT_SUPPORT) 1017 if ((soc_feature(unit, soc_feature_riot)) && 1018 (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) { 1019 if (l3cfg->l3c_flags & BCM_L3_REPLACE) { 1020 BCM_IF_ERROR_RETURN 1021 (_bcm_td2p_l3_macda_oui_profile_entry_replace(unit, mem, l3cfg, bufp)); 1022 } else { 1023 BCM_IF_ERROR_RETURN 1024 (_bcm_td2p_l3_macda_oui_profile_entry_add(unit, mem, l3cfg, bufp, 1025 &macda_oui_profile_index)); 1026 } 1027 } else 1028 #endif 1029 { 1030 soc_mem_mac_addr_set(unit, mem, bufp, 1031 fld->mac_addr, l3cfg->l3c_mac_addr); 1032 } 1033 soc_mem_field32_set(unit, mem, bufp, 1034 fld->eh_tag_type, l3cfg->l3c_eh_q_tag_type); 1035 soc_mem_field32_set(unit, mem, bufp, 1036 fld->eh_queue_tag, l3cfg->l3c_eh_q_tag); 1037 1038 /* Set copy_to_cpu bit. */ 1039 if (l3cfg->l3c_flags & BCM_L3_COPY_TO_CPU) { 1040 if (SOC_MEM_FIELD_VALID(unit, mem, fld->copy_to_cpu)) { 1041 soc_mem_field32_set(unit, mem, bufp, fld->copy_to_cpu, 1); 1042 } 1043 } 1044 } else { 1045 /* Set next hop index. */ 1046 if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) { 1047 #ifdef BCM_TRIDENT3_SUPPORT 1048 if (SOC_IS_TRIDENT3X(unit)) { 1049 soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 1050 SOC_MEM_FIF_DEST_ECMP, nh_idx); 1051 } else 1052 #endif 1053 { 1054 1055 soc_mem_field32_set(unit, mem, bufp, ECMP_PTRf, nh_idx); 1056 soc_mem_field32_set(unit, mem, bufp, ECMPf, 1); 1057 } 1058 } else { 1059 #ifdef BCM_TRIDENT3_SUPPORT 1060 if (SOC_IS_TRIDENT3X(unit)) { 1061 soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 1062 SOC_MEM_FIF_DEST_NEXTHOP, nh_idx); 1063 } else 1064 #endif 1065 { 1066 soc_mem_field32_set(unit, mem, bufp, fld->nh_idx, nh_idx); 1067 } 1068 } 1069 } 1070 1071 /* Insert in table */ 1072 rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, bufp); 1073 1074 /* Handle host entry 'replace' actions */ 1075 if ((BCM_E_EXISTS == rv) && (l3cfg->l3c_flags & BCM_L3_REPLACE)) { 1076 rv = BCM_E_NONE; 1077 } 1078 1079 1080 #ifdef BCM_TOMAHAWK_SUPPORT 1081 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 1082 if (BCM_FAILURE(rv)) { 1083 /* if host add is not successful, then corresponding entries in the 1084 * profile table need to be removed for extended view hosts. 1085 */ 1086 BCM_IF_ERROR_RETURN 1087 (_bcm_th_l3_vp_entry_del(unit, l3cfg, 1088 macda_oui_profile_index1, 1089 vntag_etag_profile_index1)); 1090 } 1091 } 1092 #endif 1093 #if defined(BCM_RIOT_SUPPORT) 1094 if ((soc_feature(unit, soc_feature_riot)) && 1095 (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) { 1096 if (BCM_FAILURE(rv)) { 1097 /* if host add is not successful, then corresponding entries in the 1098 * profile table need to be removed for extended view hosts. 1099 */ 1100 BCM_IF_ERROR_RETURN 1101 (_bcm_td2p_l3_macda_oui_profile_entry_del(unit, l3cfg, macda_oui_profile_index)); 1102 } 1103 } 1104 #endif /* BCM_RIOT_SUPPORT */ 1105 1106 /* Write status check. */ 1107 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 1108 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++; 1109 } 1110 1111 return rv; 1112 } 1113 1114 1115 /* 1116 * Function: 1117 * _bcm_td2_l3_entry_get 1118 * Purpose: 1119 * Get an entry from TD2 3 host table. 1120 * Parameters: 1121 * unit - (IN) SOC unit number. 1122 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 1123 * nh_index - (IN/OUT) Next hop index. 1124 * embd - (OUT) If TRUE, entry was found as embedded NH. 1125 * Returns: 1126 * BCM_E_XXX 1127 */ 1128 STATIC int 1129 _bcm_td2_l3_entry_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int *embd) 1130 { 1131 int ipv6; /* IPv6 entry indicator. */ 1132 int clear_hit; /* Clear hit bit. */ 1133 int rv = BCM_E_NONE; /* Operation return status. */ 1134 soc_mem_t mem, mem_ext; /* L3 table memories */ 1135 uint32 *buf_key, *buf_entry; /* Key and entry buffer ptrs*/ 1136 l3_entry_ipv4_unicast_entry_t l3v4_key, l3v4_entry; /* IPv4 */ 1137 l3_entry_ipv4_multicast_entry_t l3v4_ext_key, l3v4_ext_entry; /* IPv4-Embedded */ 1138 l3_entry_ipv6_unicast_entry_t l3v6_key, l3v6_entry; /* IPv6 */ 1139 l3_entry_ipv6_multicast_entry_t l3v6_ext_key, l3v6_ext_entry; /* IPv6-Embedded */ 1140 1141 /* Indexed NH entry */ 1142 *embd = _BCM_TD2_HOST_ENTRY_NOT_FOUND; 1143 1144 /* Get entry type. */ 1145 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1146 1147 /* Preserve clear_hit value. */ 1148 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 1149 1150 /* Table memories */ 1151 if (ipv6) { 1152 mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4); 1153 } else { 1154 mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2); 1155 } 1156 #ifdef BCM_TOMAHAWK3_SUPPORT 1157 if (SOC_IS_TOMAHAWK3(unit)) { 1158 /* 1159 * Assign entry-key buf based on table being used 1160 */ 1161 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, l3v4_key, l3v4_ext_key, l3v6_key, l3v6_ext_key); 1162 1163 /* 1164 * Assign entry buf based on table being used 1165 */ 1166 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry); 1167 } else 1168 #endif 1169 #ifdef BCM_TRIDENT3_SUPPORT 1170 if (SOC_IS_TRIDENT3X(unit)) { 1171 if (soc_feature(unit, soc_feature_flex_flow) && 1172 (l3cfg->l3c_flow_handle != 0)) { 1173 1174 return _bcm_td3_l3_flex_entry_get(unit, l3cfg, nh_idx, embd); 1175 } 1176 1177 /* Assign entry-key buf based on table being used */ 1178 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, 1179 l3v4_key, 1180 l3v4_ext_key, 1181 l3v6_key, 1182 l3v6_ext_key); 1183 1184 /* Assign entry buf based on table being used */ 1185 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1186 l3v4_entry, 1187 l3v4_ext_entry, 1188 l3v6_entry, 1189 l3v6_ext_entry); 1190 } else 1191 #endif 1192 { 1193 /* Assign entry-key buf based on table being used */ 1194 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, 1195 l3v4_key, 1196 l3v4_ext_key, 1197 l3v6_key, 1198 l3v6_ext_key); 1199 1200 /* Assign entry buf based on table being used */ 1201 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1202 l3v4_entry, 1203 l3v4_ext_entry, 1204 l3v6_entry, 1205 l3v6_ext_entry); 1206 } 1207 /* Prepare lookup key. */ 1208 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, buf_key)); 1209 1210 /* Perform lookup */ 1211 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 1212 _BCM_TD2_L3_MEM_BANKS_ALL, 1213 buf_key, buf_entry, &l3cfg->l3c_hw_index); 1214 if (BCM_SUCCESS(rv)) { 1215 /* Indexed NH entry */ 1216 *embd = FALSE; 1217 /* Extract entry info. */ 1218 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_parse(unit, mem, l3cfg, 1219 nh_idx, buf_entry, 0)); 1220 /* Clear the HIT bit */ 1221 if (clear_hit) { 1222 BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, 1223 l3cfg, buf_entry, l3cfg->l3c_hw_index)); 1224 } 1225 } else if ((BCM_E_NOT_FOUND == rv) && 1226 (soc_feature(unit, soc_feature_l3_extended_host_entry))) { 1227 /* Search in the extended tables only if the extended host entry 1228 * feature is supported and if the entry was not found in the 1229 * regular host entry */ 1230 1231 #ifdef BCM_TOMAHAWK3_SUPPORT 1232 if (SOC_IS_TOMAHAWK3(unit)) 1233 { 1234 /* 1235 * Assign entry-key buf based on table being used 1236 */ 1237 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key, l3v4_key, l3v4_ext_key, l3v6_key, l3v6_ext_key); 1238 1239 /* 1240 * Assign entry buf based on table being used 1241 */ 1242 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 1243 l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry); 1244 } 1245 else 1246 #endif 1247 #ifdef BCM_TRIDENT3_SUPPORT 1248 if (SOC_IS_TRIDENT3X(unit)) 1249 { 1250 /* Assign entry-key buf based on table being used */ 1251 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key, 1252 l3v4_key, 1253 l3v4_ext_key, 1254 l3v6_key, 1255 l3v6_ext_key); 1256 1257 /* Assign entry buf based on table being used */ 1258 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 1259 l3v4_entry, 1260 l3v4_ext_entry, 1261 l3v6_entry, 1262 l3v6_ext_entry); 1263 } else 1264 #endif 1265 { 1266 /* Assign entry-key buf based on table being used */ 1267 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key, 1268 l3v4_key, 1269 l3v4_ext_key, 1270 l3v6_key, 1271 l3v6_ext_key); 1272 1273 /* Assign entry buf based on table being used */ 1274 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 1275 l3v4_entry, 1276 l3v4_ext_entry, 1277 l3v6_entry, 1278 l3v6_ext_entry); 1279 } 1280 1281 /* Prepare lookup key. */ 1282 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem_ext, l3cfg, buf_key)); 1283 1284 /* Perform lookup hw. */ 1285 rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY, 1286 _BCM_TD2_L3_MEM_BANKS_ALL, 1287 buf_key, buf_entry, &l3cfg->l3c_hw_index); 1288 1289 if (BCM_SUCCESS(rv)) { 1290 1291 /* Embedded NH entry */ 1292 *embd = TRUE; 1293 /* Extract entry info. */ 1294 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_parse(unit, mem_ext, l3cfg, 1295 nh_idx, buf_entry, 0)); 1296 /* Clear the HIT bit */ 1297 if (clear_hit) { 1298 BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem_ext, 1299 l3cfg, buf_entry, l3cfg->l3c_hw_index)); 1300 } 1301 } 1302 } 1303 1304 return rv; 1305 } 1306 1307 /* 1308 * Function: 1309 * _bcm_td2_l3_entry_del 1310 * Purpose: 1311 * Delete an entry from TD2 L3 host table. 1312 * Parameters: 1313 * unit - (IN) SOC unit number. 1314 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 1315 * nh_index - (IN/OUT) Next hop index. 1316 * Returns: 1317 * BCM_E_XXX 1318 */ 1319 STATIC int 1320 _bcm_td2_l3_entry_del(int unit, _bcm_l3_cfg_t *l3cfg) 1321 { 1322 int ipv6; /* IPv6 entry indicator.*/ 1323 soc_mem_t mem, mem_ext; /* L3 table memory. */ 1324 int rv = BCM_E_NONE; /* Operation status. */ 1325 uint32 *buf_entry; /* Entry buffer ptrs */ 1326 l3_entry_ipv4_unicast_entry_t l3v4_entry; /* IPv4 */ 1327 l3_entry_ipv4_multicast_entry_t l3v4_ext_entry; /* IPv4-Embedded */ 1328 l3_entry_ipv6_unicast_entry_t l3v6_entry; /* IPv6 */ 1329 l3_entry_ipv6_multicast_entry_t l3v6_ext_entry; /* IPv6-Embedded */ 1330 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_RIOT_SUPPORT) 1331 int macda_oui_profile_index = -1; 1332 int ref_count = 0; 1333 #endif 1334 1335 #ifdef BCM_TOMAHAWK_SUPPORT 1336 int vntag_etag_profile_index = 0; 1337 #endif 1338 1339 /* Get entry type. */ 1340 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1341 1342 if (ipv6) { 1343 mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4); 1344 } else { 1345 mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2); 1346 } 1347 1348 #ifdef BCM_TRIDENT3_SUPPORT 1349 if (soc_feature(unit, soc_feature_flex_flow) && 1350 (l3cfg->l3c_flow_handle != 0)) { 1351 return _bcm_td3_l3_flex_entry_del(unit, l3cfg); 1352 } 1353 /* Assign entry-key buf based on table being used */ 1354 if (SOC_IS_TRIDENT3X(unit)) { 1355 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1356 l3v4_entry, 1357 l3v4_ext_entry, 1358 l3v6_entry, 1359 l3v6_ext_entry); 1360 } else 1361 #endif 1362 { 1363 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1364 l3v4_entry, 1365 l3v4_ext_entry, 1366 l3v6_entry, 1367 l3v6_ext_entry); 1368 } 1369 /* Prepare lookup key. */ 1370 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, buf_entry)); 1371 1372 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void*) buf_entry); 1373 1374 if (rv >= 0) { 1375 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--; 1376 } 1377 1378 if ((BCM_E_NOT_FOUND == rv) && 1379 (soc_feature(unit, soc_feature_l3_extended_host_entry))) { 1380 /* Delete from the extended tables only if the extended host entry 1381 * feature is supported and if the entry was not found in the 1382 * regular host entry */ 1383 1384 #ifdef BCM_TOMAHAWK_SUPPORT 1385 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 1386 BCM_IF_ERROR_RETURN 1387 (_bcm_th_get_extended_profile_index(unit, mem_ext, l3cfg, 1388 &macda_oui_profile_index, 1389 &vntag_etag_profile_index, 1390 &ref_count)); 1391 } 1392 #endif 1393 1394 #if defined(BCM_RIOT_SUPPORT) 1395 if ((soc_feature(unit, soc_feature_riot)) && 1396 (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) { 1397 BCM_IF_ERROR_RETURN 1398 (_bcm_td2p_l3_get_macda_oui_profile_index(unit, mem_ext, l3cfg, 1399 &macda_oui_profile_index, 1400 &ref_count)); 1401 } 1402 #endif 1403 /* Assign entry-key buf based on table being used */ 1404 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 1405 l3v4_entry, 1406 l3v4_ext_entry, 1407 l3v6_entry, 1408 l3v6_ext_entry); 1409 /* Prepare lookup key. */ 1410 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem_ext, l3cfg, buf_entry)); 1411 1412 rv = soc_mem_delete(unit, mem_ext, MEM_BLOCK_ANY, (void*) buf_entry); 1413 1414 if (rv >= 0) { 1415 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--; 1416 1417 #ifdef BCM_TOMAHAWK_SUPPORT 1418 BCM_IF_ERROR_RETURN 1419 (_bcm_th_l3_vp_entry_del(unit, l3cfg, 1420 macda_oui_profile_index, 1421 vntag_etag_profile_index)); 1422 #endif 1423 #if defined(BCM_RIOT_SUPPORT) 1424 if ((soc_feature(unit, soc_feature_riot)) && 1425 (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) { 1426 BCM_IF_ERROR_RETURN 1427 (_bcm_td2p_l3_macda_oui_profile_entry_del(unit, l3cfg, 1428 macda_oui_profile_index)); 1429 } 1430 #endif 1431 } 1432 } 1433 1434 return rv; 1435 } 1436 1437 int 1438 _bcm_td2_ip_key_to_l3cfg(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg) 1439 { 1440 int ipv6; /* IPV6 key. */ 1441 1442 /* Input parameters check */ 1443 if ((NULL == ipkey) || (NULL == l3cfg)) { 1444 return (BCM_E_PARAM); 1445 } 1446 1447 /* Reset destination buffer first. */ 1448 sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1449 1450 l3cfg->l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 1451 l3cfg->l3c_ing_intf = BCM_IF_INVALID; 1452 1453 ipv6 = (ipkey->l3k_flags & BCM_L3_IP6); 1454 1455 /* Set vrf id. */ 1456 l3cfg->l3c_vrf = ipkey->l3k_vrf; 1457 l3cfg->l3c_vid = ipkey->l3k_vid; 1458 1459 if (ipv6) { 1460 if (BCM_IP6_MULTICAST(ipkey->l3k_ip6_addr)) { 1461 /* Copy ipv6 group, source & vid. */ 1462 sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t)); 1463 sal_memcpy(l3cfg->l3c_sip6, ipkey->l3k_sip6_addr, 1464 sizeof(bcm_ip6_t)); 1465 l3cfg->l3c_vid = ipkey->l3k_vid; 1466 l3cfg->l3c_flags = (BCM_L3_IP6 | BCM_L3_IPMC); 1467 } else { 1468 /* Copy ipv6 address. */ 1469 sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t)); 1470 l3cfg->l3c_flags = BCM_L3_IP6; 1471 } 1472 } else { 1473 if (BCM_IP4_MULTICAST(ipkey->l3k_ip_addr)) { 1474 /* Copy ipv4 mcast group, source & vid. */ 1475 l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr; 1476 l3cfg->l3c_src_ip_addr = ipkey->l3k_sip_addr; 1477 l3cfg->l3c_vid = ipkey->l3k_vid; 1478 l3cfg->l3c_flags = BCM_L3_IPMC; 1479 } else { 1480 /* Copy ipv4 address . */ 1481 l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr; 1482 } 1483 } 1484 return (BCM_E_NONE); 1485 } 1486 1487 int 1488 _bcm_td2_l3cfg_to_ipkey(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg) 1489 { 1490 /* Input parameters check */ 1491 if ((NULL == ipkey) || (NULL == l3cfg)) { 1492 return (BCM_E_PARAM); 1493 } 1494 1495 /* Reset destination buffer first. */ 1496 sal_memset(ipkey, 0, sizeof(bcm_l3_key_t)); 1497 1498 ipkey->l3k_vrf = l3cfg->l3c_vrf; 1499 ipkey->l3k_vid = l3cfg->l3c_vid; 1500 1501 if (l3cfg->l3c_flags & BCM_L3_IP6) { 1502 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 1503 /* Copy ipv6 group, source & vid. */ 1504 sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 1505 sal_memcpy(ipkey->l3k_sip6_addr, l3cfg->l3c_sip6, 1506 sizeof(bcm_ip6_t)); 1507 ipkey->l3k_vid = l3cfg->l3c_vid; 1508 } else { 1509 /* Copy ipv6 address. */ 1510 sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 1511 } 1512 } else { 1513 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 1514 /* Copy ipv4 mcast group, source & vid. */ 1515 ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr; 1516 ipkey->l3k_sip_addr = l3cfg->l3c_src_ip_addr; 1517 ipkey->l3k_vid = l3cfg->l3c_vid; 1518 } else { 1519 /* Copy ipv4 address . */ 1520 ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr; 1521 } 1522 } 1523 /* Store entry flags. */ 1524 ipkey->l3k_flags = l3cfg->l3c_flags; 1525 return (BCM_E_NONE); 1526 } 1527 1528 int 1529 bcm_td2_l3_conflict_get(int unit, bcm_l3_key_t *ipkey, bcm_l3_key_t *cf_array, 1530 int cf_max, int *cf_count) 1531 { 1532 _bcm_l3_cfg_t l3cfg; 1533 uint32 *bufp; /* Hardware buffer ptr */ 1534 soc_mem_t mem; /* L3 table memory type. */ 1535 int nh_idx, index, rv = BCM_E_NONE; /* Operation status. */ 1536 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 1537 l3_entry_ipv4_unicast_entry_t l3v4_entry; 1538 l3_entry_ipv4_multicast_entry_t l3v4_ext_entry; 1539 l3_entry_ipv6_unicast_entry_t l3v6_entry; 1540 l3_entry_ipv6_multicast_entry_t l3v6_ext_entry; 1541 uint8 i,num_ent; 1542 uint32 l3_entry[SOC_MAX_MEM_WORDS]; 1543 uint32 ipmc, ipv6, embedded_nh; 1544 uint32 bucket; 1545 int num_banks, max_bank = 9; 1546 int hash_offset = 0, use_lsb = 0, bidx = 0; 1547 1548 /* Make sure module was initialized. */ 1549 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 1550 return (BCM_E_INIT); 1551 } 1552 1553 /* Input parameters check. */ 1554 if ((NULL == ipkey) || (NULL == cf_count) || 1555 (NULL == cf_array) || (cf_max <= 0)) { 1556 return (BCM_E_PARAM); 1557 } 1558 1559 embedded_nh = ipkey->l3k_flags & BCM_L3_DEREFERENCED_NEXTHOP; 1560 nh_idx = (embedded_nh) ? BCM_XGS3_L3_INVALID_INDEX : 0; 1561 1562 /* Translate lookup key to l3cfg format. */ 1563 BCM_IF_ERROR_RETURN(_bcm_td2_ip_key_to_l3cfg(unit, ipkey, &l3cfg)); 1564 1565 /* Get entry type. */ 1566 ipv6 = (l3cfg.l3c_flags & BCM_L3_IP6); 1567 ipmc = (l3cfg.l3c_flags & BCM_L3_IPMC); 1568 1569 #ifdef BCM_TOMAHAWK3_SUPPORT 1570 if (SOC_IS_TOMAHAWK3(unit)) 1571 { 1572 /* 1573 * Get table memory. 1574 */ 1575 BCM_TH3_L3_HOST_TABLE_MEM(unit, l3cfg.l3c_intf, ipv6, ipmc, mem, nh_idx); 1576 BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1577 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry); 1578 max_bank = 3; 1579 } else 1580 #endif 1581 { 1582 /* Get table memory. */ 1583 BCM_TD2_L3_HOST_TABLE_MEM(unit, l3cfg.l3c_intf, ipv6, mem, nh_idx); 1584 1585 /* Bump up the size conditionally */ 1586 mem = (embedded_nh || ipmc) ? (ipv6 ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm) : mem; 1587 1588 /* Set table fields */ 1589 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1590 1591 /* Assign entry buf based on table being used */ 1592 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, 1593 l3v4_entry, 1594 l3v4_ext_entry, 1595 l3v6_entry, 1596 l3v6_ext_entry); 1597 } 1598 /* Prepare host entry for addition. */ 1599 if (ipmc) { 1600 /* Zero entry buffer. */ 1601 sal_memcpy(bufp, soc_mem_entry_null(unit, mem), 1602 soc_mem_entry_words(unit,mem) * 4); 1603 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ipmc_ent_init(unit, bufp, &l3cfg)); 1604 } else { 1605 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, &l3cfg, bufp)); 1606 } 1607 1608 *cf_count = 0; 1609 1610 /* Get entries of each banks */ 1611 switch (mem) 1612 { 1613 case L3_ENTRY_IPV4_UNICASTm: 1614 case L3_ENTRY_SINGLEm: 1615 num_ent = 4; 1616 break; 1617 case L3_ENTRY_IPV6_UNICASTm: 1618 case L3_ENTRY_IPV4_MULTICASTm: 1619 case L3_ENTRY_DOUBLEm: 1620 num_ent = 2; 1621 break; 1622 case L3_ENTRY_IPV6_MULTICASTm: 1623 case L3_ENTRY_QUADm: 1624 num_ent = 1; 1625 break; 1626 1627 /* coverity[dead_error_begin] */ 1628 default: 1629 return BCM_E_PARAM; 1630 } 1631 1632 1633 1634 /* Get number of L3 banks */ 1635 #ifdef BCM_TOMAHAWK_SUPPORT 1636 #ifdef BCM_TOMAHAWK3_SUPPORT 1637 if (SOC_IS_TOMAHAWK3(unit)) { 1638 SOC_IF_ERROR_RETURN(soc_tomahawk3_hash_bank_count_get(unit, mem, &num_banks)); 1639 } else 1640 #endif /* BCM_TOMAHAWK3_SUPPORT */ 1641 if (SOC_IS_TOMAHAWKX(unit)) { 1642 SOC_IF_ERROR_RETURN(soc_tomahawk_hash_bank_count_get(unit, mem, &num_banks)); 1643 } else 1644 #endif /* BCM_TOMAHAWK_SUPPORT */ 1645 #ifdef BCM_APACHE_SUPPORT 1646 if (SOC_IS_APACHE(unit)) { 1647 SOC_IF_ERROR_RETURN 1648 (soc_apache_hash_bank_count_get(unit, mem, &num_banks)); 1649 } else 1650 #endif /* BCM_TOMAHAWK_SUPPORT */ 1651 #ifdef BCM_HELIX5_SUPPORT 1652 if (SOC_IS_HELIX5(unit)) { 1653 SOC_IF_ERROR_RETURN 1654 (soc_helix5_hash_bank_count_get(unit, mem, &num_banks)); 1655 } else 1656 #endif /* BCM_HELIX5_SUPPORT */ 1657 #ifdef BCM_TRIDENT3_SUPPORT 1658 if (SOC_IS_TRIDENT3X(unit)) { 1659 SOC_IF_ERROR_RETURN 1660 (soc_trident3_hash_bank_count_get(unit, mem, &num_banks)); 1661 } else 1662 #endif /* BCM_TRIDENT3_SUPPORT */ 1663 1664 { 1665 SOC_IF_ERROR_RETURN 1666 (soc_trident2_hash_bank_count_get(unit, mem, &num_banks)); 1667 } 1668 1669 /* bank 9 to 6 are dedicated L3 banks, 5 to 3 are dedicated, depends on 1670 * mode how many shared banks are assigned to l3 1671 */ 1672 for (bidx = max_bank; bidx >= (max_bank - num_banks + 1); bidx--) { 1673 /* Calculate hash index */ 1674 #ifdef BCM_APACHE_SUPPORT 1675 if (SOC_IS_APACHE(unit)) { 1676 rv = soc_ap_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, 1677 &use_lsb); 1678 } else 1679 #endif /* BCM_APACHE_SUPPORT */ 1680 #ifdef BCM_TOMAHAWK_SUPPORT 1681 #ifdef BCM_TOMAHAWK3_SUPPORT 1682 if (SOC_IS_TOMAHAWK3(unit)) { 1683 rv = soc_tomahawk3_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, &use_lsb); 1684 } else 1685 #endif /* BCM_TOMAHAWK3_SUPPORT */ 1686 1687 if (SOC_IS_TOMAHAWKX(unit)) { 1688 rv = soc_th_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, 1689 &use_lsb); 1690 } else 1691 #endif /* BCM_TOMAHAWK_SUPPORT */ 1692 #ifdef BCM_HELIX5_SUPPORT 1693 if (SOC_IS_HELIX5(unit)) { 1694 rv = soc_hx5_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, 1695 &use_lsb); 1696 } else 1697 #endif /* BCM_HELIX5_SUPPORT */ 1698 #ifdef BCM_TRIDENT3_SUPPORT 1699 if (SOC_IS_TRIDENT3X(unit)) { 1700 rv = soc_td3_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, 1701 &use_lsb); 1702 } else 1703 #endif /* BCM_TRIDENT3_SUPPORT */ 1704 { 1705 rv = soc_td2_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, 1706 &use_lsb); 1707 } 1708 1709 if (BCM_FAILURE(rv)) { 1710 return BCM_E_INTERNAL; 1711 } 1712 1713 /* coverity[overrun-buffer-val: FALSE] */ 1714 #ifdef BCM_APACHE_SUPPORT 1715 if (SOC_IS_APACHE(unit)) { 1716 bucket = soc_ap_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp); 1717 index = soc_ap_hash_index_get(unit, mem, bidx, bucket); 1718 } else 1719 #endif /* BCM_APACHE_SUPPORT */ 1720 #ifdef BCM_TOMAHAWK3_SUPPORT 1721 if (SOC_IS_TOMAHAWK3(unit)) { 1722 bucket = soc_tomahawk3_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp); 1723 index = soc_tomahawk3_hash_index_get(unit, mem, bidx, bucket); 1724 } else 1725 #endif /* BCM_TOMAHAWK3_SUPPORT */ 1726 #ifdef BCM_TOMAHAWK_SUPPORT 1727 if (SOC_IS_TOMAHAWKX(unit)) { 1728 bucket = soc_th_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp); 1729 index = soc_th_hash_index_get(unit, mem, bidx, bucket); 1730 } else 1731 #endif /* BCM_TOMAHAWK_SUPPORT */ 1732 #ifdef BCM_HELIX5_SUPPORT 1733 if (SOC_IS_HELIX5(unit)) { 1734 bucket = soc_hx5_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp); 1735 index = soc_hx5_hash_index_get(unit, mem, bidx, bucket); 1736 } else 1737 #endif /* BCM_HELIX5_SUPPORT */ 1738 #ifdef BCM_TRIDENT3_SUPPORT 1739 if (SOC_IS_TRIDENT3X(unit)) { 1740 bucket = soc_td3_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp); 1741 index = soc_td3_hash_index_get(unit, mem, bidx, bucket); 1742 } else 1743 #endif /* BCM_TRIDENT3_SUPPORT */ 1744 { 1745 bucket = soc_td2_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp); 1746 index = soc_hash_index_get(unit, mem, bidx, bucket); 1747 } 1748 1749 /* Get conflicting IPs from all HW entries in current bank */ 1750 for (i = 0; (i < num_ent) && (*cf_count < cf_max);) { 1751 rv = soc_mem_read(unit, mem, COPYNO_ALL, index + i, l3_entry); 1752 if (SOC_FAILURE(rv)) { 1753 return BCM_E_MEMORY; 1754 } 1755 if (soc_mem_field32_get(unit, mem, &l3_entry, fld->valid)) { 1756 switch(soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type)) { 1757 case TD2_L3_HASH_KEY_TYPE_V4UC: 1758 l3cfg.l3c_flags = 0; 1759 break; 1760 case TD2_L3_HASH_KEY_TYPE_V4UC_EXT: 1761 l3cfg.l3c_flags = BCM_L3_DEREFERENCED_NEXTHOP; 1762 break; 1763 case TD2_L3_HASH_KEY_TYPE_V4MC: 1764 l3cfg.l3c_flags = BCM_L3_IPMC; 1765 break; 1766 case TD2_L3_HASH_KEY_TYPE_V6UC: 1767 l3cfg.l3c_flags = BCM_L3_IP6; 1768 break; 1769 case TD2_L3_HASH_KEY_TYPE_V6UC_EXT: 1770 l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_DEREFERENCED_NEXTHOP; 1771 break; 1772 case TD2_L3_HASH_KEY_TYPE_V6MC: 1773 l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 1774 break; 1775 case TD2_L3_HASH_KEY_TYPE_V4L2MC: 1776 case TD2_L3_HASH_KEY_TYPE_V4L2VPMC: 1777 l3cfg.l3c_flags = BCM_L3_IPMC | BCM_L3_L2ONLY; 1778 break; 1779 case TD2_L3_HASH_KEY_TYPE_V6L2MC: 1780 case TD2_L3_HASH_KEY_TYPE_V6L2VPMC: 1781 l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC | BCM_L3_L2ONLY; 1782 default: 1783 break; 1784 } 1785 /* Get host ip address. */ 1786 rv = _bcm_td2_l3_get_by_idx(unit, NULL, index + i, &l3cfg, &nh_idx); 1787 if (BCM_FAILURE(rv)) { 1788 continue; 1789 } 1790 1791 BCM_IF_ERROR_RETURN 1792 (_bcm_td2_l3cfg_to_ipkey(unit, cf_array + (*cf_count), &l3cfg)); 1793 if ((++(*cf_count)) >= cf_max) { 1794 break; 1795 } 1796 } 1797 /* increment based upon existing entry */ 1798 i += (mem == ((SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_MULTICASTm))?L3_ENTRY_IPV6_MULTICASTm:L3_ENTRY_DOUBLEm)) ? 2 : 1; 1799 } 1800 1801 /* Stop loop if conflicting IPs got from HW is no less than cf_max. */ 1802 if ((*cf_count) >= cf_max) { 1803 break; 1804 } 1805 } 1806 return BCM_E_NONE; 1807 } 1808 1809 1810 1811 /* 1812 * Function: 1813 * _bcm_td2_l3_get_host_ent_by_idx 1814 * Purpose: 1815 * Parameters: 1816 * unit - (IN)SOC unit number. 1817 * dma_ptr - (IN)Table pointer in dma. 1818 * soc_mem_ - (IN)Table memory. 1819 * idx - (IN)Index to read. 1820 * l3cfg - (OUT)l3 entry search result. 1821 * nh_index - (OUT)Next hop index. 1822 * Returns: 1823 * BCM_E_XXX 1824 */ 1825 STATIC int 1826 _bcm_td2_l3_get_host_ent_by_idx(int unit, void *dma_ptr, soc_mem_t mem, 1827 int idx, _bcm_l3_cfg_t *l3cfg, int *nh_idx) 1828 { 1829 uint32 ipv6; /* IPv6 entry indicator. */ 1830 int key_type; 1831 int clear_hit; /* Clear hit bit flag. */ 1832 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 1833 uint32 valid, base_valid_bits = 1; 1834 uint32 *buf_entry; /* Key and entry buffer ptrs*/ 1835 l3_entry_ipv4_unicast_entry_t l3v4_entry; /* IPv4 */ 1836 l3_entry_ipv4_multicast_entry_t l3v4_ext_entry; /* IPv4-Embedded */ 1837 l3_entry_ipv6_unicast_entry_t l3v6_entry; /* IPv6 */ 1838 l3_entry_ipv6_multicast_entry_t l3v6_ext_entry; /* IPv6-Embedded */ 1839 soc_field_t uc_ipv6_lwr = INVALIDf, uc_ipv6_upr = INVALIDf; 1840 soc_field_t data_type = 44; 1841 #ifdef BCM_TRIDENT3_SUPPORT 1842 int rv = BCM_E_NOT_FOUND; 1843 uint32 view_id = 0; 1844 #endif 1845 /* Get entry type. */ 1846 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1847 /* Get clear hit flag. */ 1848 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 1849 1850 #ifdef BCM_TOMAHAWK3_SUPPORT 1851 if (SOC_IS_TOMAHAWK3(unit)) 1852 { 1853 BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1854 BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry); 1855 } 1856 else 1857 #endif 1858 #ifdef BCM_TRIDENT3_SUPPORT 1859 if (SOC_IS_TRIDENT3X(unit)) { 1860 BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1861 BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1862 l3v4_entry, 1863 l3v4_ext_entry, 1864 l3v6_entry, 1865 l3v6_ext_entry); 1866 } else 1867 1868 #endif 1869 { 1870 1871 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1872 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1873 l3v4_entry, 1874 l3v4_ext_entry, 1875 l3v6_entry, 1876 l3v6_ext_entry); 1877 } 1878 1879 1880 if (NULL == dma_ptr) { /* Read from hardware. */ 1881 /* Zero buffers. */ 1882 sal_memset(buf_entry, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 1883 1884 /* Read entry from hw. */ 1885 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_entry)); 1886 } else { /* Read from dma. */ 1887 buf_entry = soc_mem_table_idx_to_pointer(unit, mem, 1888 uint32 *, dma_ptr, idx); 1889 } 1890 1891 valid = soc_mem_field32_get(unit, mem, buf_entry, fld->valid); 1892 key_type = soc_mem_field32_get(unit, mem, buf_entry, fld->key_type); 1893 base_valid_bits = 1; 1894 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 1895 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) { 1896 if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) { 1897 data_type = soc_mem_field32_get(unit, mem, buf_entry, DATA_TYPEf); 1898 switch(mem) { 1899 case L3_ENTRY_SINGLEm: 1900 base_valid_bits = 1; 1901 break; 1902 case L3_ENTRY_DOUBLEm: 1903 if ((key_type == 0) || 1904 ((key_type == (int)TD2_L3_HASH_KEY_TYPE_V6UC) && 1905 (SOC_IS_TOMAHAWK3(unit)))) { 1906 base_valid_bits = 1; 1907 } else { 1908 base_valid_bits = 3; 1909 } 1910 break; 1911 case L3_ENTRY_QUADm: 1912 if (SOC_IS_TRIDENT3X(unit)) { 1913 if ((key_type == (int)TD3_L3_HASH_KEY_TYPE_V6UC_EXT) && 1914 (data_type == TD3_L3_HASH_DATA_TYPE_V6UC_EXT)) { 1915 base_valid_bits = 3; 1916 } else { 1917 base_valid_bits = 5; 1918 } 1919 } else if ((key_type == (int)TD2_L3_HASH_KEY_TYPE_V6MC) || 1920 (SOC_IS_TOMAHAWK3(unit))) { 1921 base_valid_bits = 1; 1922 } 1923 break; 1924 default: 1925 break; 1926 } 1927 } 1928 } 1929 #endif 1930 #if defined(BCM_TRIDENT3_SUPPORT) 1931 if (soc_feature(unit, soc_feature_flex_flow)) { 1932 soc_flow_db_ffo_t ffo[SOC_FLOW_DB_MAX_VIEW_FFO_TPL]; 1933 uint32 num_ffo = 0; 1934 1935 rv = soc_flow_db_mem_to_view_id_get(unit, 1936 mem, 1937 SOC_FLOW_DB_KEY_TYPE_INVALID, 1938 data_type, 1939 0, 1940 NULL, 1941 &view_id); 1942 if (rv == BCM_E_NONE) { 1943 /* get the flow handle, function id, option id */ 1944 BCM_IF_ERROR_RETURN( 1945 soc_flow_db_mem_view_to_ffo_get(unit, 1946 view_id, 1947 SOC_FLOW_DB_MAX_VIEW_FFO_TPL, 1948 ffo, 1949 &num_ffo)); 1950 l3cfg->l3c_flow_handle = ffo[0].flow_handle; 1951 l3cfg->l3c_flow_option_handle = ffo[0].option_id; 1952 } 1953 } 1954 #endif 1955 if(valid != base_valid_bits) { 1956 if (valid) { 1957 base_valid_bits = 1; 1958 } 1959 return (BCM_E_NOT_FOUND); 1960 } 1961 1962 l3cfg->l3c_flags = 0; 1963 switch (mem) { 1964 case L3_ENTRY_IPV4_UNICASTm: 1965 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 1966 case L3_ENTRY_SINGLEm: 1967 #endif 1968 if (!(soc_feature(unit, soc_feature_flex_flow)) && 1969 ((key_type != TD2_L3_HASH_KEY_TYPE_V4UC) || 1970 ((SOC_IS_TRIDENT3X(unit)) && (mem == L3_ENTRY_SINGLEm) && (data_type != 0)))) { 1971 /* All other keys are invalid */ 1972 return BCM_E_NOT_FOUND; 1973 } 1974 #ifdef BCM_TRIDENT3_SUPPORT 1975 /* In TD3, can't distinguish regular from extended entries as 1976 * in previous chips. Hence check for next entry BASE_VALID field 1977 * to check for extended entries */ 1978 if (SOC_IS_TRIDENT3X(unit) && (idx != soc_mem_index_max(unit, 1979 L3_ENTRY_SINGLEm))) { 1980 l3_entry_ipv4_unicast_entry_t td3_l3v4_entry; 1981 uint32 *td3_buf_entry = (uint32 *) &td3_l3v4_entry; 1982 1983 if (NULL == dma_ptr) { /* Read from hardware. */ 1984 /* Zero buffers. */ 1985 sal_memset(td3_buf_entry, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 1986 1987 /* Read entry from hw. */ 1988 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx + 1, 1989 td3_buf_entry)); 1990 } else { /* Read from dma. */ 1991 td3_buf_entry = soc_mem_table_idx_to_pointer(unit, mem, 1992 uint32 *, dma_ptr, idx + 1); 1993 } 1994 1995 valid = soc_mem_field32_get(unit, mem, td3_buf_entry, fld->valid); 1996 if (valid == 7) { 1997 return BCM_E_NOT_FOUND; 1998 } 1999 } 2000 #endif 2001 break; 2002 case L3_ENTRY_IPV4_MULTICASTm: 2003 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 2004 case L3_ENTRY_DOUBLEm: 2005 #endif 2006 if (key_type == TD2_L3_HASH_KEY_TYPE_V4MC) { 2007 l3cfg->l3c_flags = BCM_L3_IPMC; 2008 } else if (((key_type == TD2_L3_HASH_KEY_TYPE_V4UC) && 2009 (mem == L3_ENTRY_DOUBLEm) && (data_type == 1)) || 2010 ((key_type == TD2_L3_HASH_KEY_TYPE_V4UC_EXT) && (mem != L3_ENTRY_DOUBLEm))){ 2011 l3cfg->l3c_flags = 0; 2012 } else if ((key_type == TD2_L3_HASH_KEY_TYPE_V4L2MC) || 2013 (key_type == TD2_L3_HASH_KEY_TYPE_V4L2VPMC)) { 2014 l3cfg->l3c_flags = BCM_L3_IPMC | BCM_L3_L2ONLY; 2015 } else if ((key_type == TD2_L3_HASH_KEY_TYPE_V6UC) && 2016 (((mem == L3_ENTRY_DOUBLEm) && 2017 (SOC_IS_TOMAHAWK3(unit) || (data_type == 2))) || 2018 (mem != L3_ENTRY_DOUBLEm))){ 2019 2020 l3cfg->l3c_flags = BCM_L3_IP6; 2021 if (mem == L3_ENTRY_DOUBLEm) { 2022 uc_ipv6_lwr = IPV6UC__IP_ADDR_LWR_64f; 2023 uc_ipv6_upr = IPV6UC__IP_ADDR_UPR_64f; 2024 } else { 2025 uc_ipv6_lwr = IP_ADDR_LWR_64f; 2026 uc_ipv6_upr = IP_ADDR_UPR_64f; 2027 } 2028 } else { 2029 #if defined(BCM_TRIDENT3_SUPPORT) 2030 if ((SOC_IS_TRIDENT3X(unit)) && (rv == BCM_E_NONE)) { 2031 /* If it is a flex entry in TD3X, do not return error */ 2032 } else 2033 #endif 2034 { 2035 return BCM_E_NOT_FOUND; 2036 } 2037 } 2038 break; 2039 case L3_ENTRY_IPV6_UNICASTm: 2040 if (key_type == TD2_L3_HASH_KEY_TYPE_V6UC) { 2041 l3cfg->l3c_flags = BCM_L3_IP6; 2042 uc_ipv6_lwr = IP_ADDR_LWR_64f; 2043 uc_ipv6_upr = IP_ADDR_UPR_64f; 2044 } else { 2045 return BCM_E_NOT_FOUND; 2046 } 2047 break; 2048 case L3_ENTRY_IPV6_MULTICASTm: 2049 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 2050 case L3_ENTRY_QUADm: 2051 #endif 2052 uc_ipv6_lwr = IPV6UC_EXT__IP_ADDR_LWR_64f; 2053 uc_ipv6_upr = IPV6UC_EXT__IP_ADDR_UPR_64f; 2054 if (key_type == TD2_L3_HASH_KEY_TYPE_V6MC) { 2055 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 2056 } if ((key_type == TD2_L3_HASH_KEY_TYPE_V6UC_EXT)) { 2057 l3cfg->l3c_flags = BCM_L3_IP6; 2058 } else if ((key_type == TD2_L3_HASH_KEY_TYPE_V6L2MC) || 2059 (key_type == TD2_L3_HASH_KEY_TYPE_V6L2VPMC)) { 2060 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC | BCM_L3_L2ONLY; 2061 } 2062 #ifdef BCM_TRIDENT3_SUPPORT 2063 else if (SOC_IS_TRIDENT3X(unit) && (key_type == 2064 TD3_L3_HASH_KEY_TYPE_V6UC_EXT) && (data_type == 2065 TD3_L3_HASH_DATA_TYPE_V6UC_EXT)) { 2066 l3cfg->l3c_flags = BCM_L3_IP6; 2067 } 2068 #endif 2069 else { 2070 #if defined(BCM_TRIDENT3_SUPPORT) 2071 if ((soc_feature(unit, soc_feature_flex_flow)) && (rv == BCM_E_NONE)) { 2072 /* TD3X flex entry */ 2073 if (SOC_MEM_FIELD_VALID(unit, view_id, IPV6__DIPf)) { 2074 l3cfg->l3c_flags = BCM_L3_IP6; 2075 soc_mem_ip6_addr_get(unit, view_id, buf_entry,IPV6__DIPf, l3cfg->l3c_ip6, 0); 2076 } else if (SOC_MEM_FIELD_VALID(unit, view_id, IPV6__SIPf)) { 2077 l3cfg->l3c_flags = BCM_L3_IP6; 2078 soc_mem_ip6_addr_get(unit, view_id, buf_entry,IPV6__SIPf, l3cfg->l3c_ip6, 0); 2079 } 2080 } else 2081 #endif 2082 { 2083 return BCM_E_NOT_FOUND; 2084 } 2085 } 2086 break; 2087 default : 2088 return BCM_E_NOT_FOUND; 2089 } 2090 2091 /* Ignore protocol mismatch & multicast entries. */ 2092 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 2093 (l3cfg->l3c_flags & BCM_L3_IPMC)) { 2094 return (BCM_E_NONE); 2095 } 2096 2097 if (ipv6) { 2098 #if defined(BCM_TRIDENT3_SUPPORT) 2099 if (!(soc_feature(unit, soc_feature_flex_flow) && (rv == BCM_E_NONE))) 2100 #endif 2101 {/* Extract host info from the entry. */ 2102 soc_mem_ip6_addr_get(unit, mem, buf_entry, 2103 uc_ipv6_lwr, l3cfg->l3c_ip6, 2104 SOC_MEM_IP6_LOWER_ONLY); 2105 2106 soc_mem_ip6_addr_get(unit, mem, buf_entry, 2107 uc_ipv6_upr, l3cfg->l3c_ip6, 2108 SOC_MEM_IP6_UPPER_ONLY); 2109 } 2110 } 2111 /* Set index to l3cfg. */ 2112 l3cfg->l3c_hw_index = idx; 2113 2114 if (!ipv6) { 2115 l3cfg->l3c_ip_addr = 2116 soc_mem_field32_get(unit, mem, buf_entry, fld->ip4); 2117 } 2118 2119 /* Parse entry data. */ 2120 BCM_IF_ERROR_RETURN( 2121 _bcm_td2_l3_ent_parse(unit, mem, l3cfg, nh_idx, buf_entry, key_type)); 2122 2123 /* Clear the HIT bit */ 2124 if (clear_hit) { 2125 BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, l3cfg, 2126 (void *)buf_entry, idx)); 2127 } 2128 2129 return (BCM_E_NONE); 2130 } 2131 2132 /* 2133 * Function: 2134 * _bcm_td2_l3_ipmc_ent_init 2135 * Purpose: 2136 * Set GROUP/SOURCE/VID/IMPC flag in the entry. 2137 * Parameters: 2138 * unit - (IN)SOC unit number. 2139 * l3x_entry - (IN/OUT) IPMC entry to fill. 2140 * l3cfg - (IN) Api IPMC data. 2141 * Returns: 2142 * BCM_E_XXX 2143 */ 2144 int 2145 _bcm_td2_l3_ipmc_ent_init(int unit, uint32 *buf_p, 2146 _bcm_l3_cfg_t *l3cfg) 2147 { 2148 soc_mem_t mem; /* IPMC table memory. */ 2149 int ipv6; /* IPv6 entry indicator. */ 2150 int idx; /* Iteration index. */ 2151 soc_field_t v4typef[] = { KEY_TYPE_0f, KEY_TYPE_1f }; 2152 soc_field_t v6typef[] = { KEY_TYPE_0f, KEY_TYPE_1f, 2153 KEY_TYPE_2f, KEY_TYPE_3f }; 2154 soc_field_t validf[] = { VALID_0f, VALID_1f, VALID_2f, VALID_3f }; 2155 int rv = BCM_E_NONE; 2156 int vfi, key_type = 0; 2157 uint32 base_valid0, base_valid1, base_valid2, base_valid3; 2158 2159 /* Get entry type. */ 2160 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 2161 2162 /* Get table memory. */ 2163 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 2164 mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm; 2165 } else { 2166 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 2167 } 2168 2169 if (ipv6) { 2170 /* Set group address. */ 2171 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_64f, 2172 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 2173 l3cfg->l3c_ip6[0] = 0x0; /* Don't write ff entry already mcast. */ 2174 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_56f, 2175 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 2176 l3cfg->l3c_ip6[0] = 0xff; /* Restore The entry */ 2177 2178 /* Set source address. */ 2179 if (soc_mem_field_valid(unit, mem, IPV6MC__SOURCE_IP_ADDR_BITS_63_32f)) { 2180 soc_mem_ip6_addr_set(unit, mem, buf_p, 2181 IPV6MC__SOURCE_IP_ADDR_BITS_63_32f, l3cfg->l3c_sip6, 2182 SOC_MEM_IP6_BITS_63_32); 2183 soc_mem_ip6_addr_set(unit, mem, buf_p, 2184 IPV6MC__SOURCE_IP_ADDR_BITS_31_0f, l3cfg->l3c_sip6, 2185 SOC_MEM_IP6_BITS_31_0); 2186 } else { 2187 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 2188 l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY); 2189 } 2190 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 2191 l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY); 2192 2193 /* Set vlan id, VPN or L3_IIF. 2194 * if flag BCM_L3_L2ONLY is set or l3c_ing_intf is invalid, then program 2195 * VLAN or VPN. 2196 * Else program L3_IIF. 2197 */ 2198 if ((l3cfg->l3c_flags & BCM_L3_L2ONLY) || 2199 (l3cfg->l3c_ing_intf == BCM_IF_INVALID)) { 2200 if (_BCM_VPN_IS_SET(l3cfg->l3c_vid)) { 2201 2202 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2203 (l3cfg->l3c_flags & BCM_L3_L2ONLY)) { 2204 if (_BCM_VPN_IS_L3(l3cfg->l3c_vid)) { 2205 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_L3, l3cfg->l3c_vid); 2206 } else if (_BCM_VPN_IS_VPWS(l3cfg->l3c_vid)) { 2207 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VPWS, l3cfg->l3c_vid); 2208 } else { 2209 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, l3cfg->l3c_vid); 2210 } 2211 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VFIf, vfi); 2212 key_type = TD2_L3_HASH_KEY_TYPE_V6L2VPMC; 2213 } else { 2214 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__L3_IIFf, l3cfg->l3c_vid); 2215 key_type = TD2_L3_HASH_KEY_TYPE_V6MC; 2216 } 2217 } else { 2218 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VLAN_IDf, l3cfg->l3c_vid); 2219 key_type = TD2_L3_HASH_KEY_TYPE_V6L2MC; 2220 } 2221 if (!soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) || 2222 !soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2223 /* Override the key in case feature not supported */ 2224 key_type = TD2_L3_HASH_KEY_TYPE_V6MC; 2225 } 2226 } else { 2227 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__L3_IIFf, 2228 l3cfg->l3c_ing_intf); 2229 key_type = TD2_L3_HASH_KEY_TYPE_V6MC; 2230 } 2231 if (soc_feature(unit, soc_feature_base_valid)) { 2232 /* Set key type */ 2233 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, key_type); 2234 if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) { 2235 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, key_type); 2236 } 2237 /* Set entry valid bit. */ 2238 if (SOC_IS_TOMAHAWK3(unit)) { 2239 base_valid0 = 1; 2240 base_valid1 = 2; 2241 base_valid2 = 2; 2242 base_valid3 = 7; 2243 } else { 2244 base_valid0 = 5; 2245 base_valid1 = 6; 2246 base_valid2 = 6; 2247 base_valid3 = 7; 2248 } 2249 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0); 2250 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1); 2251 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_2f, base_valid2); 2252 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_3f, base_valid3); 2253 } else { 2254 for (idx = 0; idx < 4; idx++) { 2255 /* Set key type */ 2256 soc_mem_field32_set(unit, mem, buf_p, v6typef[idx], 2257 key_type); 2258 /* Set entry valid bit. */ 2259 soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1); 2260 } 2261 } 2262 /* Set virtual router id. */ 2263 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VRF_IDf, l3cfg->l3c_vrf); 2264 2265 } else { 2266 /* Set group id. */ 2267 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf, 2268 l3cfg->l3c_ip_addr); 2269 2270 /* Set source address. */ 2271 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__SOURCE_IP_ADDRf, 2272 l3cfg->l3c_src_ip_addr); 2273 2274 if ((l3cfg->l3c_flags & BCM_L3_L2ONLY) || 2275 (l3cfg->l3c_ing_intf == BCM_IF_INVALID)) { 2276 if (_BCM_VPN_IS_SET(l3cfg->l3c_vid)) { 2277 2278 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 2279 (l3cfg->l3c_flags & BCM_L3_L2ONLY)) { 2280 if (_BCM_VPN_IS_L3(l3cfg->l3c_vid)) { 2281 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_L3, l3cfg->l3c_vid); 2282 } else if (_BCM_VPN_IS_VPWS(l3cfg->l3c_vid)) { 2283 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VPWS, l3cfg->l3c_vid); 2284 } else { 2285 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, l3cfg->l3c_vid); 2286 } 2287 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VFIf, vfi); 2288 key_type = TD2_L3_HASH_KEY_TYPE_V4L2VPMC; 2289 } else { 2290 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__L3_IIFf, l3cfg->l3c_vid); 2291 key_type = TD2_L3_HASH_KEY_TYPE_V4MC; 2292 } 2293 } else { 2294 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VLAN_IDf, l3cfg->l3c_vid); 2295 key_type = TD2_L3_HASH_KEY_TYPE_V4L2MC; 2296 } 2297 if (!soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) || 2298 !soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) { 2299 /* Override the key in case feature not supported */ 2300 key_type = TD2_L3_HASH_KEY_TYPE_V4MC; 2301 } 2302 } else { 2303 /* L3_IIF. */ 2304 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__L3_IIFf, l3cfg->l3c_ing_intf); 2305 key_type = TD2_L3_HASH_KEY_TYPE_V4MC; 2306 } 2307 2308 if (soc_feature(unit, soc_feature_base_valid)) { 2309 /* Set key type */ 2310 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, key_type); 2311 if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) { 2312 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, key_type); 2313 } 2314 /* Set entry valid bit. */ 2315 if (!SOC_IS_TOMAHAWK3(unit)) { 2316 base_valid0 = 3; 2317 base_valid1 = 4; 2318 } else { 2319 base_valid0 = 1; 2320 base_valid1 = 7; 2321 } 2322 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0); 2323 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1); 2324 } else { 2325 for (idx = 0; idx < 2; idx++) { 2326 /* Set key type */ 2327 soc_mem_field32_set(unit, mem, buf_p, v4typef[idx], 2328 key_type); 2329 /* Set entry valid bit. */ 2330 soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1); 2331 } 2332 } 2333 /* Set virtual router id. */ 2334 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VRF_IDf, l3cfg->l3c_vrf); 2335 } 2336 2337 #ifdef BCM_TOMAHAWK_SUPPORT 2338 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 2339 /* 2340 * This Tomahawk specific code handles migration of 2341 * T, MODULE_Id, PORT_NUM, TGID fields from L3_IPMC_1 table to 2342 * L3_ENTRY_IPV4_MULTICAST table 2343 */ 2344 int is_trunk, mod, port_tgid, no_src_check = FALSE; 2345 soc_field_t trunk_port, module_id,port_num, trunk_id; 2346 2347 if (ipv6) { 2348 trunk_port = IPV6MC__Tf; 2349 module_id = IPV6MC__MODULE_IDf; 2350 port_num = IPV6MC__PORT_NUMf; 2351 trunk_id = IPV6MC__TGIDf; 2352 } else { 2353 trunk_port = IPV4MC__Tf; 2354 module_id = IPV4MC__MODULE_IDf; 2355 port_num = IPV4MC__PORT_NUMf; 2356 trunk_id = IPV4MC__TGIDf; 2357 } 2358 if ((l3cfg->l3c_flags & BCM_IPMC_SOURCE_PORT_NOCHECK) || 2359 (l3cfg->l3c_port_tgid < 0)) { /* no source port */ 2360 no_src_check = TRUE; 2361 is_trunk = 0; 2362 mod = SOC_MODID_MAX(unit); 2363 port_tgid = TH_IPMC_NO_SRC_CHECK_PORT; 2364 } else if (l3cfg->l3c_tunnel) { /* trunk source port */ 2365 is_trunk = 1; 2366 mod = 0; 2367 port_tgid = l3cfg->l3c_port_tgid; 2368 } else { /* source port */ 2369 bcm_module_t mod_in, mod_out; 2370 bcm_port_t port_in, port_out; 2371 2372 mod_in = l3cfg->l3c_modid; 2373 port_in = l3cfg->l3c_port_tgid; 2374 BCM_IF_ERROR_RETURN 2375 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 2376 mod_in, port_in, 2377 &mod_out, &port_out)); 2378 /* Check parameters, since above is an application callback */ 2379 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 2380 return BCM_E_BADID; 2381 } 2382 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 2383 return BCM_E_PORT; 2384 } 2385 is_trunk = 0; 2386 mod = mod_out; 2387 port_tgid = port_out; 2388 } 2389 2390 if (is_trunk) { 2391 soc_mem_field32_set(unit, mem, buf_p, trunk_port, 1); 2392 soc_mem_field32_set(unit, mem, buf_p, trunk_id, port_tgid); 2393 } else { 2394 if (!SOC_IS_TOMAHAWK3(unit)) { 2395 soc_mem_field32_set(unit, mem, buf_p, module_id, mod); 2396 } 2397 soc_mem_field32_set(unit, mem, buf_p, port_num, port_tgid); 2398 if (no_src_check) { 2399 /* For no src check program all 1's in Tf, MOD_ID and PORT_NUM */ 2400 if (SOC_IS_TRIDENT3X(unit)) 2401 soc_mem_field32_set(unit, mem, buf_p, trunk_port, 0); 2402 else 2403 soc_mem_field32_set(unit, mem, buf_p, trunk_port, 1); 2404 } else { 2405 soc_mem_field32_set(unit, mem, buf_p, trunk_port, 0); 2406 } 2407 } 2408 2409 } 2410 #endif 2411 2412 return rv; 2413 } 2414 2415 /* 2416 * Function: 2417 * _bcm_td2_l3_ipmc_ent_parse 2418 * Purpose: 2419 * Service routine used to parse hw l3 ipmc entry to api format. 2420 * Parameters: 2421 * unit - (IN)SOC unit number. 2422 * l3cfg - (IN/OUT)l3 entry parsing destination buf. 2423 * l3x_entry - (IN/OUT)hw buffer. 2424 * Returns: 2425 * void 2426 */ 2427 STATIC int 2428 _bcm_td2_l3_ipmc_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg, 2429 l3_entry_ipv6_multicast_entry_t *l3x_entry) 2430 { 2431 soc_mem_t mem; /* IPMC table memory. */ 2432 uint32 *buf_p; /* HW buffer address. */ 2433 int ipv6; /* IPv6 entry indicator. */ 2434 uint32 hit = 0; /* composite hit = hit_x|hit_y */ 2435 l3_entry_hit_only_x_entry_t hit_x; 2436 l3_entry_hit_only_y_entry_t hit_y; 2437 l3_entry_hit_only_entry_t hit_default; 2438 int idx, idx_max, idx_offset, hit_idx_shift; /* Iteration index. */ 2439 soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f}; 2440 soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, l3mc_idx_l2, class_id, pri, 2441 rpa_id, expected_l3_iif, l3iif; 2442 #ifdef BCM_MONTEREY_SUPPORT 2443 soc_field_t vlan_id; 2444 soc_field_t roe_decap; 2445 #endif 2446 soc_field_t rpf_fail_drop, rpf_fail_tocpu; 2447 soc_field_t trunk_port, module_id, source_vp, port_num, trunk_id, svp_valid; 2448 soc_field_t flex_ctr_base_counter_idx; 2449 soc_field_t flex_ctr_offset_mode; 2450 soc_field_t flex_ctr_pool_number; 2451 uint8 l2only = 0; /* Entry is L2 only domain */ 2452 buf_p = (uint32 *)l3x_entry; 2453 2454 /* Get entry type. */ 2455 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 2456 l2only = (l3cfg->l3c_flags & BCM_L3_L2ONLY); 2457 2458 /* Get table memory and table fields */ 2459 if (ipv6) { 2460 if (soc_mem_is_valid(unit, L3_ENTRY_QUADm)) { 2461 mem = L3_ENTRY_QUADm; 2462 if (soc_mem_field_valid(unit, L3_ENTRY_QUADm, 2463 IPV6MC__DESTINATIONf)) { 2464 l3mc_idx = IPV6MC__DESTINATIONf; 2465 } else { 2466 l3mc_idx = IPV6MC__L3MC_INDEXf; 2467 } 2468 l3mc_idx_l2 = IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf; 2469 } else { 2470 mem = L3_ENTRY_IPV6_MULTICASTm; 2471 l3mc_idx = IPV6MC__L3MC_INDEXf; 2472 l3mc_idx_l2 = INVALIDf; 2473 } 2474 pri = IPV6MC__PRIf; 2475 rpe = IPV6MC__RPEf; 2476 vrf_id = IPV6MC__VRF_IDf; 2477 l3iif = IPV6MC__L3_IIFf; 2478 #ifdef BCM_MONTEREY_SUPPORT 2479 vlan_id = IPV6MC__VLAN_IDf; 2480 roe_decap = IPV6MC__ROE_DECAPf; 2481 #endif 2482 class_id = IPV6MC__CLASS_IDf; 2483 dst_discard = IPV6MC__DST_DISCARDf; 2484 rpa_id = IPV6MC__RPA_IDf; 2485 expected_l3_iif = IPV6MC__EXPECTED_L3_IIFf; 2486 rpf_fail_drop = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf; 2487 rpf_fail_tocpu = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf; 2488 idx_max = 4; 2489 hit_idx_shift = 0; 2490 idx_offset = 0; 2491 trunk_port = IPV6MC__Tf; 2492 module_id = IPV6MC__MODULE_IDf; 2493 source_vp = IPV6MC__SOURCE_VPf; 2494 port_num = IPV6MC__PORT_NUMf; 2495 trunk_id = IPV6MC__TGIDf; 2496 svp_valid = IPV6MC__SVP_VALIDf; 2497 flex_ctr_base_counter_idx = IPV6MC__FLEX_CTR_BASE_COUNTER_IDXf; 2498 flex_ctr_offset_mode = IPV6MC__FLEX_CTR_OFFSET_MODEf; 2499 flex_ctr_pool_number = IPV6MC__FLEX_CTR_POOL_NUMBERf; 2500 } else { 2501 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 2502 mem = L3_ENTRY_DOUBLEm; 2503 if (SOC_MEM_FIELD_VALID(unit, L3_ENTRY_DOUBLEm, 2504 IPV4MC__DESTINATIONf)) { 2505 l3mc_idx = IPV4MC__DESTINATIONf; 2506 } else { 2507 l3mc_idx = IPV4MC__L3MC_INDEXf; 2508 } 2509 l3mc_idx_l2 = IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf; 2510 } else { 2511 mem = L3_ENTRY_IPV4_MULTICASTm; 2512 l3mc_idx = IPV4MC__L3MC_INDEXf; 2513 l3mc_idx_l2 = INVALIDf; 2514 } 2515 pri = IPV4MC__PRIf; 2516 rpe = IPV4MC__RPEf; 2517 vrf_id = IPV4MC__VRF_IDf; 2518 l3iif = IPV4MC__L3_IIFf; 2519 #ifdef BCM_MONTEREY_SUPPORT 2520 vlan_id = IPV4MC__VLAN_IDf; 2521 roe_decap = IPV4MC__ROE_DECAPf; 2522 #endif 2523 class_id = IPV4MC__CLASS_IDf; 2524 dst_discard = IPV4MC__DST_DISCARDf; 2525 rpa_id = IPV4MC__RPA_IDf; 2526 expected_l3_iif = IPV4MC__EXPECTED_L3_IIFf; 2527 rpf_fail_drop = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf; 2528 rpf_fail_tocpu = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf; 2529 idx_max = 2; 2530 hit_idx_shift = 1; 2531 idx_offset = (l3cfg->l3c_hw_index & 0x1) << 1; 2532 trunk_port = IPV4MC__Tf; 2533 module_id = IPV4MC__MODULE_IDf; 2534 source_vp = IPV4MC__SOURCE_VPf; 2535 port_num = IPV4MC__PORT_NUMf; 2536 trunk_id = IPV4MC__TGIDf; 2537 svp_valid = IPV4MC__SVP_VALIDf; 2538 flex_ctr_base_counter_idx = IPV4MC__FLEX_CTR_BASE_COUNTER_IDXf; 2539 flex_ctr_offset_mode = IPV4MC__FLEX_CTR_OFFSET_MODEf; 2540 flex_ctr_pool_number = IPV4MC__FLEX_CTR_POOL_NUMBERf; 2541 } 2542 2543 /* Mark entry as multicast & clear rest of the flags. */ 2544 l3cfg->l3c_flags = BCM_L3_IPMC; 2545 if (ipv6) { 2546 l3cfg->l3c_flags |= BCM_L3_IP6; 2547 } 2548 if (l2only) { 2549 l3cfg->l3c_flags |= BCM_L3_L2ONLY; 2550 } 2551 2552 if (soc_feature(unit, soc_feature_multi_pipe_mapped_ports)) { 2553 BCM_IF_ERROR_RETURN( 2554 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm, 2555 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x)); 2556 2557 /* Read hit value. */ 2558 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2559 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm, 2560 &hit_x, hitf[idx]); 2561 } 2562 2563 /* Check Source Virtual Port */ 2564 if (soc_mem_field_valid(unit, mem, svp_valid) && 2565 soc_mem_field32_get(unit, mem, buf_p, svp_valid)) { 2566 l3cfg->l3c_port_tgid = soc_mem_field32_get(unit, mem, buf_p, 2567 source_vp); 2568 } else { /* Check Trunk Port */ 2569 if (soc_mem_field32_get(unit, mem, buf_p, trunk_port)) { 2570 l3cfg->l3c_tunnel = 1; 2571 l3cfg->l3c_port_tgid = soc_mem_field32_get(unit, mem, buf_p, trunk_id); 2572 if ((SOC_MEM_FIELD_VALID(unit, mem, module_id)) && 2573 (((l3cfg->l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT) 2574 == TH_IPMC_NO_SRC_CHECK_PORT)) && 2575 (soc_mem_field32_get(unit, mem, buf_p, module_id) == SOC_MODID_MAX(unit))) { 2576 l3cfg->l3c_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 2577 l3cfg->l3c_modid = SOC_MODID_MAX(unit); 2578 } else { 2579 l3cfg->l3c_flags |= BCM_L3_TGID; 2580 } 2581 } else { 2582 #ifdef BCM_TRIDENT3_SUPPORT 2583 if (SOC_IS_TRIDENT3X(unit) && 2584 ((((l3cfg->l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT) 2585 == TH_IPMC_NO_SRC_CHECK_PORT)) && 2586 (soc_mem_field32_get(unit, mem, buf_p, module_id) 2587 == SOC_MODID_MAX(unit)))) { 2588 l3cfg->l3c_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 2589 l3cfg->l3c_modid = SOC_MODID_MAX(unit); 2590 } else 2591 #endif /* BCM_TRIDENT3_SUPPORT */ 2592 { 2593 if (soc_mem_field_valid(unit, mem, module_id)) { 2594 l3cfg->l3c_modid = soc_mem_field32_get(unit, mem, buf_p, 2595 module_id); 2596 } 2597 l3cfg->l3c_port_tgid = soc_mem_field32_get(unit, mem, buf_p, 2598 port_num); 2599 } 2600 l3cfg->l3c_tunnel = 0; 2601 } 2602 } 2603 } else if (soc_feature(unit, soc_feature_two_ingress_pipes) && 2604 !SOC_IS_TRIDENT3X(unit)) { 2605 BCM_IF_ERROR_RETURN( 2606 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Xm, 2607 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x)); 2608 2609 BCM_IF_ERROR_RETURN( 2610 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Ym, 2611 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_y)); 2612 2613 /* Read hit value. */ 2614 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2615 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Xm, 2616 &hit_x, hitf[idx]); 2617 } 2618 2619 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2620 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Ym, 2621 &hit_y, hitf[idx]); 2622 } 2623 } else { 2624 BCM_IF_ERROR_RETURN( 2625 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm, 2626 (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_default)); 2627 2628 /* Read hit value. */ 2629 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2630 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm, 2631 &hit_default, hitf[idx]); 2632 } 2633 } 2634 2635 if (hit) { 2636 l3cfg->l3c_flags |= BCM_L3_HIT; 2637 } 2638 2639 /* Set ipv6 group address to multicast. */ 2640 if (ipv6) { 2641 l3cfg->l3c_ip6[0] = 0xff; /* Set entry ip to mcast address. */ 2642 } 2643 if (l2only) { 2644 /* Vlan/VFI is key, read L3iif */ 2645 l3cfg->l3c_ing_intf = soc_mem_field32_get(unit, mem, buf_p, l3iif); 2646 } else { 2647 /* L3IIF is key, read vid */ 2648 #ifdef BCM_MONTEREY_SUPPORT 2649 if (SOC_IS_MONTEREY(unit)) { 2650 l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, vlan_id); 2651 } else 2652 #endif 2653 { 2654 l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, l3iif); 2655 } 2656 } 2657 /* Read priority override */ 2658 if(soc_mem_field32_get(unit, mem, buf_p, rpe)) { 2659 l3cfg->l3c_flags |= BCM_L3_RPE; 2660 } 2661 2662 /* Read destination discard bit. */ 2663 if(soc_mem_field32_get(unit, mem, buf_p, dst_discard)) { 2664 l3cfg->l3c_flags |= BCM_L3_DST_DISCARD; 2665 } 2666 2667 /* Read Virtual Router Id. */ 2668 l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, vrf_id); 2669 2670 /* Pointer to ipmc replication table. */ 2671 if (soc_feature(unit, soc_feature_generic_dest)) { 2672 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 2673 l3cfg->l3c_ipmc_ptr = soc_mem_field32_dest_get(unit, mem, buf_p, 2674 l3mc_idx, &dest_type); 2675 if (dest_type != SOC_MEM_FIF_DEST_IPMC) { 2676 return BCM_E_FAIL; 2677 } 2678 } else { 2679 l3cfg->l3c_ipmc_ptr = soc_mem_field32_get(unit, mem, buf_p, l3mc_idx); 2680 } 2681 2682 if (l3mc_idx_l2 != INVALIDf && soc_mem_field_valid(unit, mem, l3mc_idx_l2)) { 2683 l3cfg->l3c_ipmc_ptr_l2 = soc_mem_field32_get(unit, mem, buf_p, l3mc_idx_l2); 2684 } 2685 2686 /* Classification lookup class id. */ 2687 l3cfg->l3c_lookup_class = soc_mem_field32_get(unit, mem, buf_p, class_id); 2688 2689 /* Read priority value. */ 2690 l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, pri); 2691 2692 /* Read RPA_ID value. */ 2693 if (soc_mem_field_valid(unit, mem, rpa_id)) { 2694 l3cfg->l3c_rp_id = soc_mem_field32_get(unit, mem, buf_p, rpa_id); 2695 } else { 2696 l3cfg->l3c_rp_id = 0; 2697 } 2698 2699 if (l3cfg->l3c_rp_id == 0 && 2700 (l3cfg->l3c_vid != 0 || 2701 soc_mem_field32_get(unit, mem, buf_p, expected_l3_iif) != 0)) { 2702 /* If RPA_ID field value is 0, it could mean (1) this IPMC entry is 2703 * not a PIM-BIDIR entry, or (2) this entry is a PIM-BIDIR entry and 2704 * is associated with rendezvous point 0. If either the L3 IIF in the 2705 * key or the expected L3 IIF in the data is not zero, this 2706 * entry is not a PIM-BIDIR entry. 2707 */ 2708 l3cfg->l3c_rp_id = BCM_IPMC_RP_ID_INVALID; 2709 } 2710 2711 /* Read expected iif */ 2712 l3cfg->l3c_intf = soc_mem_field32_get(unit, mem, buf_p, expected_l3_iif); 2713 if (0 != l3cfg->l3c_intf) { 2714 l3cfg->l3c_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 2715 } 2716 if (soc_mem_field32_get(unit, mem, buf_p, rpf_fail_drop)) { 2717 l3cfg->l3c_flags |= BCM_IPMC_RPF_FAIL_DROP; 2718 } 2719 if (soc_mem_field32_get(unit, mem, buf_p, rpf_fail_tocpu)) { 2720 l3cfg->l3c_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 2721 } 2722 2723 2724 if (!SOC_IS_MONTEREY(unit)) { 2725 /* Read base counter index. */ 2726 l3cfg->l3c_flex_ctr_base_id = 2727 soc_mem_field32_get(unit, mem, buf_p, flex_ctr_base_counter_idx); 2728 /* Read counter offset mode. */ 2729 l3cfg->l3c_flex_ctr_mode = 2730 soc_mem_field32_get(unit, mem, buf_p, flex_ctr_offset_mode); 2731 /* Read counter pool number. */ 2732 l3cfg->l3c_flex_ctr_pool = 2733 soc_mem_field32_get(unit, mem, buf_p, flex_ctr_pool_number); 2734 } 2735 2736 #ifdef BCM_MONTEREY_SUPPORT 2737 if (soc_feature(unit, soc_feature_roe) || 2738 soc_feature(unit, soc_feature_roe_custom)) { 2739 if (SOC_MEM_FIELD_VALID(unit, mem, roe_decap)) { 2740 if (soc_mem_field32_get(unit, mem, buf_p, roe_decap)) { 2741 l3cfg->l3c_flags2 |= BCM_L3_FLAGS2_DECAP_ROE_HEADER; 2742 } 2743 } 2744 } 2745 #endif 2746 2747 return BCM_E_NONE; 2748 } 2749 2750 /* 2751 * Function: 2752 * _bcm_td2_l3_host_stat_get_table_info 2753 * Description: 2754 * Provides relevant flex table information(table-name,index with 2755 * direction) for given L3 Host entry 2756 * 2757 * Parameters: 2758 * unit - (IN) unit number 2759 * port - (IN) GPORT ID 2760 * num_of_tables - (OUT) Number of flex counter tables 2761 * table_info - (OUT) Flex counter tables information 2762 * 2763 * Return Value: 2764 * BCM_E_XXX 2765 * Notes: 2766 */ 2767 STATIC bcm_error_t 2768 _bcm_td2_l3_host_stat_get_table_info( 2769 int unit, 2770 bcm_l3_host_t *info, 2771 uint32 *num_of_tables, 2772 bcm_stat_flex_table_info_t *table_info) 2773 { 2774 int rv, embd; 2775 soc_mem_t mem; 2776 _bcm_l3_cfg_t l3cfg; 2777 2778 if (NULL == info) { 2779 return (BCM_E_PARAM); 2780 } 2781 2782 if (!(soc_feature(unit, soc_feature_l3_extended_host_entry))) { 2783 return BCM_E_UNAVAIL; 2784 } 2785 2786 mem = INVALIDm; 2787 /* Vrf is in device supported range check. */ 2788 if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 2789 (info->l3a_vrf < BCM_L3_VRF_DEFAULT)) { 2790 return (BCM_E_PARAM); 2791 } 2792 2793 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2794 l3cfg.l3c_flags = info->l3a_flags; 2795 l3cfg.l3c_vrf = info->l3a_vrf; 2796 2797 if (info->l3a_flags & BCM_L3_IP6) { 2798 sal_memcpy(l3cfg.l3c_ip6, info->l3a_ip6_addr, BCM_IP6_ADDRLEN); 2799 } else { 2800 l3cfg.l3c_ip_addr = info->l3a_ip_addr; 2801 } 2802 2803 rv = _bcm_td2_l3_entry_get(unit, &l3cfg, NULL, &embd); 2804 if (BCM_SUCCESS(rv)) { /* Entry found */ 2805 #ifdef BCM_TRIDENT3_SUPPORT 2806 if (SOC_IS_TRIDENT3X(unit)) { 2807 mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_QUADm : 2808 L3_ENTRY_DOUBLEm; 2809 } else 2810 #endif 2811 { 2812 if (embd != TRUE) { 2813 return (BCM_E_PARAM); 2814 } 2815 mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_IPV6_MULTICASTm : 2816 L3_ENTRY_IPV4_MULTICASTm; 2817 } 2818 2819 table_info[*num_of_tables].table = mem; 2820 table_info[*num_of_tables].index = l3cfg.l3c_hw_index; 2821 table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress; 2822 (*num_of_tables)++; 2823 } 2824 2825 return rv; 2826 } 2827 2828 /*----- END STATIC FUNCS ----- */ 2829 2830 /* 2831 * Function: 2832 * _bcm_td2_l3_add 2833 * Purpose: 2834 * Add and entry to TD2 L3 host table. 2835 * The decision to add to is based on 2836 * switch control(s) and table full conditions. 2837 * conditions. 2838 * Parameters: 2839 * unit - (IN) SOC unit number. 2840 * l3cfg - (IN) L3 entry info. 2841 * nh_idx - (IN) Next hop index. 2842 * Returns: 2843 * BCM_E_XXX 2844 */ 2845 int 2846 _bcm_td2_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 2847 { 2848 int rv; 2849 2850 rv = _bcm_td2_l3_entry_add(unit, l3cfg, nh_idx); 2851 return rv; 2852 } 2853 2854 /* 2855 * Function: 2856 * _bcm_td2_l3_get 2857 * Purpose: 2858 * Get an entry from TD2 L3 host table. 2859 * Parameters: 2860 * unit - (IN) SOC unit number. 2861 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 2862 * nh_index - (IN/OUT) Next hop index. 2863 * Returns: 2864 * BCM_E_XXX 2865 */ 2866 int 2867 _bcm_td2_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx) 2868 { 2869 int rv; 2870 int embd = _BCM_TD2_HOST_ENTRY_NOT_FOUND; 2871 2872 rv = _bcm_td2_l3_entry_get(unit, l3cfg, nh_idx, &embd); 2873 return rv; 2874 } 2875 2876 /* 2877 * Function: 2878 * _bcm_td2_l3_del 2879 * Purpose: 2880 * Del an entry from TD2 L3 host table. 2881 * Parameters: 2882 * unit - (IN) SOC unit number. 2883 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 2884 * nh_index - (IN/OUT) Next hop index. 2885 * Returns: 2886 * BCM_E_XXX 2887 */ 2888 int 2889 _bcm_td2_l3_del(int unit, _bcm_l3_cfg_t *l3cfg) 2890 { 2891 int rv; 2892 2893 /* Attempt to delete entry */ 2894 rv = _bcm_td2_l3_entry_del(unit, l3cfg); 2895 return rv; 2896 } 2897 2898 /* 2899 * Function: 2900 * _bcm_td2_l3_traverse 2901 * Purpose: 2902 * Walk over range of entries in l3 host table. 2903 * Parameters: 2904 * unit - SOC unit number. 2905 * flags - L3 entry flags to match during traverse. 2906 * start - First index to read. 2907 * end - Last index to read. 2908 * cb - Caller notification callback. 2909 * user_data - User cookie, which should be returned in cb. 2910 * Returns: 2911 * BCM_E_XXX 2912 */ 2913 int 2914 _bcm_td2_l3_traverse(int unit, int flags, uint32 start, uint32 end, 2915 bcm_l3_host_traverse_cb cb, void *user_data) 2916 { 2917 int rv = BCM_E_NONE; 2918 int ipv6; /* Protocol IPv6/IPv4 */ 2919 int nh_idx; /* Next hop index. */ 2920 int total = 0; /* Total number of entries walked. */ 2921 int table_size; /* Number of entries in the table. */ 2922 int table_ent_size; /* Table entry size. */ 2923 bcm_l3_host_t info; /* Callback info buffer. */ 2924 _bcm_l3_cfg_t l3cfg; /* HW entry info. */ 2925 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 2926 int tbl, idx, idx_min, idx_max; /* Min and Max iteration index */ 2927 int num_tables = 2; 2928 soc_mem_t mem[2] = {INVALIDm, INVALIDm}; 2929 int show_idx_flag; 2930 2931 /* If no callback provided, we are done. */ 2932 if (NULL == cb) { 2933 return (BCM_E_NONE); 2934 } 2935 2936 ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE; 2937 show_idx_flag = (flags & _BCM_L3_SHOW_INDEX) ? TRUE : FALSE; 2938 /* If table is empty -> there is nothing to read. */ 2939 if (ipv6 && (!BCM_XGS3_L3_IP6_CNT(unit))) { 2940 return (BCM_E_NONE); 2941 } 2942 if (!ipv6 && (!BCM_XGS3_L3_IP4_CNT(unit))) { 2943 return (BCM_E_NONE); 2944 } 2945 2946 if (ipv6) { 2947 mem[0] = BCM_XGS3_L3_MEM(unit, v6); 2948 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2949 mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 2950 } 2951 } else { 2952 mem[0] = BCM_XGS3_L3_MEM(unit, v4); 2953 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2954 mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 2955 } 2956 } 2957 2958 for(tbl = 0; tbl < num_tables; tbl++) { 2959 2960 if (INVALIDm == mem[tbl]) { 2961 continue; 2962 } 2963 idx_max = soc_mem_index_max(unit, mem[tbl]); 2964 idx_min = soc_mem_index_min(unit, mem[tbl]); 2965 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]); 2966 2967 BCM_IF_ERROR_RETURN (bcm_xgs3_l3_tbl_dma(unit, mem[tbl], table_ent_size, 2968 "l3_tbl", &l3_tbl_ptr, &table_size)); 2969 2970 /* Input index`s sanity. */ 2971 if (start > (uint32)table_size || start > end) { 2972 if(l3_tbl_ptr) { 2973 soc_cm_sfree(unit, l3_tbl_ptr); 2974 } 2975 return (BCM_E_NOT_FOUND); 2976 } 2977 2978 /* Iterate over all the entries - show matching ones. */ 2979 for (idx = idx_min; idx <= idx_max; idx++) { 2980 /* Reset buffer before read. */ 2981 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2982 l3cfg.l3c_flags = flags; 2983 2984 /* Get entry from hw. */ 2985 rv = _bcm_td2_l3_get_host_ent_by_idx(unit, l3_tbl_ptr, mem[tbl], 2986 idx, &l3cfg, &nh_idx); 2987 2988 /* Check for read errors & invalid entries. */ 2989 if (rv < 0) { 2990 if (rv != BCM_E_NOT_FOUND) { 2991 break; 2992 } 2993 continue; 2994 } 2995 #if defined(BCM_TRIDENT3_SUPPORT) 2996 if (soc_feature(unit, soc_feature_flex_flow) 2997 && (l3cfg.l3c_flow_handle) 2998 && (l3cfg.l3c_flags & BCM_L3_IPMC)) { 2999 if (!IPMC_USED_ISSET(unit, l3cfg.l3c_ipmc_ptr)) { 3000 LOG_ERROR(BSL_LS_BCM_L3, 3001 (BSL_META_U(unit, 3002 "L3 host: Invalid IPMC group %d " \ 3003 "in L3 host entry index %d\n"), 3004 l3cfg.l3c_ipmc_ptr, idx)); 3005 continue; 3006 } 3007 3008 if (BCM_L3_CMP_EQUAL != 3009 _bcm_td3_l3_flex_entry_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 3010 continue; 3011 } 3012 3013 /* Valid entry found -> increment total table_sizeer */ 3014 total++; 3015 if ((uint32)total < start) { 3016 continue; 3017 } 3018 3019 /* Don't read beyond last required index. */ 3020 if ((uint32)total > end) { 3021 break; 3022 } 3023 3024 } else 3025 #endif /* BCM_TRIDENT3_SUPPORT */ 3026 { 3027 /* Check read entry flags & update index accordingly. */ 3028 if (BCM_L3_CMP_EQUAL != 3029 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 3030 continue; 3031 } 3032 3033 /* Valid entry found -> increment total table_sizeer */ 3034 total++; 3035 if ((uint32)total < start) { 3036 continue; 3037 } 3038 3039 /* Don't read beyond last required index. */ 3040 if ((uint32)total > end) { 3041 break; 3042 } 3043 3044 /* Get next hop info. */ 3045 rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx); 3046 if (rv < 0) { 3047 continue; 3048 } 3049 } 3050 3051 /* Fill host info. */ 3052 _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info); 3053 if (show_idx_flag && user_data) { 3054 *(int *)user_data = idx; 3055 } 3056 3057 if (cb) { 3058 rv = (*cb) (unit, total, &info, user_data); 3059 #ifdef BCM_CB_ABORT_ON_ERR 3060 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 3061 break; 3062 } 3063 #endif 3064 } 3065 } 3066 3067 if (l3_tbl_ptr) { 3068 soc_cm_sfree(unit, l3_tbl_ptr); 3069 } 3070 } 3071 3072 /* Reset last read status. */ 3073 if (BCM_E_NOT_FOUND == rv) { 3074 rv = BCM_E_NONE; 3075 } 3076 3077 return (rv); 3078 3079 } 3080 3081 /* 3082 * Function: 3083 * _bcm_td2_l3_host_stat_attach 3084 * Description: 3085 * Attach counters entries to the given L3 host entry 3086 * 3087 * Parameters: 3088 * unit - (IN) unit number 3089 * info - (IN) L3 host description 3090 * stat_counter_id - (IN) Stat Counter ID. 3091 * 3092 * Return Value: 3093 * BCM_E_XXX 3094 * Notes: 3095 * On BCM56640, the L3 host tables (tables L3_ENTRY_2 and L3_ENTRY_4, 3096 * table EXT_L3_UCAST_DATA_WIDE) may contain a flex stat pointer when 3097 * entry has a dereference next hop (no NEXT_HOP pointer, but the NH info 3098 * instead). This counter is analogous to what would be in the egress 3099 * object, but is implemented in the ingress and so requires an ingress 3100 * counter pool allocated. 3101 */ 3102 bcm_error_t 3103 _bcm_td2_l3_host_stat_attach( 3104 int unit, 3105 bcm_l3_host_t *info, 3106 uint32 stat_counter_id) 3107 { 3108 soc_mem_t table[4]={0}; 3109 uint32 flex_table_index=0; 3110 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 3111 uint32 pool_number=0; 3112 uint32 base_index=0; 3113 bcm_stat_flex_mode_t offset_mode=0; 3114 bcm_stat_object_t object=bcmStatObjectIngPort; 3115 bcm_stat_group_mode_t group_mode= bcmStatGroupModeSingle; 3116 uint32 count=0; 3117 uint32 actual_num_tables=0; 3118 uint32 num_of_tables=0; 3119 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 3120 3121 _bcm_esw_stat_get_counter_id_info( 3122 unit, stat_counter_id, 3123 &group_mode,&object,&offset_mode,&pool_number,&base_index); 3124 3125 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction)); 3126 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode)); 3127 3128 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info( 3129 unit,object,4,&actual_num_tables,&table[0],&direction)); 3130 3131 BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info( 3132 unit, info,&num_of_tables,&table_info[0])); 3133 /* TD3 doesn't support Flex Counter for L3_ENTRY_DOUBLE view */ 3134 if (SOC_IS_TRIDENT3(unit) && 3135 SOC_URPF_STATUS_GET(unit) && 3136 table_info[0].table == L3_ENTRY_DOUBLEm) { 3137 return BCM_E_UNAVAIL; 3138 } 3139 3140 for (count=0; count < num_of_tables ; count++) { 3141 for (flex_table_index=0; 3142 flex_table_index < actual_num_tables ; 3143 flex_table_index++) { 3144 if ((table_info[count].direction == direction) && 3145 (table_info[count].table == table[flex_table_index]) ) { 3146 if (direction == bcmStatFlexDirectionIngress) { 3147 return _bcm_esw_stat_flex_attach_ingress_table_counters( 3148 unit, 3149 table_info[count].table, 3150 table_info[count].index, 3151 offset_mode, 3152 base_index, 3153 pool_number); 3154 } else { 3155 return _bcm_esw_stat_flex_attach_egress_table_counters( 3156 unit, 3157 table_info[count].table, 3158 table_info[count].index, 3159 0, 3160 offset_mode, 3161 base_index, 3162 pool_number); 3163 } 3164 } 3165 } 3166 } 3167 return BCM_E_NOT_FOUND; 3168 } 3169 3170 /* 3171 * Function: 3172 * _bcm_td2_l3_host_stat_detach 3173 * Description: 3174 * Detach counters entries to the given L3 host entry 3175 * 3176 * Parameters: 3177 * unit - (IN) unit number 3178 * info - (IN) L3 host description 3179 * 3180 * Return Value: 3181 * BCM_E_XXX 3182 * Notes: 3183 */ 3184 bcm_error_t 3185 _bcm_td2_l3_host_stat_detach( 3186 int unit, 3187 bcm_l3_host_t *info) 3188 { 3189 uint32 count=0; 3190 uint32 num_of_tables=0; 3191 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 3192 bcm_error_t rv = BCM_E_NONE; 3193 bcm_error_t err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE}; 3194 3195 BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info( 3196 unit, info,&num_of_tables,&table_info[0])); 3197 3198 for (count=0; count < num_of_tables ; count++) { 3199 if (table_info[count].direction == bcmStatFlexDirectionIngress) { 3200 rv = _bcm_esw_stat_flex_detach_ingress_table_counters( 3201 unit, 3202 table_info[count].table, 3203 table_info[count].index); 3204 if (BCM_E_NONE != rv && 3205 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) { 3206 err_code[bcmStatFlexDirectionIngress] = rv; 3207 } 3208 } else { 3209 rv = _bcm_esw_stat_flex_detach_egress_table_counters( 3210 unit, 3211 0, 3212 table_info[count].table, 3213 table_info[count].index); 3214 if (BCM_E_NONE != rv && 3215 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) { 3216 err_code[bcmStatFlexDirectionEgress] = rv; 3217 } 3218 } 3219 } 3220 3221 BCM_STAT_FLEX_DETACH_RETURN(err_code) 3222 } 3223 3224 /* 3225 * Function: 3226 * _bcm_td2_l3_host_stat_counter_get 3227 * Description: 3228 * Get counter statistic values for specific L3 host entry 3229 * if sync_mode is set, sync the sw accumulated count 3230 * with hw count value first, else return sw count. 3231 * 3232 * Parameters: 3233 * unit - (IN) unit number 3234 * sync_mode - (IN) hwcount is to be synced to sw count 3235 * info - (IN) L3 host description 3236 * stat - (IN) Type of the counter to retrieve 3237 * I.e. ingress/egress byte/packet) 3238 * num_entries - (IN) Number of counter Entries 3239 * counter_indexes - (IN) Pointer to Counter indexes entries 3240 * counter_values - (OUT) Pointer to counter values 3241 * 3242 * Return Value: 3243 * BCM_E_XXX 3244 * Notes: 3245 */ 3246 bcm_error_t 3247 _bcm_td2_l3_host_stat_counter_get( 3248 int unit, 3249 int sync_mode, 3250 bcm_l3_host_t *info, 3251 bcm_l3_stat_t stat, 3252 uint32 num_entries, 3253 uint32 *counter_indexes, 3254 bcm_stat_value_t *counter_values) 3255 { 3256 uint32 table_count=0; 3257 uint32 index_count=0; 3258 uint32 num_of_tables=0; 3259 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 3260 uint32 byte_flag=0; 3261 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 3262 3263 if ((stat == bcmL3StatInPackets) || 3264 (stat == bcmL3StatInBytes)) { 3265 direction = bcmStatFlexDirectionIngress; 3266 } else { 3267 /* direction = bcmStatFlexDirectionEgress; */ 3268 return BCM_E_PARAM; 3269 } 3270 if (stat == bcmL3StatInPackets) { 3271 byte_flag=0; 3272 } else { 3273 byte_flag=1; 3274 } 3275 3276 BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info( 3277 unit, info,&num_of_tables,&table_info[0])); 3278 3279 for (table_count=0; table_count < num_of_tables ; table_count++) { 3280 if (table_info[table_count].direction == direction) { 3281 for (index_count=0; index_count < num_entries ; index_count++) { 3282 /*ctr_offset_info.offset_index = counter_indexes[index_count];*/ 3283 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get( 3284 unit, sync_mode, 3285 table_info[table_count].index, 3286 table_info[table_count].table, 3287 0, 3288 byte_flag, 3289 counter_indexes[index_count], 3290 &counter_values[index_count])); 3291 } 3292 } 3293 } 3294 return BCM_E_NONE; 3295 } 3296 3297 /* 3298 * Function: 3299 * _bcm_td2_l3_host_stat_counter_set 3300 * Description: 3301 * Set counter statistic values for specific L3 host entry 3302 * 3303 * Parameters: 3304 * unit - (IN) unit number 3305 * info - (IN) L3 host description 3306 * stat - (IN) Type of the counter to retrieve 3307 * I.e. ingress/egress byte/packet) 3308 * num_entries - (IN) Number of counter Entries 3309 * counter_indexes - (IN) Pointer to Counter indexes entries 3310 * counter_values - (IN) Pointer to counter values 3311 * 3312 * Return Value: 3313 * BCM_E_XXX 3314 * Notes: 3315 */ 3316 bcm_error_t 3317 _bcm_td2_l3_host_stat_counter_set( 3318 int unit, 3319 bcm_l3_host_t *info, 3320 bcm_l3_stat_t stat, 3321 uint32 num_entries, 3322 uint32 *counter_indexes, 3323 bcm_stat_value_t *counter_values) 3324 { 3325 uint32 table_count=0; 3326 uint32 index_count=0; 3327 uint32 num_of_tables=0; 3328 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 3329 uint32 byte_flag=0; 3330 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 3331 if ((stat == bcmL3StatInPackets) || 3332 (stat == bcmL3StatInBytes)) { 3333 direction = bcmStatFlexDirectionIngress; 3334 } else { 3335 /* direction = bcmStatFlexDirectionEgress; */ 3336 return BCM_E_PARAM; 3337 } 3338 if (stat == bcmL3StatInPackets) { 3339 byte_flag=0; 3340 } else { 3341 byte_flag=1; 3342 } 3343 3344 BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info( 3345 unit, info,&num_of_tables,&table_info[0])); 3346 3347 for (table_count=0; table_count < num_of_tables ; table_count++) { 3348 if (table_info[table_count].direction == direction) { 3349 for (index_count=0; index_count < num_entries ; index_count++) { 3350 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set( 3351 unit, 3352 table_info[table_count].index, 3353 table_info[table_count].table, 3354 0, 3355 byte_flag, 3356 counter_indexes[index_count], 3357 &counter_values[index_count])); 3358 } 3359 } 3360 } 3361 return BCM_E_NONE; 3362 } 3363 3364 /* 3365 * Function: 3366 * _bcm_td2_l3_host_stat_id_get 3367 * Description: 3368 * Get stat counter id associated with given L3 host entry 3369 * 3370 * Parameters: 3371 * unit - (IN) unit number 3372 * info - (IN) L3 host description 3373 * stat - (IN) Type of the counter to retrieve 3374 * I.e. ingress/egress byte/packet) 3375 * Stat_counter_id - (OUT) Stat Counter ID 3376 * Return Value: 3377 * BCM_E_XXX 3378 * Notes: 3379 */ 3380 bcm_error_t 3381 _bcm_td2_l3_host_stat_id_get( 3382 int unit, 3383 bcm_l3_host_t *info, 3384 bcm_l3_stat_t stat, 3385 uint32 *stat_counter_id) 3386 { 3387 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 3388 uint32 num_of_tables=0; 3389 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 3390 uint32 index=0; 3391 uint32 num_stat_counter_ids=0; 3392 3393 if ((stat == bcmL3StatInPackets) || 3394 (stat == bcmL3StatInBytes)) { 3395 direction = bcmStatFlexDirectionIngress; 3396 } else { 3397 /* direction = bcmStatFlexDirectionEgress; */ 3398 return BCM_E_PARAM; 3399 } 3400 3401 BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info( 3402 unit,info,&num_of_tables,&table_info[0])); 3403 for (index=0; index < num_of_tables ; index++) { 3404 if (table_info[index].direction == direction) 3405 return _bcm_esw_stat_flex_get_counter_id( 3406 unit, 1, &table_info[index], 3407 &num_stat_counter_ids,stat_counter_id); 3408 } 3409 return BCM_E_NOT_FOUND; 3410 } 3411 3412 /* 3413 * Function: 3414 * bcm_td2_l3_replace 3415 * Purpose: 3416 * Replace an entry in TD2 L3 host table. 3417 * Parameters: 3418 * unit - (IN)SOC unit number. 3419 * l3cfg - (IN)L3 entry information. 3420 * Returns: 3421 * BCM_E_XXX 3422 */ 3423 int 3424 bcm_td2_l3_replace(int unit, _bcm_l3_cfg_t *l3cfg) 3425 { 3426 3427 _bcm_l3_cfg_t entry; /* Original l3 entry. */ 3428 int nh_idx_old; /* Original entry next hop index. */ 3429 int nh_idx_new; /* New allocated next hop index */ 3430 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 3431 int embd_old = 0, embd_new = 0; 3432 int mpath = 0; /* Multipath */ 3433 3434 /* Make sure module was initialized. */ 3435 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 3436 return (BCM_E_INIT); 3437 } 3438 3439 /* Input parameters check. */ 3440 if (NULL == l3cfg) { 3441 return (BCM_E_PARAM); 3442 } 3443 3444 /* Set lookup key. */ 3445 entry = *l3cfg; 3446 3447 if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) { 3448 /* Check if identical entry exits. */ 3449 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) { 3450 BCM_XGS3_L3_MODULE_LOCK(unit); 3451 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, &entry); 3452 BCM_XGS3_L3_MODULE_UNLOCK(unit); 3453 } 3454 if (rv < 0) { 3455 return rv; 3456 } 3457 3458 /* Write mcast entry to hw. */ 3459 l3cfg->l3c_hw_index = entry.l3c_hw_index; /*Replacement index & flag. */ 3460 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) { 3461 BCM_XGS3_L3_MODULE_LOCK(unit); 3462 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg); 3463 BCM_XGS3_L3_MODULE_UNLOCK(unit); 3464 } else { 3465 return (BCM_E_UNAVAIL); 3466 } 3467 } else { 3468 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 3469 /* Trunk id validation. */ 3470 BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags, 3471 l3cfg->l3c_port_tgid); 3472 } 3473 mpath = l3cfg->l3c_flags & BCM_L3_MULTIPATH; 3474 if (!mpath && 3475 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) { 3476 return BCM_E_PARAM; 3477 } 3478 3479 if (mpath && 3480 !BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) { 3481 return BCM_E_PARAM; 3482 } 3483 3484 /* Check if identical entry exits. */ 3485 rv = _bcm_td2_l3_entry_get(unit, &entry, &nh_idx_old, &embd_old); 3486 if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) && 3487 !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) { 3488 return bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv); 3489 } else if (BCM_FAILURE(rv)) { 3490 return rv; 3491 } 3492 3493 if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid)) { 3494 nh_idx_new = 0; 3495 } else { /* If new entry is in indexed NH table */ 3496 /* Get next hop index. */ 3497 BCM_IF_ERROR_RETURN 3498 (_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx_new)); 3499 } 3500 3501 #ifdef BCM_TOMAHAWK_SUPPORT 3502 if (soc_feature(unit, soc_feature_extended_view_no_trunk_support) && 3503 BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx_new) && 3504 (l3cfg->l3c_flags & BCM_L3_TGID)) { 3505 return BCM_E_UNAVAIL; 3506 } 3507 #endif /* BCM_TOMAHAWK_SUPPORT */ 3508 3509 #ifdef BCM_TRIDENT2_SUPPORT 3510 if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) && 3511 soc_feature(unit, soc_feature_ecmp_resilient_hash) && 3512 mpath && (entry.l3c_flags & BCM_L3_MULTIPATH)) { 3513 /* If an old ECMP group is replaced by a new one, and if 3514 * they have members in common, the resilient hash flow set 3515 * entries containing the shared members are copied from the old 3516 * ECMP group to the new ECMP group, in order to minimize 3517 * flow-to-member reassignments. 3518 */ 3519 BCM_IF_ERROR_RETURN(bcm_td2_l3_egress_ecmp_rh_shared_copy(unit, 3520 nh_idx_old, nh_idx_new)); 3521 } 3522 #ifdef BCM_TOMAHAWK_SUPPORT 3523 if (SOC_IS_TOMAHAWKX(unit) && 3524 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) && 3525 mpath && (entry.l3c_flags & BCM_L3_MULTIPATH)) { 3526 BCM_IF_ERROR_RETURN(bcm_opt_l3_egress_ecmp_rh_shared_copy(unit, 3527 nh_idx_old, nh_idx_new)); 3528 } 3529 #endif /* BCM_TOMAHAWK_SUPPORT */ 3530 #endif /* BCM_TRIDENT2_SUPPORT */ 3531 3532 embd_new = BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, 3533 nh_idx_new); 3534 /* Write entry to hw. */ 3535 if (embd_old != embd_new) { 3536 rv = bcm_xgs3_l3_del(unit, &entry); 3537 l3cfg->l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX; 3538 } else { 3539 /*Replacement index & flag. */ 3540 l3cfg->l3c_hw_index = entry.l3c_hw_index; 3541 } 3542 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) { 3543 BCM_XGS3_L3_MODULE_LOCK(unit); 3544 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add)(unit, l3cfg, nh_idx_new); 3545 BCM_XGS3_L3_MODULE_UNLOCK(unit); 3546 } else { 3547 rv = BCM_E_UNAVAIL; 3548 } 3549 3550 /* Do best effort clean_up if needed. */ 3551 if (BCM_FAILURE(rv)) { 3552 bcm_xgs3_nh_del(unit, 0, nh_idx_new); 3553 } 3554 3555 if (embd_old == embd_new) { 3556 /* Free original next hop index. */ 3557 if (entry.l3c_flags & BCM_L3_MULTIPATH) { 3558 /* Destroy ecmp group only if previous route is multipath */ 3559 BCM_IF_ERROR_RETURN( 3560 bcm_xgs3_ecmp_group_del(unit, nh_idx_old, 0)); 3561 } else { 3562 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx_old)); 3563 } 3564 } 3565 } 3566 return rv; 3567 } 3568 3569 /* 3570 * Function: 3571 * bcm_td2_l3_del_intf 3572 * Purpose: 3573 * Delete all the entries in TD2 L3 host table with 3574 * NH matching a certain interface. 3575 * Parameters: 3576 * unit - (IN)SOC unit number. 3577 * l3cfg - (IN)Pointer to memory for l3 table related information. 3578 * negate - (IN)0 means interface match; 1 means not match 3579 * Returns: 3580 * BCM_E_XXX 3581 */ 3582 int 3583 bcm_td2_l3_del_intf(int unit, _bcm_l3_cfg_t *l3cfg, int negate) 3584 { 3585 int rv; /* Operation return status. */ 3586 int tmp_rv; /* First error occured. */ 3587 bcm_if_t intf; /* Deleted interface id. */ 3588 int nh_index; /* Next hop index. */ 3589 bcm_l3_egress_t egr; /* Egress object. */ 3590 _bcm_if_del_pattern_t pattern; /* Interface & negate combination 3591 to be used for every l3 entry 3592 comparision. */ 3593 3594 /* Make sure module was initialized. */ 3595 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 3596 return (BCM_E_INIT); 3597 } 3598 3599 /* Input parameters check */ 3600 if (NULL == l3cfg) { 3601 return (BCM_E_PARAM); 3602 } 3603 3604 intf = l3cfg->l3c_intf; 3605 3606 /* Check l3 switching mode. */ 3607 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 3608 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 3609 BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 3610 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 3611 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 3612 } else { 3613 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 3614 } 3615 /* Get egress object information. */ 3616 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr)); 3617 /* Use egress object interface for iteration */ 3618 intf = egr.intf; 3619 } 3620 } 3621 3622 pattern.l3_intf = intf; 3623 pattern.negate = negate; 3624 3625 /* Delete all ipv4 entries matching the interface. */ 3626 tmp_rv = _bcm_td2_l3_del_match(unit, 0, (void *)&pattern, 3627 _bcm_xgs3_l3_intf_cmp, NULL, NULL); 3628 3629 /* Delete all ipv6 entries matching the interface. */ 3630 rv = _bcm_td2_l3_del_match(unit, BCM_L3_IP6, (void *)&pattern, 3631 _bcm_xgs3_l3_intf_cmp, NULL, NULL); 3632 3633 return (tmp_rv < 0) ? tmp_rv : rv; 3634 } 3635 3636 /* 3637 * Function: 3638 * _bcm_td2_l3_get_by_idx 3639 * Purpose: 3640 * Get an entry from L3 table by index. 3641 * Parameters: 3642 * unit - (IN)SOC unit number. 3643 * dma_ptr - (IN)Table pointer in dma. 3644 * idx - (IN)Index to read. 3645 * l3cfg - (OUT)l3 entry search result. 3646 * nh_index - (OUT)Next hop index. 3647 * Returns: 3648 * BCM_E_XXX 3649 */ 3650 int 3651 _bcm_td2_l3_get_by_idx(int unit, void *dma_ptr, int idx, 3652 _bcm_l3_cfg_t *l3cfg, int *nh_idx) 3653 { 3654 int v6; 3655 int embeded_nh; 3656 soc_mem_t mem; 3657 int rv = BCM_E_UNAVAIL; /* Operation return code. */ 3658 3659 /* Make sure module was initialized. */ 3660 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 3661 return (BCM_E_INIT); 3662 } 3663 3664 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 3665 /* Get multicast entry. */ 3666 rv = _bcm_td2_l3_ipmc_get_by_idx(unit, dma_ptr, idx, l3cfg); 3667 } else { 3668 /* Get unicast entry. */ 3669 v6 = (l3cfg->l3c_flags & BCM_L3_IP6); 3670 embeded_nh = (l3cfg->l3c_flags & BCM_L3_DEREFERENCED_NEXTHOP); 3671 mem = (v6) ? 3672 ((embeded_nh) ? 3673 BCM_XGS3_L3_MEM(unit, v6_4) : BCM_XGS3_L3_MEM(unit, v6)) : 3674 ((embeded_nh) ? 3675 BCM_XGS3_L3_MEM(unit, v4_2) : BCM_XGS3_L3_MEM(unit, v4)); 3676 rv = _bcm_td2_l3_get_host_ent_by_idx(unit, dma_ptr, mem, 3677 idx, l3cfg, nh_idx); 3678 } 3679 return rv; 3680 } 3681 3682 3683 /* 3684 * Function: 3685 * _bcm_td2_l3_del_match 3686 * Purpose: 3687 * Delete an entry in L3 table matches a certain rule. 3688 * Parameters: 3689 * unit - (IN)SOC unit number. 3690 * flags. - (IN)Generic l3 flags. 3691 * pattern - (IN)Comparison match argurment. 3692 * cmp_func - (IN)Comparison function. 3693 * notify_cb - (IN)Delete notification callback. 3694 * user_data - (IN)User provided cookie for callback. 3695 * Returns: 3696 * BCM_E_XXX 3697 */ 3698 int 3699 _bcm_td2_l3_del_match(int unit, int flags, void *pattern, 3700 bcm_xgs3_ent_op_cb cmp_func, 3701 bcm_l3_host_traverse_cb notify_cb, void *user_data) 3702 { 3703 int rv = BCM_E_NONE; 3704 int ipv6; /* IPv6/IPv4 lookup flag. */ 3705 int nh_idx; /* Next hop index. */ 3706 int tbl, idx; /* Iteration indices. */ 3707 int cmp_result; /* Compare against pattern result. */ 3708 bcm_l3_host_t info; /* Host cb buffer. */ 3709 _bcm_l3_cfg_t l3cfg; /* Hw entry info. */ 3710 int idx_max; 3711 int num_tables = 2; 3712 soc_mem_t mem[2] = {INVALIDm, INVALIDm}; 3713 int table_ent_size; /* Table entry size. */ 3714 int table_size; /* Number of entries in the table. */ 3715 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 3716 3717 /* Check Protocol. */ 3718 ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE; 3719 3720 if (ipv6) { 3721 mem[0] = BCM_XGS3_L3_MEM(unit, v6); 3722 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 3723 mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 3724 } 3725 } else { 3726 mem[0] = BCM_XGS3_L3_MEM(unit, v4); 3727 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 3728 mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 3729 } 3730 } 3731 3732 for (tbl = 0; tbl < num_tables; tbl++) { 3733 if (INVALIDm == mem[tbl]) { 3734 continue; 3735 } 3736 idx_max = soc_mem_index_max(unit, mem[tbl]); 3737 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]); 3738 BCM_IF_ERROR_RETURN( 3739 bcm_xgs3_l3_tbl_dma(unit, mem[tbl], table_ent_size, 3740 "l3_tbl", &l3_tbl_ptr, &table_size)); 3741 3742 for (idx = 0; idx <= idx_max; idx++) { 3743 3744 /* Set protocol. */ 3745 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 3746 l3cfg.l3c_flags = flags; 3747 rv = _bcm_td2_l3_get_host_ent_by_idx(unit, l3_tbl_ptr, mem[tbl], idx, 3748 &l3cfg, &nh_idx); 3749 /* Check for read errors & invalid entries. */ 3750 if (rv < 0) { 3751 if (rv != BCM_E_NOT_FOUND) { 3752 break; 3753 } 3754 /* If not found, reset the return value */ 3755 rv = BCM_E_NONE; 3756 continue; 3757 } 3758 3759 #if defined(BCM_TRIDENT3_SUPPORT) 3760 if (soc_feature(unit, soc_feature_flex_flow) 3761 && (l3cfg.l3c_flow_handle) 3762 && (l3cfg.l3c_flags & BCM_L3_IPMC)) { 3763 LOG_VERBOSE(BSL_LS_BCM_L3, 3764 (BSL_META_U(unit, 3765 "L3 host: IPMC do not compare the l3 entry flags."))); 3766 nh_idx = BCM_XGS3_L3_INVALID_INDEX; 3767 if (BCM_L3_CMP_EQUAL != 3768 _bcm_td3_l3_flex_entry_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 3769 continue; 3770 } 3771 } else 3772 #endif /* BCM_TRIDENT3_SUPPORT */ 3773 { 3774 3775 /* Check read entry flags & update index accordingly. */ 3776 if (BCM_L3_CMP_EQUAL != 3777 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 3778 continue; 3779 } 3780 } 3781 3782 /* If compare function provided match the entry against pattern */ 3783 if (cmp_func) { 3784 rv = (*cmp_func) (unit, pattern, (void *)&l3cfg, 3785 (void *)&nh_idx, &cmp_result); 3786 if (BCM_FAILURE(rv)) { 3787 break; 3788 } 3789 /* If entry doesn't match the pattern don't delete it. */ 3790 if (BCM_L3_CMP_EQUAL != cmp_result) { 3791 continue; 3792 } 3793 } 3794 3795 /* Entry matches the rule -> delete it. */ 3796 rv = _bcm_td2_l3_entry_del(unit, &l3cfg); 3797 if (BCM_FAILURE(rv)) { 3798 break; 3799 } 3800 3801 if (l3cfg.l3c_flags & BCM_L3_MULTIPATH) { 3802 /* Update ECMP reference count */ 3803 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 3804 rv = bcm_xgs3_ecmp_group_del(unit, nh_idx, 0); 3805 } 3806 } else { 3807 /* Release next hop index. */ 3808 rv = bcm_xgs3_nh_del(unit, 0, nh_idx); 3809 } 3810 if (BCM_FAILURE(rv)) { 3811 break; 3812 } 3813 3814 /* Check if notification required. */ 3815 if (notify_cb) { 3816 /* Fill host info. */ 3817 _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info); 3818 /* Call notification callback. */ 3819 (*notify_cb) (unit, idx, &info, user_data); 3820 } 3821 } 3822 3823 if (l3_tbl_ptr) { 3824 soc_cm_sfree(unit, l3_tbl_ptr); 3825 l3_tbl_ptr = NULL; 3826 } 3827 if (BCM_FAILURE(rv)) { 3828 return rv; 3829 } 3830 } 3831 /* Reset last read status. */ 3832 return BCM_E_NONE; 3833 } 3834 3835 /* 3836 * Function: 3837 * _bcm_td2_l3_ipmc_get 3838 * Purpose: 3839 * Get TD2 L3 multicast entry. 3840 * Parameters: 3841 * unit - (IN)SOC unit number. 3842 * l3cfg - (IN/OUT)Group/Source key & Get result buffer. 3843 * Returns: 3844 * BCM_E_XXX 3845 */ 3846 int 3847 _bcm_td2_l3_ipmc_get(int unit, _bcm_l3_cfg_t *l3cfg) 3848 { 3849 uint32 l3x_key[SOC_MAX_MEM_FIELD_WORDS]; /* Lookup key buffer. */ 3850 uint32 l3x_entry[SOC_MAX_MEM_FIELD_WORDS]; /* Search result buffer. */ 3851 int clear_hit; /* Clear hit flag. */ 3852 soc_mem_t mem; /* IPMC table memory. */ 3853 int ipv6; /* IPv6 entry indicator. */ 3854 int rv; /* Return value. */ 3855 int l3_entry_idx; /* Entry index */ 3856 3857 #ifdef BCM_TRIDENT3_SUPPORT 3858 if (soc_feature(unit, soc_feature_flex_flow) && 3859 (l3cfg->l3c_flow_handle != 0)) { 3860 int nh_idx = 0; 3861 int embd = 0; 3862 3863 return _bcm_td3_l3_flex_entry_get(unit, l3cfg, &nh_idx, &embd); 3864 } 3865 #endif 3866 3867 /* Get entry type. */ 3868 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 3869 3870 /* Get table memory. */ 3871 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 3872 mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm; 3873 } else { 3874 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 3875 } 3876 3877 /* Zero buffers. */ 3878 sal_memcpy(l3x_key, soc_mem_entry_null(unit, mem), 3879 soc_mem_entry_words(unit,mem) * 4); 3880 sal_memcpy(l3x_entry, soc_mem_entry_null(unit, mem), 3881 soc_mem_entry_words(unit,mem) * 4); 3882 3883 /* Check if clear hit bit is required. */ 3884 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 3885 3886 /* Lookup Key preparation. */ 3887 rv = _bcm_td2_l3_ipmc_ent_init(unit, (uint32 *)l3x_key, l3cfg); 3888 if (BCM_FAILURE(rv)) { 3889 return rv; 3890 } 3891 3892 /* Perform hw lookup. */ 3893 MEM_LOCK(unit, mem); 3894 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 3895 _BCM_TD2_L3_MEM_BANKS_ALL, 3896 l3x_key, l3x_entry, &l3_entry_idx); 3897 l3cfg->l3c_hw_index = l3_entry_idx; 3898 3899 MEM_UNLOCK(unit, mem); 3900 BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND); 3901 3902 /* Extract buffer information. */ 3903 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ipmc_ent_parse(unit, l3cfg, (void *)l3x_entry)); 3904 3905 /* Clear the HIT bit */ 3906 if (clear_hit) { 3907 BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, l3cfg, l3x_entry, 3908 l3_entry_idx)); 3909 } 3910 return rv; 3911 } 3912 3913 /* 3914 * Function: 3915 * _bcm_td2_l3_ipmc_get_by_idx 3916 * Purpose: 3917 * Get l3 multicast entry by entry index. 3918 * Parameters: 3919 * unit - (IN)SOC unit number. 3920 * dma_ptr - (IN)Table pointer in dma. 3921 * idx - (IN)Index to read. 3922 * l3cfg - (IN/OUT)Entry data. 3923 * Returns: 3924 * BCM_E_XXX 3925 */ 3926 int 3927 _bcm_td2_l3_ipmc_get_by_idx(int unit, void *dma_ptr, 3928 int idx, _bcm_l3_cfg_t *l3cfg) 3929 { 3930 uint32 l3_entry_v6[SOC_MAX_MEM_FIELD_WORDS]; /* Read buffer. */ 3931 uint32 l3_entry_v4[SOC_MAX_MEM_FIELD_WORDS]; /* Read buffer. */ 3932 void *buf_p; /* Hardware buffer ptr */ 3933 soc_mem_t mem; /* IPMC table memory. */ 3934 uint32 ipv6; /* IPv6 entry indicator. */ 3935 int clear_hit; /* Clear hit bit indicator.*/ 3936 int key_type; 3937 soc_field_t l3iif; 3938 uint32 base_valid0, base_valid1, base_valid2, base_valid3; 3939 3940 /* Get entry type. */ 3941 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 3942 3943 /* Get table memory. */ 3944 if (ipv6) { 3945 mem = L3_ENTRY_IPV6_MULTICASTm; 3946 buf_p = (l3_entry_ipv6_multicast_entry_t *)l3_entry_v6; 3947 l3iif = IPV6MC__L3_IIFf; 3948 } else { 3949 mem = L3_ENTRY_IPV4_MULTICASTm; 3950 buf_p = (l3_entry_ipv4_multicast_entry_t *)l3_entry_v4; 3951 l3iif = IPV4MC__L3_IIFf; 3952 } 3953 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 3954 mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm; 3955 if (ipv6) { 3956 buf_p = (l3_entry_quad_entry_t *)l3_entry_v6; 3957 } else { 3958 buf_p = (l3_entry_double_entry_t *)l3_entry_v4; 3959 } 3960 } 3961 3962 /* Check if clear hit is required. */ 3963 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 3964 3965 if (NULL == dma_ptr) { /* Read from hardware. */ 3966 /* Zero buffers. */ 3967 sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 3968 soc_mem_entry_words(unit,mem) * 4); 3969 3970 /* Read entry from hw. */ 3971 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_p)); 3972 } else { /* Read from dma. */ 3973 if (ipv6) { 3974 if (soc_mem_is_valid(unit, L3_ENTRY_QUADm)) { 3975 buf_p = soc_mem_table_idx_to_pointer(unit, mem, 3976 l3_entry_quad_entry_t *, dma_ptr, idx); 3977 } else { 3978 buf_p = soc_mem_table_idx_to_pointer(unit, mem, 3979 l3_entry_ipv6_multicast_entry_t *, dma_ptr, idx); 3980 } 3981 } else { 3982 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 3983 buf_p = soc_mem_table_idx_to_pointer(unit, mem, 3984 l3_entry_double_entry_t *, dma_ptr, idx); 3985 } else { 3986 buf_p = soc_mem_table_idx_to_pointer(unit, mem, 3987 l3_entry_ipv4_multicast_entry_t *, dma_ptr, idx); 3988 } 3989 } 3990 } 3991 3992 /* Ignore invalid entries. */ 3993 if (soc_feature(unit, soc_feature_base_valid)) { 3994 if (ipv6) { 3995 if (SOC_IS_TOMAHAWK3(unit)) 3996 { 3997 base_valid0 = 1; 3998 base_valid1 = 2; 3999 base_valid2 = 2; 4000 base_valid3 = 7; 4001 } 4002 else 4003 { 4004 base_valid0 = 5; 4005 base_valid1 = 6; 4006 base_valid2 = 6; 4007 base_valid3 = 7; 4008 } 4009 4010 if (soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_0f) != base_valid0 || 4011 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_1f) != base_valid1 || 4012 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_2f) != base_valid2 || 4013 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_3f) != base_valid3) { 4014 return (BCM_E_NOT_FOUND); 4015 } 4016 } else { 4017 if (SOC_IS_TOMAHAWK3(unit)) 4018 { 4019 base_valid0 = 1; 4020 base_valid1 = 7; 4021 } 4022 else 4023 { 4024 base_valid0 = 3; 4025 base_valid1 = 4; 4026 } 4027 if (soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_0f) != base_valid0 || 4028 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_1f) != base_valid1) { 4029 return (BCM_E_NOT_FOUND); 4030 } 4031 } 4032 key_type = soc_mem_field32_get(unit, mem, buf_p, KEY_TYPEf); 4033 } else { 4034 if (!soc_mem_field32_get(unit, mem, buf_p, VALID_0f)) { 4035 return (BCM_E_NOT_FOUND); 4036 } 4037 4038 key_type = soc_mem_field32_get(unit, mem, buf_p, KEY_TYPE_0f); 4039 } 4040 4041 switch (key_type) { 4042 case TD2_L3_HASH_KEY_TYPE_V4L2MC: 4043 case TD2_L3_HASH_KEY_TYPE_V4L2VPMC: 4044 l3cfg->l3c_flags = BCM_L3_IPMC | BCM_L3_L2ONLY; 4045 break; 4046 case TD2_L3_HASH_KEY_TYPE_V4MC: 4047 l3cfg->l3c_flags = BCM_L3_IPMC; 4048 break; 4049 case TD2_L3_HASH_KEY_TYPE_V6L2MC: 4050 case TD2_L3_HASH_KEY_TYPE_V6L2VPMC: 4051 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC | BCM_L3_L2ONLY; 4052 break; 4053 case TD2_L3_HASH_KEY_TYPE_V6MC: 4054 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 4055 break; 4056 default: 4057 /* Catch all other key types, set flags to zero so that the 4058 * following flag check is effective for all key types */ 4059 l3cfg->l3c_flags = 0; 4060 break; 4061 } 4062 4063 /* Ignore protocol mismatch & multicast entries. */ 4064 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 4065 (!(l3cfg->l3c_flags & BCM_L3_IPMC))) { 4066 return (BCM_E_NOT_FOUND); 4067 } 4068 4069 /* Set index to l3cfg. */ 4070 l3cfg->l3c_hw_index = idx; 4071 4072 if (ipv6) { 4073 /* Get group address. */ 4074 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_64f, 4075 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 4076 4077 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_56f, 4078 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 4079 4080 /* Get source address. */ 4081 if (soc_mem_field_valid(unit, mem, IPV6MC__SOURCE_IP_ADDR_BITS_63_32f)) { 4082 soc_mem_ip6_addr_get(unit, mem, buf_p, 4083 IPV6MC__SOURCE_IP_ADDR_BITS_63_32f, l3cfg->l3c_sip6, 4084 SOC_MEM_IP6_BITS_63_32); 4085 soc_mem_ip6_addr_get(unit, mem, buf_p, 4086 IPV6MC__SOURCE_IP_ADDR_BITS_31_0f, l3cfg->l3c_sip6, 4087 SOC_MEM_IP6_BITS_31_0); 4088 } else { 4089 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 4090 l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY); 4091 } 4092 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 4093 l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY); 4094 4095 l3cfg->l3c_ip6[0] = 0xff; /* Set entry to multicast*/ 4096 } else { 4097 /* Get group id. */ 4098 l3cfg->l3c_ip_addr = 4099 soc_mem_field32_get(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf); 4100 4101 /* Get source address. */ 4102 l3cfg->l3c_src_ip_addr = 4103 soc_mem_field32_get(unit, mem, buf_p, IPV4MC__SOURCE_IP_ADDRf); 4104 } 4105 4106 /* Get L3_IIF or vlan id. */ 4107 l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, l3iif); 4108 4109 /* Parse entry data. */ 4110 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ipmc_ent_parse(unit, l3cfg, buf_p)); 4111 4112 /* Clear the HIT bit */ 4113 if (clear_hit) { 4114 BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, l3cfg, buf_p, 4115 l3cfg->l3c_hw_index)); 4116 } 4117 return (BCM_E_NONE); 4118 } 4119 4120 /* 4121 * Function: 4122 * _bcm_td2_l3_ipmc_add 4123 * Purpose: 4124 * Add TD2 L3 multicast entry. 4125 * Parameters: 4126 * unit - (IN)SOC unit number. 4127 * l3cfg - (IN/OUT)Group/Source key. 4128 * Returns: 4129 * BCM_E_XXX 4130 */ 4131 int 4132 _bcm_td2_l3_ipmc_add(int unit, _bcm_l3_cfg_t *l3cfg) 4133 { 4134 uint32 l3x_entry[SOC_MAX_MEM_FIELD_WORDS]; /* Write entry buffer. */ 4135 soc_mem_t mem; /* IPMC table memory. */ 4136 uint32 *buf_p; /* HW buffer address. */ 4137 int ipv6; /* IPv6 entry indicator. */ 4138 int idx; /* Iteration index. */ 4139 int idx_max; /* Iteration index max. */ 4140 int rv; /* Return value. */ 4141 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f}; 4142 soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, l3mc_idx_l2, class_id, pri, rpa_id; 4143 soc_field_t exp_iif, exp_iif_drop, exp_iif_copytocpu; 4144 soc_field_t flex_ctr_base_counter_idx; 4145 soc_field_t flex_ctr_offset_mode; 4146 soc_field_t flex_ctr_pool_number; 4147 #ifdef BCM_MONTEREY_SUPPORT 4148 soc_field_t roe_decap; 4149 #endif 4150 4151 #ifdef BCM_TRIDENT3_SUPPORT 4152 if (soc_feature(unit, soc_feature_flex_flow) && 4153 (l3cfg->l3c_flow_handle != 0)) { 4154 return _bcm_td3_l3_flex_entry_add(unit, l3cfg, 0); 4155 } 4156 #endif 4157 4158 /* Get entry type. */ 4159 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 4160 4161 /* Get table memory and table fields */ 4162 if (ipv6) { 4163 if (soc_mem_is_valid(unit, L3_ENTRY_QUADm)) { 4164 mem = L3_ENTRY_QUADm; 4165 l3mc_idx = IPV6MC__DESTINATIONf; 4166 if (soc_feature(unit, soc_feature_generic_dest)) { 4167 l3mc_idx = IPV6MC__DESTINATIONf; 4168 } else { 4169 l3mc_idx = IPV6MC__L3MC_INDEXf; 4170 } 4171 l3mc_idx_l2 = IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf; 4172 } else { 4173 mem = L3_ENTRY_IPV6_MULTICASTm; 4174 l3mc_idx = IPV6MC__L3MC_INDEXf; 4175 l3mc_idx_l2 = INVALIDf; 4176 } 4177 pri = IPV6MC__PRIf; 4178 rpe = IPV6MC__RPEf; 4179 vrf_id = IPV6MC__VRF_IDf; 4180 class_id = IPV6MC__CLASS_IDf; 4181 dst_discard = IPV6MC__DST_DISCARDf; 4182 rpa_id = IPV6MC__RPA_IDf; 4183 exp_iif = IPV6MC__EXPECTED_L3_IIFf; 4184 exp_iif_drop = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf; 4185 exp_iif_copytocpu = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf; 4186 flex_ctr_base_counter_idx = IPV6MC__FLEX_CTR_BASE_COUNTER_IDXf; 4187 flex_ctr_offset_mode = IPV6MC__FLEX_CTR_OFFSET_MODEf; 4188 flex_ctr_pool_number = IPV6MC__FLEX_CTR_POOL_NUMBERf; 4189 #ifdef BCM_MONTEREY_SUPPORT 4190 roe_decap = IPV6MC__ROE_DECAPf; 4191 #endif 4192 } else { 4193 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 4194 mem = L3_ENTRY_DOUBLEm; 4195 if (soc_feature(unit, soc_feature_generic_dest)) { 4196 l3mc_idx = IPV4MC__DESTINATIONf; 4197 } else { 4198 l3mc_idx = IPV4MC__L3MC_INDEXf; 4199 } 4200 l3mc_idx_l2 = IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf; 4201 } else { 4202 mem = L3_ENTRY_IPV4_MULTICASTm; 4203 l3mc_idx = IPV4MC__L3MC_INDEXf; 4204 l3mc_idx_l2 = INVALIDf; 4205 } 4206 4207 pri = IPV4MC__PRIf; 4208 rpe = IPV4MC__RPEf; 4209 vrf_id = IPV4MC__VRF_IDf; 4210 class_id = IPV4MC__CLASS_IDf; 4211 dst_discard = IPV4MC__DST_DISCARDf; 4212 rpa_id = IPV4MC__RPA_IDf; 4213 exp_iif = IPV4MC__EXPECTED_L3_IIFf; 4214 exp_iif_drop = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf; 4215 exp_iif_copytocpu = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf; 4216 flex_ctr_base_counter_idx = IPV4MC__FLEX_CTR_BASE_COUNTER_IDXf; 4217 flex_ctr_offset_mode = IPV4MC__FLEX_CTR_OFFSET_MODEf; 4218 flex_ctr_pool_number = IPV4MC__FLEX_CTR_POOL_NUMBERf; 4219 #ifdef BCM_MONTEREY_SUPPORT 4220 roe_decap = IPV4MC__ROE_DECAPf; 4221 #endif 4222 } 4223 4224 /* Zero buffers. */ 4225 buf_p = l3x_entry; 4226 sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 4227 soc_mem_entry_words(unit,mem) * 4); 4228 4229 /* Prepare entry to write. */ 4230 rv = _bcm_td2_l3_ipmc_ent_init(unit, l3x_entry, l3cfg); 4231 if (BCM_FAILURE(rv)) { 4232 return rv; 4233 } 4234 4235 /* Set priority override bit. */ 4236 if (l3cfg->l3c_flags & BCM_L3_RPE) { 4237 soc_mem_field32_set(unit, mem, buf_p, rpe, 1); 4238 } 4239 4240 /* Set destination discard. */ 4241 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 4242 soc_mem_field32_set(unit, mem, buf_p, dst_discard, 1); 4243 } 4244 4245 /* Virtual router id. */ 4246 soc_mem_field32_set(unit, mem, buf_p, vrf_id, l3cfg->l3c_vrf); 4247 4248 /* Set priority. */ 4249 soc_mem_field32_set(unit, mem, buf_p, pri, l3cfg->l3c_prio); 4250 4251 /* Pointer to ipmc table. */ 4252 if (soc_feature(unit, soc_feature_generic_dest)) { 4253 soc_mem_field32_dest_set(unit, mem, buf_p, l3mc_idx, 4254 SOC_MEM_FIF_DEST_IPMC, l3cfg->l3c_ipmc_ptr); 4255 } else { 4256 soc_mem_field32_set(unit, mem, buf_p, l3mc_idx, l3cfg->l3c_ipmc_ptr); 4257 } 4258 4259 /* Set L3MC_INDEX_FOR_L2_DISTRIBUTION */ 4260 if (l3mc_idx_l2 != INVALIDf && soc_mem_field_valid(unit, mem, l3mc_idx_l2)) { 4261 soc_mem_field32_set(unit, mem, buf_p, l3mc_idx_l2, l3cfg->l3c_ipmc_ptr_l2); 4262 } 4263 4264 /* Classification lookup class id. */ 4265 soc_mem_field32_set(unit, mem, buf_p, class_id, l3cfg->l3c_lookup_class); 4266 4267 /* Rendezvous point ID. */ 4268 if (SOC_MEM_FIELD_VALID(unit, mem, rpa_id)) { 4269 if (l3cfg->l3c_rp_id != BCM_IPMC_RP_ID_INVALID) { 4270 soc_mem_field32_set(unit, mem, buf_p, rpa_id, l3cfg->l3c_rp_id); 4271 } 4272 } 4273 4274 /* RPF */ 4275 if ((BCM_IPMC_POST_LOOKUP_RPF_CHECK & l3cfg->l3c_flags) && 4276 (0 != l3cfg->l3c_intf)) { 4277 /* Set Expected_IIF to L3_IIF*/ 4278 soc_mem_field32_set(unit, mem, buf_p, exp_iif, l3cfg->l3c_intf); 4279 if (BCM_IPMC_RPF_FAIL_DROP & l3cfg->l3c_flags) { 4280 soc_mem_field32_set(unit, mem, buf_p, exp_iif_drop, 1); 4281 } 4282 if (BCM_IPMC_RPF_FAIL_TOCPU & l3cfg->l3c_flags) { 4283 soc_mem_field32_set(unit, mem, buf_p, exp_iif_copytocpu, 1); 4284 } 4285 } 4286 4287 idx_max = (ipv6) ? 4 : 2; 4288 for (idx = 0; idx < idx_max; idx++) { 4289 /* Set hit bit. */ 4290 if (l3cfg->l3c_flags & BCM_L3_HIT) { 4291 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 1); 4292 } 4293 } 4294 4295 4296 if (!SOC_IS_MONTEREY(unit)) { 4297 /* Base counter index. */ 4298 soc_mem_field32_set(unit, mem, buf_p, flex_ctr_base_counter_idx, 4299 l3cfg->l3c_flex_ctr_base_id); 4300 /* Counter offset mode. */ 4301 soc_mem_field32_set(unit, mem, buf_p, flex_ctr_offset_mode, 4302 l3cfg->l3c_flex_ctr_mode); 4303 /* Counter pool number. */ 4304 soc_mem_field32_set(unit, mem, buf_p, flex_ctr_pool_number, 4305 l3cfg->l3c_flex_ctr_pool); 4306 } 4307 4308 #ifdef BCM_MONTEREY_SUPPORT 4309 if (soc_feature(unit, soc_feature_roe) || 4310 soc_feature(unit, soc_feature_roe_custom)) { 4311 if (SOC_MEM_FIELD_VALID(unit, mem, roe_decap)) { 4312 if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) { 4313 soc_mem_field32_set(unit, mem, buf_p, roe_decap, 1); 4314 } 4315 } 4316 } 4317 #endif 4318 4319 /* Write entry to the hw. */ 4320 MEM_LOCK(unit, mem); 4321 /* Handle replacement. */ 4322 if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) { 4323 rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p); 4324 } else { 4325 rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)buf_p); 4326 } 4327 4328 /* Increment number of ipmc routes. */ 4329 if (BCM_SUCCESS(rv) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 4330 (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)++ : \ 4331 BCM_XGS3_L3_IP4_IPMC_CNT(unit)++; 4332 } 4333 /* coverity[overrun-local : FALSE] */ 4334 MEM_UNLOCK(unit, mem); 4335 return rv; 4336 } 4337 4338 /* 4339 * Function: 4340 * _bcm_td2_l3_ipmc_del 4341 * Purpose: 4342 * Delete TD2 L3 multicast entry. 4343 * Parameters: 4344 * unit - (IN)SOC unit number. 4345 * l3cfg - (IN)Group/Source deletion key. 4346 * Returns: 4347 * BCM_E_XXX 4348 */ 4349 int 4350 _bcm_td2_l3_ipmc_del(int unit, _bcm_l3_cfg_t *l3cfg) 4351 { 4352 uint32 l3x_entry[SOC_MAX_MEM_FIELD_WORDS]; /* Delete buffer. */ 4353 soc_mem_t mem; /* IPMC table memory. */ 4354 int ipv6; /* IPv6 entry indicator. */ 4355 int rv; /* Operation return value. */ 4356 4357 #ifdef BCM_TRIDENT3_SUPPORT 4358 if (soc_feature(unit, soc_feature_flex_flow) && 4359 (l3cfg->l3c_flow_handle != 0)) { 4360 return _bcm_td3_l3_flex_entry_del(unit, l3cfg); 4361 } 4362 #endif 4363 4364 /* Get entry type. */ 4365 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 4366 4367 /* Get table memory. */ 4368 if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) { 4369 mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm; 4370 } else { 4371 mem = (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm; 4372 } 4373 4374 /* Zero entry buffer. */ 4375 sal_memcpy(l3x_entry, soc_mem_entry_null(unit, mem), 4376 soc_mem_entry_words(unit,mem) * 4); 4377 4378 4379 /* Key preparation. */ 4380 rv = _bcm_td2_l3_ipmc_ent_init(unit, l3x_entry, l3cfg); 4381 if (BCM_FAILURE(rv)) { 4382 return rv; 4383 } 4384 4385 /* Delete the entry from hw. */ 4386 MEM_LOCK(unit, mem); 4387 4388 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)l3x_entry); 4389 4390 /* Decrement number of ipmc routes. */ 4391 if (BCM_SUCCESS(rv)) { 4392 (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)-- : \ 4393 BCM_XGS3_L3_IP4_IPMC_CNT(unit)--; 4394 } 4395 MEM_UNLOCK(unit, mem); 4396 return rv; 4397 } 4398 4399 /* 4400 * FLEX STAT FUNCTIONS for L3 ROUTE and L3 NAT 4401 * 4402 * This following functions implements flex stat routines to attach, detach and get/set 4403 * flex counter functions. 4404 * 4405 * FLEX ATTACH 4406 * The function allocates flex counter from the counter pool and configures 4407 * attributes to set the base counter index and base offset. Flex counter pool, 4408 * base index and offset is associated to the table index request for the 4409 * module identifiers like, vpn, port, vp Additionally the reference counter 4410 * for the flex counter is incremented for multple references of the counter. 4411 * 4412 * FLEX DETACH 4413 * The function disassociates flex counter details assigned during flex attach 4414 * and decrements the reference counter. 4415 * 4416 * FLEX COUNTER GET/SET 4417 * The function read/set the associate counter values. Set is required for the 4418 * purpose of clearing the counter. 4419 * 4420 * 4421 * FLEX COUNTER MULTI GET/SET 4422 * The function reads/sets multiple flex stats and returns the counter arrays. 4423 * 4424 * FLEX STAT ID 4425 * The funciton retrieves the stat id for the given module identifiers. The 4426 * flex counter stat id has the following format. 4427 * 4428 * (8 modes) (32 groups) (16 pools) (32 objIds) (64K index) 4429 * +---------+------------+----------+-----------+-----------------+ 4430 * | | | | | | 4431 * | ModeId | GroupMode | PoolId | Account | Base Index | 4432 * | | | | objectId | | 4433 * +---------+------------+----------+-----------+-----------------+ 4434 * (31) (29)(28) (24)(23) (20)(19) (15)(14) (0) 4435 * 4436 * 4437 * PoolId : Counter pool no. 4438 * ( TD2: Ingress(8 pool x 4k counters) 4439 * Egress (4 pool x 4k counters) 4440 * GroupMode : Attribute group mode determines base offset and no. of counters 4441 * ModeId : Ingress/Egress Modes 4442 * Base Idx : Index into counter block of 256 counters 4443 * Account Obj : Flexible accounting objects 4444 */ 4445 4446 /* 4447 * Function: 4448 * _bcm_td2_l3_route_stat_get_table_info 4449 * Description: 4450 * Provides relevant flex table information(table-name,index with 4451 * direction) for given ingress interface. 4452 * 4453 * Parameters: 4454 * unit - (IN) unit number 4455 * info - (IN) L3 Route Info 4456 * num_of_tables - (OUT) Number of flex counter tables 4457 * table_info - (OUT) Flex counter tables information 4458 * 4459 * Return Value: 4460 * BCM_E_XXX 4461 * Notes: 4462 */ 4463 #ifdef BCM_TOMAHAWK_SUPPORT 4464 #ifdef ALPM_ENABLE 4465 #define ALPM_BKT_NODE_PTR_CNT 32768 4466 /* No need per unit setting */ 4467 uint32 *alpm_bkt_node_ptr[ALPM_BKT_NODE_PTR_CNT]; 4468 4469 uint32 *alpm_bkt_node_ptr_arr_get(uint32 idx) 4470 { 4471 if (idx >= 0 && idx < ALPM_BKT_NODE_PTR_CNT) { 4472 return alpm_bkt_node_ptr[idx]; 4473 } 4474 4475 return NULL; 4476 } 4477 4478 int alpm_bkt_node_ptr_arr_idx_get(uint32 *bkt_node_ptr, uint32 *idx) 4479 { 4480 int i; 4481 4482 for (i = 0; i < ALPM_BKT_NODE_PTR_CNT; i++) { 4483 if (alpm_bkt_node_ptr[i] == bkt_node_ptr) { 4484 *idx = i; 4485 return BCM_E_NONE; 4486 } 4487 } 4488 4489 return BCM_E_NOT_FOUND; 4490 } 4491 4492 int alpm_bkt_node_ptr_arr_add(uint32 *bkt_node_ptr, uint32 *idx) 4493 { 4494 int i, first_null_idx = -1; 4495 4496 for (i = 0; i < ALPM_BKT_NODE_PTR_CNT; i++) { 4497 if (alpm_bkt_node_ptr[i] == bkt_node_ptr) { 4498 *idx = i; 4499 return BCM_E_EXISTS; 4500 } 4501 4502 if (first_null_idx == -1 && alpm_bkt_node_ptr[i] == NULL) { 4503 first_null_idx = i; 4504 } 4505 } 4506 4507 if (first_null_idx == -1) { 4508 return BCM_E_FULL; 4509 } else { 4510 alpm_bkt_node_ptr[first_null_idx] = bkt_node_ptr; 4511 *idx = first_null_idx; 4512 return BCM_E_NONE; 4513 } 4514 } 4515 4516 int alpm_bkt_node_ptr_arr_del(uint32 *bkt_node_ptr) 4517 { 4518 int i; 4519 4520 for (i = 0; i < ALPM_BKT_NODE_PTR_CNT; i++) { 4521 if (alpm_bkt_node_ptr[i] == bkt_node_ptr) { 4522 alpm_bkt_node_ptr[i] = NULL; 4523 return BCM_E_NONE; 4524 } 4525 } 4526 4527 return BCM_E_NOT_FOUND; 4528 } 4529 4530 #endif /* ALPM_ENABLE */ 4531 #endif 4532 static 4533 bcm_error_t _bcm_td2_l3_route_stat_get_table_info( 4534 int unit, 4535 bcm_l3_route_t *info, 4536 uint32 *num_of_tables, 4537 bcm_stat_flex_table_info_t *table_info, 4538 _bcm_defip_cfg_t *defip_copy) 4539 { 4540 int rv; 4541 int index, scale; 4542 soc_mem_t mem; 4543 int max_prefix_length; 4544 _bcm_defip_cfg_t defip; 4545 soc_mem_t defip_mem = L3_DEFIPm; 4546 soc_mem_t defip_pair_mem = L3_DEFIP_PAIR_128m; 4547 4548 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 4549 defip_mem = L3_DEFIP_LEVEL1m; 4550 defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m; 4551 } 4552 4553 if (!soc_feature(unit,soc_feature_advanced_flex_counter)) { 4554 return BCM_E_UNAVAIL; 4555 } 4556 4557 /* Make sure module was initialized. */ 4558 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 4559 return (BCM_E_INIT); 4560 } 4561 4562 /* Vrf is in device supported range check. */ 4563 if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 4564 (info->l3a_vrf < BCM_L3_VRF_GLOBAL)) { 4565 return BCM_E_PARAM; 4566 } 4567 4568 /* Check that device supports ipv6. */ 4569 if (BCM_L3_NO_IP6_SUPPORT(unit, info->l3a_flags)) { 4570 return BCM_E_UNAVAIL; 4571 } 4572 4573 mem = defip_mem; 4574 scale = 1; 4575 4576 sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t)); 4577 defip.defip_flags = info->l3a_flags; 4578 defip.defip_vrf = info->l3a_vrf; 4579 4580 L3_LOCK(unit); 4581 if (info->l3a_flags & BCM_L3_IP6) { 4582 #if defined(BCM_TRIDENT3_SUPPORT) 4583 if (SOC_IS_TRIDENT3X(unit) && soc_feature(unit, soc_feature_flex_flow) 4584 && (info->flow_handle != 0)) { 4585 soc_mem_t view_id; 4586 soc_flow_db_mem_view_info_t vinfo; 4587 4588 BCM_IF_ERROR_RETURN( 4589 soc_flow_db_ffo_to_mem_view_id_get(unit, 4590 info->flow_handle, 4591 info->flow_option_handle, 4592 SOC_FLOW_DB_FUNC_L3_ROUTE_ID, 4593 (uint32 *)&view_id)); 4594 BCM_IF_ERROR_RETURN(soc_flow_db_mem_view_info_get(unit, view_id, &vinfo)); 4595 mem = vinfo.mem; 4596 } else 4597 #endif /* BCM_TRIDENT3_SUPPORT */ 4598 { 4599 max_prefix_length = 4600 soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ? 128 : 64; 4601 sal_memcpy(defip.defip_ip6_addr, info->l3a_ip6_net, BCM_IP6_ADDRLEN); 4602 defip.defip_sub_len = bcm_ip6_mask_length(info->l3a_ip6_mask); 4603 if (defip.defip_sub_len > max_prefix_length) { 4604 L3_UNLOCK(unit); 4605 return BCM_E_PARAM; 4606 } 4607 if (defip.defip_sub_len > 64) { 4608 if (SOC_PERSIST(unit)->memState[defip_pair_mem].index_max >= 0) { 4609 mem = defip_pair_mem; 4610 } 4611 } else { 4612 scale = 2; 4613 } 4614 } 4615 rv = mbcm_driver[unit]->mbcm_ip6_defip_cfg_get(unit, &defip); 4616 } else { 4617 defip.defip_ip_addr = info->l3a_subnet & info->l3a_ip_mask; 4618 defip.defip_sub_len = bcm_ip_mask_length(info->l3a_ip_mask); 4619 rv = mbcm_driver[unit]->mbcm_ip4_defip_cfg_get(unit, &defip); 4620 } 4621 4622 L3_UNLOCK(unit); 4623 if (rv < 0) { 4624 return rv; 4625 } 4626 4627 index = defip.defip_index * scale; 4628 4629 #ifdef ALPM_ENABLE 4630 if (soc_feature(unit, soc_feature_alpm) && 4631 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 4632 4633 if (defip.defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT) { 4634 /* override table and index to ALPM format */ 4635 if (soc_feature(unit, soc_feature_alpm2)) { 4636 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_RAWm)) { 4637 mem = L3_DEFIP_ALPM_RAWm; 4638 } else { 4639 if (soc_property_get(unit, "l3_alpm2_level", 3) == 2) { 4640 mem = L3_DEFIP_ALPM_LEVEL2m; 4641 } else { 4642 mem = L3_DEFIP_ALPM_LEVEL3m; 4643 } 4644 } 4645 } else { 4646 if (info->l3a_flags & BCM_L3_IP6) { 4647 if (soc_mem_index_count(unit, defip_pair_mem)) { 4648 mem = L3_DEFIP_ALPM_IPV6_128m; 4649 } else { 4650 mem = L3_DEFIP_ALPM_IPV6_64_1m; 4651 } 4652 } else { 4653 mem = L3_DEFIP_ALPM_IPV4_1m; 4654 } 4655 if (mem == L3_DEFIP_ALPM_IPV6_64_1m || mem == L3_DEFIP_ALPM_IPV4_1m) { 4656 if (!(defip.defip_alpm_cookie & SOC_ALPM_COOKIE_FLEX)) { 4657 return BCM_E_PARAM; 4658 } 4659 } 4660 } 4661 index = ALPM_ENT_INDEX(defip.defip_index); 4662 if (defip_copy) { 4663 sal_memcpy(defip_copy, &defip, sizeof(defip)); 4664 } 4665 } else { /* Entries in TCAM, like Global High, IPMC */ 4666 index = defip.defip_index; 4667 if (info->l3a_flags & BCM_L3_IP6) { 4668 if (soc_mem_index_count(unit, defip_pair_mem)) { 4669 mem = defip_pair_mem; 4670 } else { 4671 mem = defip_mem; 4672 index *= 2; 4673 } 4674 } else { 4675 mem = defip_mem; 4676 } 4677 if (defip_copy) { 4678 sal_memcpy(defip_copy, &defip, sizeof(defip)); 4679 } 4680 } 4681 } 4682 #endif 4683 4684 table_info[*num_of_tables].table = mem; 4685 table_info[*num_of_tables].index = index; 4686 table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress; 4687 (*num_of_tables)++; 4688 4689 LOG_INFO(BSL_LS_BCM_L3, 4690 (BSL_META_U(unit, 4691 "L3 Route Stat: table = %s, index = %d\n"), 4692 SOC_MEM_NAME(unit, mem), index)); 4693 4694 return BCM_E_NONE; 4695 } 4696 4697 4698 /* 4699 * Function: 4700 * _bcm_td2_l3_route_stat_attach 4701 * Description: 4702 * Attach counters entries to the given l3 route defip index . Allocate 4703 * flex counter and assign counter index and offset for the index pointed 4704 * by l3 defip index 4705 * 4706 * Parameters: 4707 * unit - (IN) unit number 4708 * info - (IN) L3 Route Info 4709 * stat_counter_id - (IN) Stat Counter ID. 4710 * 4711 * Return Value: 4712 * BCM_E_XXX 4713 * Notes: 4714 */ 4715 4716 bcm_error_t _bcm_td2_l3_route_stat_attach ( 4717 int unit, 4718 bcm_l3_route_t *info, 4719 uint32 stat_counter_id) 4720 { 4721 int rv = BCM_E_NONE; 4722 int counter_flag = 0; 4723 soc_mem_t table[5] = {INVALIDm}; 4724 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 4725 uint32 pool_number = 0; 4726 uint32 base_index = 0; 4727 bcm_stat_flex_mode_t offset_mode = 0; 4728 bcm_stat_object_t object = bcmStatObjectIngPort; 4729 bcm_stat_group_mode_t group_mode = bcmStatGroupModeSingle; 4730 uint32 count = 0; 4731 uint32 actual_num_tables = 0; 4732 uint32 flex_table_index = 0; 4733 uint32 num_of_tables = 0; 4734 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 4735 _bcm_defip_cfg_t defip; 4736 4737 4738 /* Get pool, base index group mode and offset modes from stat counter id */ 4739 _bcm_esw_stat_get_counter_id_info( 4740 unit, stat_counter_id, 4741 &group_mode, &object, &offset_mode, &pool_number, &base_index); 4742 4743 /* Validate object and group mode */ 4744 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction)); 4745 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit, group_mode)); 4746 4747 /* Get Table index to attach flexible counter */ 4748 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info( 4749 unit, object, 5, &actual_num_tables, &table[0], &direction)); 4750 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info( 4751 unit, info, &num_of_tables, &table_info[0], &defip)); 4752 4753 #ifdef ALPM_ENABLE 4754 #ifdef BCM_TOMAHAWK_SUPPORT 4755 if (soc_feature(unit, soc_feature_alpm2) && 4756 (table_info[0].table == L3_DEFIP_ALPM_RAWm || 4757 table_info[0].table == L3_DEFIP_ALPM_LEVEL2m || 4758 table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) { 4759 /* flex counter only available in Full route data mode, 4760 ALPM_ROUTE_FULL_MD is same as SOC_ALPM_COOKIE_FLEX */ 4761 if ((defip.defip_alpm_cookie & ALPM_ROUTE_FULL_MD) == 0) { 4762 return BCM_E_UNAVAIL; 4763 } 4764 4765 rv = alpm_bkt_node_ptr_arr_add(defip.bkt_node, &table_info[0].index); 4766 if (rv == BCM_E_FULL) { 4767 return rv; 4768 } 4769 } 4770 #endif 4771 #endif 4772 4773 for (count = 0; count < num_of_tables; count++) { 4774 for (flex_table_index=0; 4775 flex_table_index < actual_num_tables ; 4776 flex_table_index++) { 4777 if ((table_info[count].direction == direction) && 4778 (table_info[count].table == table[flex_table_index]) ) { 4779 if (direction == bcmStatFlexDirectionIngress) { 4780 counter_flag = 1; 4781 rv = _bcm_esw_stat_flex_attach_ingress_table_counters( 4782 unit, 4783 table_info[count].table, 4784 table_info[count].index, 4785 offset_mode, 4786 base_index, 4787 pool_number); 4788 if (BCM_FAILURE(rv)) { 4789 break; 4790 } 4791 } else { 4792 counter_flag = 1; 4793 rv = _bcm_esw_stat_flex_attach_egress_table_counters( 4794 unit, 4795 table_info[count].table, 4796 table_info[count].index, 4797 0, 4798 offset_mode, 4799 base_index, 4800 pool_number); 4801 4802 if(BCM_FAILURE(rv)) { 4803 break; 4804 } 4805 } 4806 } 4807 } 4808 } 4809 4810 if (counter_flag == 0) { 4811 rv = BCM_E_NOT_FOUND; 4812 } 4813 4814 if (BCM_FAILURE(rv)) { 4815 return rv; 4816 } 4817 4818 #ifdef ALPM_ENABLE 4819 if (soc_feature(unit, soc_feature_alpm) && 4820 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 4821 4822 if (defip.defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT) { 4823 /* for ALPM, need call add to trigger propation */ 4824 L3_LOCK(unit); 4825 defip.defip_flags |= BCM_L3_REPLACE; 4826 if (info->l3a_flags & BCM_L3_IP6) { 4827 rv = mbcm_driver[unit]->mbcm_ip6_defip_add(unit, &defip); 4828 } else { 4829 rv = mbcm_driver[unit]->mbcm_ip4_defip_add(unit, &defip); 4830 } 4831 L3_UNLOCK(unit); 4832 } 4833 } 4834 #endif 4835 4836 return rv; 4837 } 4838 4839 4840 /* 4841 * Function: 4842 * _bcm_td2_l3_route_stat_detach 4843 * Description: 4844 * Detach counter entries to the given l3 route index. 4845 * 4846 * Parameters: 4847 * unit - (IN) unit number 4848 * info - (IN) L3 Route Info 4849 * 4850 * Return Value: 4851 * BCM_E_XXX 4852 * Notes: 4853 */ 4854 bcm_error_t _bcm_td2_l3_route_stat_detach ( 4855 int unit, 4856 bcm_l3_route_t *info) 4857 { 4858 uint32 count = 0; 4859 uint32 num_of_tables = 0; 4860 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 4861 bcm_error_t rv = BCM_E_NONE; 4862 bcm_error_t err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE}; 4863 _bcm_defip_cfg_t defip; 4864 4865 /* Get the table index to be detached */ 4866 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info( 4867 unit, info, &num_of_tables, &table_info[0], &defip)); 4868 4869 #ifdef ALPM_ENABLE 4870 #ifdef BCM_TOMAHAWK_SUPPORT 4871 if (soc_feature(unit, soc_feature_alpm2) && 4872 (table_info[0].table == L3_DEFIP_ALPM_RAWm || 4873 table_info[0].table == L3_DEFIP_ALPM_LEVEL2m || 4874 table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) { 4875 /* flex counter only available in Full route data mode, 4876 ALPM_ROUTE_FULL_MD is same as SOC_ALPM_COOKIE_FLEX */ 4877 if ((defip.defip_alpm_cookie & ALPM_ROUTE_FULL_MD) == 0) { 4878 return BCM_E_UNAVAIL; 4879 } 4880 4881 BCM_IF_ERROR_RETURN( 4882 alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index)); 4883 } 4884 #endif 4885 #endif 4886 4887 for (count = 0; count < num_of_tables; count++) { 4888 if (table_info[count].direction == bcmStatFlexDirectionIngress) { 4889 rv = _bcm_esw_stat_flex_detach_ingress_table_counters( 4890 unit, table_info[count].table, table_info[count].index); 4891 if (BCM_E_NONE != rv && 4892 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) { 4893 err_code[bcmStatFlexDirectionIngress] = rv; 4894 } 4895 } else { 4896 rv = _bcm_esw_stat_flex_detach_egress_table_counters( 4897 unit, 0, table_info[count].table, table_info[count].index); 4898 if (BCM_E_NONE != rv && 4899 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) { 4900 err_code[bcmStatFlexDirectionEgress] = rv; 4901 } 4902 } 4903 } 4904 4905 #ifdef ALPM_ENABLE 4906 #ifdef BCM_TOMAHAWK_SUPPORT 4907 if (soc_feature(unit, soc_feature_alpm2) && 4908 table_info[0].table == L3_DEFIP_ALPM_RAWm) { 4909 (void)alpm_bkt_node_ptr_arr_del(defip.bkt_node); 4910 } 4911 #endif 4912 #endif 4913 4914 BCM_STAT_FLEX_DETACH_RV_SET(rv, err_code) 4915 4916 if (BCM_FAILURE(rv)) { 4917 return rv; 4918 } 4919 4920 #ifdef ALPM_ENABLE 4921 if (soc_feature(unit, soc_feature_alpm) && 4922 soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) { 4923 4924 if (defip.defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT) { 4925 /* for ALPM, need call add to trigger propation */ 4926 L3_LOCK(unit); 4927 defip.defip_flags |= BCM_L3_REPLACE; 4928 if (info->l3a_flags & BCM_L3_IP6) { 4929 rv = mbcm_driver[unit]->mbcm_ip6_defip_add(unit, &defip); 4930 } else { 4931 rv = mbcm_driver[unit]->mbcm_ip4_defip_add(unit, &defip); 4932 } 4933 L3_UNLOCK(unit); 4934 } 4935 } 4936 #endif 4937 4938 return rv; 4939 } 4940 4941 /* 4942 * Function: 4943 * _bcm_td2_l3_route_stat_counter_get 4944 * 4945 * Description: 4946 * Get l3 route counter value for specified l3 route index 4947 * if sync_mode is set, sync the sw accumulated count 4948 * with hw count value first, else return sw count. 4949 * 4950 * Parameters: 4951 * unit - (IN) unit number 4952 * sync_mode - (IN) hwcount is to be synced to sw count 4953 * info - (IN) L3 Route Info 4954 * stat - (IN) l3 route counter stat types 4955 * num_entries - (IN) Number of counter Entries 4956 * counter_indexes - (IN) Pointer to Counter indexes entries 4957 * counter_values - (OUT) Pointer to counter values 4958 * 4959 * Return Value: 4960 * BCM_E_XXX 4961 * Notes: 4962 */ 4963 bcm_error_t _bcm_td2_l3_route_stat_counter_get( 4964 int unit, 4965 int sync_mode, 4966 bcm_l3_route_t *info, 4967 bcm_l3_route_stat_t stat, 4968 uint32 num_entries, 4969 uint32 *counter_indexes, 4970 bcm_stat_value_t *counter_values) 4971 { 4972 uint32 table_count = 0; 4973 uint32 index_count = 0; 4974 uint32 num_of_tables = 0; 4975 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 4976 uint32 byte_flag = 0; 4977 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 4978 _bcm_defip_cfg_t defip; 4979 4980 /* Get the flex counter direction - ingress/egress */ 4981 if ((stat == bcmL3RouteInPackets) || 4982 (stat == bcmL3RouteInBytes)) { 4983 direction = bcmStatFlexDirectionIngress; 4984 } else { 4985 /* direction = bcmStatFlexDirectionEgress;*/ 4986 return BCM_E_UNAVAIL; 4987 } 4988 if (stat == bcmL3RouteInPackets) { 4989 byte_flag=0; 4990 } else { 4991 byte_flag=1; 4992 } 4993 4994 /* Get Table index to read the flex counter */ 4995 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info( 4996 unit, info, &num_of_tables, &table_info[0], &defip)); 4997 4998 #ifdef ALPM_ENABLE 4999 #ifdef BCM_TOMAHAWK_SUPPORT 5000 if (soc_feature(unit, soc_feature_alpm2) && 5001 (table_info[0].table == L3_DEFIP_ALPM_RAWm || 5002 table_info[0].table == L3_DEFIP_ALPM_LEVEL2m || 5003 table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) { 5004 BCM_IF_ERROR_RETURN( 5005 alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index)); 5006 } 5007 #endif 5008 #endif 5009 5010 /* Get the flex counter for the attached table index */ 5011 for (table_count = 0; table_count < num_of_tables ; table_count++) { 5012 if (table_info[table_count].direction == direction) { 5013 for (index_count = 0; index_count < num_entries ; index_count++) { 5014 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get( 5015 unit, sync_mode, 5016 table_info[table_count].index, 5017 table_info[table_count].table, 5018 0, 5019 byte_flag, 5020 counter_indexes[index_count], 5021 &counter_values[index_count])); 5022 } 5023 } 5024 } 5025 5026 return BCM_E_NONE; 5027 } 5028 5029 /* 5030 * Function: 5031 * _bcm_td2_l3_route_stat_counter_set 5032 * 5033 * Description: 5034 * Set l3 route counter value for specified l3 route index 5035 * 5036 * Parameters: 5037 * unit - (IN) unit number 5038 * info - (IN) L3 Route Info 5039 * stat - (IN) l3 route counter stat types 5040 * num_entries - (IN) Number of counter Entries 5041 * counter_indexes - (IN) Pointer to Counter indexes entries 5042 * counter_values - (OUT) Pointer to counter values 5043 * 5044 * Return Value: 5045 * BCM_E_XXX 5046 * Notes: 5047 */ 5048 bcm_error_t _bcm_td2_l3_route_stat_counter_set( 5049 int unit, 5050 bcm_l3_route_t *info, 5051 bcm_l3_route_stat_t stat, 5052 uint32 num_entries, 5053 uint32 *counter_indexes, 5054 bcm_stat_value_t *counter_values) 5055 { 5056 uint32 table_count=0; 5057 uint32 index_count=0; 5058 uint32 num_of_tables=0; 5059 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 5060 uint32 byte_flag=0; 5061 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 5062 _bcm_defip_cfg_t defip; 5063 5064 /* Get the flex counter direction - ingress/egress */ 5065 if ((stat == bcmL3RouteInPackets) || 5066 (stat == bcmL3RouteInBytes)) { 5067 direction = bcmStatFlexDirectionIngress; 5068 } else { 5069 /* direction = bcmStatFlexDirectionEgress;*/ 5070 return BCM_E_UNAVAIL; 5071 } 5072 if (stat == bcmL3RouteInPackets) { 5073 byte_flag=0; 5074 } else { 5075 byte_flag=1; 5076 } 5077 5078 /* Get Table index to read the flex counter */ 5079 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info( 5080 unit, info, &num_of_tables, &table_info[0], &defip)); 5081 5082 #ifdef ALPM_ENABLE 5083 #ifdef BCM_TOMAHAWK_SUPPORT 5084 if (soc_feature(unit, soc_feature_alpm2) && 5085 (table_info[0].table == L3_DEFIP_ALPM_RAWm || 5086 table_info[0].table == L3_DEFIP_ALPM_LEVEL2m || 5087 table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) { 5088 BCM_IF_ERROR_RETURN( 5089 alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index)); 5090 } 5091 #endif 5092 #endif 5093 5094 /* Get the flex counter for the attached table index */ 5095 for (table_count = 0; table_count < num_of_tables ; table_count++) { 5096 if (table_info[table_count].direction == direction) { 5097 for (index_count = 0; index_count < num_entries; index_count++) { 5098 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set( 5099 unit, 5100 table_info[table_count].index, 5101 table_info[table_count].table, 5102 0, 5103 byte_flag, 5104 counter_indexes[index_count], 5105 &counter_values[index_count])); 5106 } 5107 } 5108 } 5109 return BCM_E_NONE; 5110 } 5111 5112 /* 5113 * Function: 5114 * _bcm_td2_l3_route_stat_multi_get 5115 * 5116 * Description: 5117 * Get Multiple l3 route counter value for specified l3 route index for multiple stat 5118 * types 5119 * 5120 * Parameters: 5121 * unit - (IN) unit number 5122 * info - (IN) L3 Route Info 5123 * nstat - (IN) Number of elements in stat array 5124 * stat_arr - (IN) Collected statistics descriptors array 5125 * value_arr - (OUT) Collected counters values 5126 * 5127 * Return Value: 5128 * BCM_E_XXX 5129 * Notes: 5130 */ 5131 5132 5133 bcm_error_t _bcm_td2_l3_route_stat_multi_get( 5134 int unit, 5135 bcm_l3_route_t *info, 5136 int nstat, 5137 bcm_l3_route_stat_t *stat_arr, 5138 uint64 *value_arr) 5139 { 5140 int rv = BCM_E_NONE; 5141 int idx; 5142 uint32 counter_indexes = 0; 5143 bcm_stat_value_t counter_values = {0}; 5144 int sync_mode = 0; 5145 5146 /* Iterate of all stats array to retrieve flex counter values */ 5147 for (idx = 0; idx < nstat ;idx++) { 5148 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_get( 5149 unit, sync_mode, info, stat_arr[idx], 5150 1, &counter_indexes, &counter_values)); 5151 if ((stat_arr[idx] == bcmL3RouteInPackets)) { 5152 COMPILER_64_SET(value_arr[idx], 5153 COMPILER_64_HI(counter_values.packets64), 5154 COMPILER_64_LO(counter_values.packets64)); 5155 } else { 5156 COMPILER_64_SET(value_arr[idx], 5157 COMPILER_64_HI(counter_values.bytes), 5158 COMPILER_64_LO(counter_values.bytes)); 5159 } 5160 } 5161 return rv; 5162 } 5163 5164 /* 5165 * Function: 5166 * _bcm_td2_l3_route_stat_multi_get32 5167 * 5168 * Description: 5169 * Get 32bit l3 route counter value for specified l3 route index for multiple stat 5170 * types 5171 * 5172 * Parameters: 5173 * unit - (IN) unit number 5174 * info - (IN) L3 Route Info 5175 * nstat - (IN) Number of elements in stat array 5176 * stat_arr - (IN) Collected statistics descriptors array 5177 * value_arr - (OUT) Collected counters values 5178 * 5179 * Return Value: 5180 * BCM_E_XXX 5181 * Notes: 5182 */ 5183 bcm_error_t _bcm_td2_l3_route_stat_multi_get32( 5184 int unit, 5185 bcm_l3_route_t *info, 5186 int nstat, 5187 bcm_l3_route_stat_t *stat_arr, 5188 uint32 *value_arr) 5189 { 5190 int rv = BCM_E_NONE; 5191 int idx; 5192 uint32 counter_indexes = 0; 5193 bcm_stat_value_t counter_values = {0}; 5194 int sync_mode = 0; 5195 5196 /* Iterate of all stats array to retrieve flex counter values */ 5197 for (idx = 0; idx < nstat ;idx++) { 5198 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_get( 5199 unit, sync_mode, info, stat_arr[idx], 5200 1, &counter_indexes, &counter_values)); 5201 if ((stat_arr[idx] == bcmL3RouteInPackets)) { 5202 value_arr[idx] = counter_values.packets; 5203 } else { 5204 value_arr[idx] = COMPILER_64_LO(counter_values.bytes); 5205 } 5206 } 5207 return rv; 5208 } 5209 5210 /* 5211 * Function: 5212 * _bcm_td2_l3_route_stat_multi_set 5213 * 5214 * Description: 5215 * Set l3 route counter value for specified l3 route index for multiple stat 5216 * types 5217 * 5218 * Parameters: 5219 * unit - (IN) unit number 5220 * info - (IN) L3 Route Info 5221 * stat - (IN) l3 route counter stat types 5222 * num_entries - (IN) Number of counter Entries 5223 * counter_indexes - (IN) Pointer to Counter indexes entries 5224 * counter_values - (OUT) Pointer to counter values 5225 * 5226 * Return Value: 5227 * BCM_E_XXX 5228 * Notes: 5229 */ 5230 bcm_error_t _bcm_td2_l3_route_stat_multi_set( 5231 int unit, 5232 bcm_l3_route_t *info, 5233 int nstat, 5234 bcm_l3_route_stat_t *stat_arr, 5235 uint64 *value_arr) 5236 { 5237 int rv = BCM_E_NONE; 5238 int idx; 5239 uint32 counter_indexes = 0; 5240 bcm_stat_value_t counter_values = {0}; 5241 5242 /* Iterate f all stats array to retrieve flex counter values */ 5243 for (idx = 0; idx < nstat ;idx++) { 5244 if ((stat_arr[idx] == bcmL3RouteInPackets)) { 5245 counter_values.packets = COMPILER_64_LO(value_arr[idx]); 5246 } else { 5247 COMPILER_64_SET(counter_values.bytes, 5248 COMPILER_64_HI(value_arr[idx]), 5249 COMPILER_64_LO(value_arr[idx])); 5250 } 5251 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_set( 5252 unit, info, stat_arr[idx], 5253 1, &counter_indexes, &counter_values)); 5254 } 5255 return rv; 5256 5257 } 5258 5259 /* 5260 * Function: 5261 * _bcm_td2_l3_route_stat_multi_set32 5262 * 5263 * Description: 5264 * Set 32bit l3 route counter value for specified l3 route index for multiple stat 5265 * types 5266 * 5267 * Parameters: 5268 * unit - (IN) unit number 5269 * info - (IN) L3 Route Info 5270 * stat - (IN) l3 route counter stat types 5271 * num_entries - (IN) Number of counter Entries 5272 * counter_indexes - (IN) Pointer to Counter indexes entries 5273 * counter_values - (OUT) Pointer to counter values 5274 * 5275 * Return Value: 5276 * BCM_E_XXX 5277 * Notes: 5278 */ 5279 5280 bcm_error_t _bcm_td2_l3_route_stat_multi_set32( 5281 int unit, 5282 bcm_l3_route_t *info, 5283 int nstat, 5284 bcm_l3_route_stat_t *stat_arr, 5285 uint32 *value_arr) 5286 { 5287 int rv = BCM_E_NONE; 5288 int idx; 5289 uint32 counter_indexes = 0; 5290 bcm_stat_value_t counter_values = {0}; 5291 5292 /* Iterate of all stats array to retrieve flex counter values */ 5293 for (idx = 0; idx < nstat ;idx++) { 5294 if ((stat_arr[idx] == bcmL3RouteInPackets)) { 5295 counter_values.packets = value_arr[idx]; 5296 } else { 5297 COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]); 5298 } 5299 5300 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_set( 5301 unit, info, stat_arr[idx], 5302 1, &counter_indexes, &counter_values)); 5303 } 5304 return rv; 5305 } 5306 5307 /* 5308 * Function: 5309 * _bcm_td2_l3_route_stat_id_get 5310 * 5311 * Description: 5312 * Get Stat Counter if associated with given l3 route index 5313 * 5314 * Parameters: 5315 * unit - (IN) bcm device 5316 * info - (IN) L3 Route Info 5317 * stat - (IN) l3 route counter stat types 5318 * stat_counter_id - (IN) Stat Counter ID. 5319 * 5320 * Returns: 5321 * BCM_E_NONE - Success 5322 * BCM_E_XXX 5323 * Notes: 5324 */ 5325 5326 bcm_error_t _bcm_td2_l3_route_stat_id_get( 5327 int unit, 5328 bcm_l3_route_t *info, 5329 bcm_l3_route_stat_t stat, 5330 uint32 *stat_counter_id) 5331 { 5332 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 5333 uint32 num_of_tables = 0; 5334 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 5335 uint32 index = 0; 5336 uint32 num_stat_counter_ids = 0; 5337 _bcm_defip_cfg_t defip; 5338 5339 if ((stat == bcmL3RouteInPackets) || 5340 (stat == bcmL3RouteInBytes)) { 5341 direction = bcmStatFlexDirectionIngress; 5342 } else { 5343 /* direction = bcmStatFlexDirectionEgress;*/ 5344 return BCM_E_UNAVAIL; 5345 } 5346 5347 /* Get Tables, for which flex counter are attached */ 5348 BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info( 5349 unit, info, &num_of_tables, &table_info[0], &defip)); 5350 5351 #ifdef ALPM_ENABLE 5352 #ifdef BCM_TOMAHAWK_SUPPORT 5353 if (soc_feature(unit, soc_feature_alpm2) && 5354 (table_info[0].table == L3_DEFIP_ALPM_RAWm || 5355 table_info[0].table == L3_DEFIP_ALPM_LEVEL2m || 5356 table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) { 5357 BCM_IF_ERROR_RETURN( 5358 alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index)); 5359 } 5360 #endif 5361 #endif 5362 5363 /* Retrieve stat counter id */ 5364 for (index = 0; index < num_of_tables ; index++) { 5365 if (table_info[index].direction == direction) 5366 return _bcm_esw_stat_flex_get_counter_id( 5367 unit, 1, &table_info[index], 5368 &num_stat_counter_ids, stat_counter_id); 5369 } 5370 return BCM_E_NOT_FOUND; 5371 } 5372 /*************************************************************** 5373 * IP4 Options 5374 */ 5375 5376 /* Free IP4 options resources */ 5377 int _bcm_td2_l3_ip4_options_free_resources(int unit) 5378 { 5379 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 5380 5381 /* free ip4 options profile usage bitmap */ 5382 if (NULL != l3_bk_info->ip4_options_bitmap) { 5383 sal_free(l3_bk_info->ip4_options_bitmap); 5384 l3_bk_info->ip4_options_bitmap = NULL; 5385 } 5386 5387 /* free ip4 options hw index usage bitmap */ 5388 if (NULL != l3_bk_info->ip4_profiles_hw_idx) { 5389 sal_free(l3_bk_info->ip4_profiles_hw_idx); 5390 l3_bk_info->ip4_profiles_hw_idx = NULL; 5391 } 5392 if (NULL != ip4_profiles_hw_idx_lock[unit]) { 5393 sal_mutex_destroy(ip4_profiles_hw_idx_lock[unit]); 5394 ip4_profiles_hw_idx_lock[unit] = NULL; 5395 } 5396 return BCM_E_NONE; 5397 } 5398 5399 /* Initialize the IP4 options book keeping */ 5400 int 5401 _bcm_td2_l3_ip4_options_profile_init(int unit) 5402 { 5403 _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit); 5404 int ip4_options_profiles; 5405 int default_index = BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX; 5406 int rv = BCM_E_NONE; 5407 5408 ip4_options_profiles = _BCM_IP4_OPTIONS_LEN; 5409 5410 /* Allocate ip4 options profile usage bitmap */ 5411 if (NULL == l3_bk_info->ip4_options_bitmap) { 5412 l3_bk_info->ip4_options_bitmap = 5413 sal_alloc(SHR_BITALLOCSIZE(ip4_options_profiles), "ip4_options_bitmap"); 5414 if (l3_bk_info->ip4_options_bitmap == NULL) { 5415 _bcm_td2_l3_ip4_options_free_resources(unit); 5416 return BCM_E_MEMORY; 5417 } 5418 } 5419 sal_memset(l3_bk_info->ip4_options_bitmap, 0, SHR_BITALLOCSIZE(ip4_options_profiles)); 5420 if (NULL == l3_bk_info->ip4_profiles_hw_idx) { 5421 l3_bk_info->ip4_profiles_hw_idx = 5422 sal_alloc(sizeof(uint32) * ip4_options_profiles, "ip4_profiles_hw_idx"); 5423 if (l3_bk_info->ip4_profiles_hw_idx == NULL) { 5424 _bcm_td2_l3_ip4_options_free_resources(unit); 5425 return BCM_E_MEMORY; 5426 } 5427 } 5428 sal_memset(l3_bk_info->ip4_profiles_hw_idx, 0, (sizeof(uint32) * ip4_options_profiles)); 5429 5430 if (NULL == ip4_profiles_hw_idx_lock[unit]) { 5431 ip4_profiles_hw_idx_lock[unit] = sal_mutex_create("Ip4 profiles hw idx mutex"); 5432 5433 if (NULL == ip4_profiles_hw_idx_lock[unit]) { 5434 _bcm_td2_l3_ip4_options_free_resources(unit); 5435 return BCM_E_MEMORY; 5436 } 5437 } 5438 rv = _bcm_td2_l3_ip4_options_profile_create (unit, BCM_L3_IP4_OPTIONS_WITH_ID, 5439 bcmIntfIPOptionActionDrop, &default_index); 5440 return rv; 5441 } 5442 5443 5444 5445 STATIC int 5446 _bcm_td2_l3_ip4_profile_id_alloc(int unit) 5447 { 5448 int i, option_profile_size = -1; 5449 SHR_BITDCL *bitmap; 5450 5451 bitmap = L3_INFO(unit)->ip4_options_bitmap; 5452 option_profile_size = _BCM_IP4_OPTIONS_LEN; 5453 for (i = 0; i < option_profile_size; i++) { 5454 if (!SHR_BITGET(bitmap, i)) { 5455 return i; 5456 } 5457 } 5458 return -1; 5459 } 5460 5461 int 5462 _bcm_td2_l3_ip4_options_profile_create(int unit, uint32 flags, 5463 bcm_l3_ip4_options_action_t default_action, 5464 int *ip4_options_profile_id) 5465 { 5466 ip_option_control_profile_table_entry_t ip_option_profile[_BCM_IP_OPTION_PROFILE_CHUNK]; 5467 int id, index = -1, rv = BCM_E_NONE; 5468 int i, copy_cpu, drop; 5469 void *entries[1], *entry; 5470 5471 /* Check for pre-specified ID */ 5472 if (flags & BCM_L3_IP4_OPTIONS_WITH_ID) { 5473 id = *ip4_options_profile_id; 5474 if (id >= _BCM_IP4_OPTIONS_LEN ) { 5475 return BCM_E_PARAM; 5476 } 5477 if (_BCM_IP4_OPTIONS_USED_GET(unit, id)) { 5478 if (!(flags & BCM_L3_IP4_OPTIONS_REPLACE)) { 5479 return BCM_E_EXISTS; 5480 } else { 5481 if (id == BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX) { 5482 return BCM_E_BADID; 5483 } 5484 } 5485 } 5486 } 5487 /* Reserve a chunk in the IP4_OPTION Profile table */ 5488 sal_memset(ip_option_profile, 0, sizeof(ip_option_profile)); 5489 entries[0] = &ip_option_profile; 5490 5491 /* Set the default action for the profile */ 5492 switch (default_action) { 5493 case bcmIntfIPOptionActionCopyToCPU: 5494 copy_cpu = 1; 5495 drop = 0; 5496 break; 5497 case bcmIntfIPOptionActionDrop: 5498 copy_cpu = 0; 5499 drop = 1; 5500 break; 5501 case bcmIntfIPOptionActionCopyCPUAndDrop: 5502 copy_cpu = 1; 5503 drop = 1; 5504 break; 5505 case bcmIntfIPOptionActionNone: 5506 default : 5507 copy_cpu = 0; 5508 drop = 0; 5509 break; 5510 } 5511 for (i = 0; i < _BCM_IP_OPTION_PROFILE_CHUNK; i++) { 5512 entry = &ip_option_profile[i]; 5513 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5514 COPYTO_CPUf, copy_cpu); 5515 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5516 DROPf, drop); 5517 } 5518 5519 BCM_IF_ERROR_RETURN(_bcm_l3_ip4_options_profile_entry_add(unit, entries, 5520 _BCM_IP_OPTION_PROFILE_CHUNK, 5521 (uint32 *)&index)); 5522 /* To avoid deadlock, There should be not any semaphore 5523 * between HW_IDX_LOCK and HW_IDX_UNLOCK 5524 */ 5525 HW_IDX_LOCK(unit); 5526 5527 if (flags & BCM_L3_IP4_OPTIONS_WITH_ID) { 5528 id = *ip4_options_profile_id; 5529 if (0 == (_BCM_IP4_OPTIONS_USED_GET(unit, id))) { 5530 _BCM_IP4_OPTIONS_USED_SET(unit, id); 5531 } 5532 } else { 5533 id = _bcm_td2_l3_ip4_profile_id_alloc(unit); 5534 if (id == -1) { 5535 HW_IDX_UNLOCK(unit); 5536 _bcm_l3_ip4_options_profile_entry_delete(unit, index); 5537 return BCM_E_RESOURCE; 5538 } 5539 _BCM_IP4_OPTIONS_USED_SET(unit, id); 5540 *ip4_options_profile_id = id; 5541 } 5542 5543 L3_INFO(unit)->ip4_profiles_hw_idx[id] = (index / 5544 _BCM_IP_OPTION_PROFILE_CHUNK); 5545 HW_IDX_UNLOCK(unit); 5546 5547 return rv; 5548 } 5549 5550 5551 5552 int 5553 _bcm_td2_l3_ip4_options_profile_destroy(int unit, int ip4_options_profile_id) 5554 { 5555 int id, rv = BCM_E_UNAVAIL; 5556 int index; 5557 5558 if (ip4_options_profile_id == BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX) { 5559 return BCM_E_BADID; 5560 } 5561 L3_LOCK(unit); 5562 id = ip4_options_profile_id; 5563 if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) { 5564 L3_UNLOCK(unit); 5565 return BCM_E_NOT_FOUND; 5566 } else { 5567 5568 HW_IDX_LOCK(unit); 5569 index = L3_INFO(unit)->ip4_profiles_hw_idx[id]; 5570 L3_INFO(unit)->ip4_profiles_hw_idx[id] = 0; 5571 HW_IDX_UNLOCK(unit); 5572 5573 rv = _bcm_l3_ip4_options_profile_entry_delete 5574 (unit, index * _BCM_IP_OPTION_PROFILE_CHUNK); 5575 5576 _BCM_IP4_OPTIONS_USED_CLR(unit, id); 5577 } 5578 #ifdef BCM_WARM_BOOT_SUPPORT 5579 SOC_CONTROL_LOCK(unit); 5580 SOC_CONTROL(unit)->scache_dirty = 1; 5581 SOC_CONTROL_UNLOCK(unit); 5582 #endif 5583 L3_UNLOCK(unit); 5584 return rv; 5585 } 5586 5587 /* Add an entry to a ip_option_profile */ 5588 /* Read the existing profile chunk, modify what's needed and add the 5589 * new profile. This can result in the HW profile index changing for a 5590 * given ID */ 5591 int 5592 _bcm_td2_l3_ip4_options_profile_action_set(int unit, 5593 int ip4_options_profile_id, 5594 int ip4_option, 5595 bcm_l3_ip4_options_action_t action) 5596 { 5597 ip_option_control_profile_table_entry_t ip_option_profile[_BCM_IP_OPTION_PROFILE_CHUNK]; 5598 int id, index = -1, rv = BCM_E_NONE; 5599 void *entries[1], *entry; 5600 int offset; 5601 5602 /* Make sure module was initialized. */ 5603 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 5604 return (BCM_E_INIT); 5605 } 5606 5607 id = ip4_options_profile_id; 5608 if (id == BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX) { 5609 return BCM_E_BADID; 5610 } 5611 L3_LOCK(unit); 5612 5613 if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) { 5614 L3_UNLOCK(unit); 5615 return BCM_E_PARAM; 5616 } else { 5617 entries[0] = ip_option_profile; 5618 5619 /* Base index of table in hardware */ 5620 GET_HW_IDX(unit, index, id); 5621 index = index * _BCM_IP_OPTION_PROFILE_CHUNK; 5622 5623 rv = _bcm_l3_ip4_options_profile_entry_get(unit, index, 5624 _BCM_IP_OPTION_PROFILE_CHUNK, 5625 entries); 5626 if (BCM_FAILURE(rv)) { 5627 L3_UNLOCK(unit); 5628 return (rv); 5629 } 5630 5631 /* Offset within table */ 5632 offset = ip4_option; 5633 5634 /* Modify what's needed */ 5635 entry = &ip_option_profile[offset]; 5636 switch (action) { 5637 case bcmIntfIPOptionActionCopyToCPU: 5638 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5639 COPYTO_CPUf, 1); 5640 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5641 DROPf, 0); 5642 break; 5643 5644 case bcmIntfIPOptionActionDrop: 5645 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5646 COPYTO_CPUf, 0); 5647 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5648 DROPf, 1); 5649 break; 5650 5651 case bcmIntfIPOptionActionCopyCPUAndDrop: 5652 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5653 COPYTO_CPUf, 1); 5654 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5655 DROPf, 1); 5656 break; 5657 5658 case bcmIntfIPOptionActionNone: 5659 default : 5660 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5661 COPYTO_CPUf, 0); 5662 soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5663 DROPf, 0); 5664 5665 } 5666 /* Delete the old profile chunk */ 5667 rv = _bcm_l3_ip4_options_profile_entry_delete(unit, index); 5668 if (BCM_FAILURE(rv)) { 5669 L3_UNLOCK(unit); 5670 return (rv); 5671 } 5672 5673 /* Add new chunk and store new HW index */ 5674 rv = _bcm_l3_ip4_options_profile_entry_add(unit, entries, 5675 _BCM_IP_OPTION_PROFILE_CHUNK, 5676 (uint32 *)&index); 5677 5678 SET_HW_IDX(unit, id, index / _BCM_IP_OPTION_PROFILE_CHUNK); 5679 5680 } 5681 #ifdef BCM_WARM_BOOT_SUPPORT 5682 SOC_CONTROL_LOCK(unit); 5683 SOC_CONTROL(unit)->scache_dirty = 1; 5684 SOC_CONTROL_UNLOCK(unit); 5685 #endif 5686 L3_UNLOCK(unit); 5687 return rv; 5688 } 5689 5690 5691 int 5692 _bcm_td2_l3_ip4_options_profile_action_get(int unit, 5693 int ip4_options_profile_id, 5694 int ip4_option, 5695 bcm_l3_ip4_options_action_t *action) 5696 { 5697 ip_option_control_profile_table_entry_t ip_option_profile[_BCM_IP_OPTION_PROFILE_CHUNK]; 5698 int id, index = -1, rv = BCM_E_NONE; 5699 void *entries[1], *entry; 5700 int offset; 5701 int copy_to_cpu, drop; 5702 5703 /* Make sure module was initialized. */ 5704 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 5705 return (BCM_E_INIT); 5706 } 5707 5708 id = ip4_options_profile_id; 5709 L3_LOCK(unit); 5710 5711 if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) { 5712 L3_UNLOCK(unit); 5713 return BCM_E_PARAM; 5714 } else { 5715 entries[0] = ip_option_profile; 5716 5717 /* Base index of table in hardware */ 5718 GET_HW_IDX(unit, index, id); 5719 5720 index = index * _BCM_IP_OPTION_PROFILE_CHUNK; 5721 5722 rv = _bcm_l3_ip4_options_profile_entry_get(unit, index, 5723 _BCM_IP_OPTION_PROFILE_CHUNK, 5724 entries); 5725 if (BCM_FAILURE(rv)) { 5726 L3_UNLOCK(unit); 5727 return (rv); 5728 } 5729 5730 /* Offset within table */ 5731 offset = ip4_option; 5732 5733 /* Modify what's needed */ 5734 entry = &ip_option_profile[offset]; 5735 5736 copy_to_cpu = soc_mem_field32_get(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5737 COPYTO_CPUf); 5738 drop = soc_mem_field32_get(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry, 5739 DROPf); 5740 5741 *action = bcmIntfIPOptionActionNone; 5742 if ((copy_to_cpu == 0) && (drop == 0)) { 5743 *action = bcmIntfIPOptionActionNone; 5744 } 5745 if ((copy_to_cpu == 1) && (drop == 0)) { 5746 *action = bcmIntfIPOptionActionCopyToCPU; 5747 } 5748 if ((copy_to_cpu == 0) && (drop == 1)) { 5749 *action = bcmIntfIPOptionActionDrop; 5750 } 5751 if ((copy_to_cpu == 1) && (drop == 1)) { 5752 *action = bcmIntfIPOptionActionCopyCPUAndDrop; 5753 } 5754 } 5755 L3_UNLOCK(unit); 5756 return rv; 5757 } 5758 5759 /* Get the list of all created IP options profile IDs */ 5760 int 5761 _bcm_td2_l3_ip4_options_profile_multi_get(int unit, int array_size, 5762 int *ip_options_ids_array, 5763 int *array_count) 5764 { 5765 int rv = BCM_E_NONE; 5766 int idx, count; 5767 5768 L3_LOCK(unit); 5769 if (array_size == 0) { 5770 /* querying the number of map-ids for storage allocation */ 5771 if (array_count == NULL) { 5772 rv = BCM_E_PARAM; 5773 } 5774 if (BCM_SUCCESS(rv)) { 5775 count = 0; 5776 *array_count = 0; 5777 SHR_BITCOUNT_RANGE(L3_INFO(unit)->ip4_options_bitmap, count, 5778 0, _BCM_IP4_OPTIONS_LEN); 5779 *array_count += count; 5780 } 5781 } else { 5782 if ((ip_options_ids_array == NULL) || (array_count == NULL)) { 5783 rv = BCM_E_PARAM; 5784 } 5785 if (BCM_SUCCESS(rv)) { 5786 count = 0; 5787 for (idx = 0; ((idx < _BCM_IP4_OPTIONS_LEN) && 5788 (count < array_size)); idx++) { 5789 if (_BCM_IP4_OPTIONS_USED_GET(unit, idx)) { 5790 *(ip_options_ids_array + count) = idx; 5791 count++; 5792 } 5793 } 5794 *array_count = count; 5795 } 5796 } 5797 L3_UNLOCK(unit); 5798 return rv; 5799 } 5800 5801 /* Get the IP options actions for a given profile ID */ 5802 int 5803 _bcm_td2_l3_ip4_options_profile_action_multi_get(int unit, uint32 flags, 5804 int ip_option_profile_id, int array_size, 5805 bcm_l3_ip4_options_action_t *array, int *array_count) 5806 { 5807 int rv = BCM_E_NONE; 5808 int num_entries, idx, id, hw_id, alloc_size, entry_size, count; 5809 uint8 *dma_buf; 5810 void *entry; 5811 soc_mem_t mem; 5812 bcm_l3_ip4_options_action_t *action; 5813 int copy_to_cpu, drop; 5814 5815 /* ignore with_id & replace flags */ 5816 id = ip_option_profile_id; 5817 hw_id = 0; 5818 num_entries = 0; 5819 entry_size = 0; 5820 L3_LOCK(unit); 5821 5822 if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) { 5823 rv = BCM_E_PARAM; 5824 } 5825 num_entries = _BCM_IP_OPTION_PROFILE_CHUNK; 5826 entry_size = sizeof(ip_option_control_profile_table_entry_t); 5827 5828 GET_HW_IDX(unit, hw_id, id); 5829 hw_id = hw_id * _BCM_IP_OPTION_PROFILE_CHUNK; 5830 mem = IP_OPTION_CONTROL_PROFILE_TABLEm; 5831 5832 5833 L3_UNLOCK(unit); 5834 BCM_IF_ERROR_RETURN(rv); 5835 5836 if (array_size == 0) { /* querying the size of profile-chunk */ 5837 *array_count = num_entries; 5838 return BCM_E_NONE; 5839 } 5840 if (!array || !array_count) { 5841 return BCM_E_PARAM; 5842 } 5843 5844 /* Allocate memory for DMA & regular */ 5845 alloc_size = num_entries * entry_size; 5846 dma_buf = soc_cm_salloc(unit, alloc_size, "IP option multi get DMA buf"); 5847 if (!dma_buf) { 5848 return BCM_E_MEMORY; 5849 } 5850 sal_memset(dma_buf, 0, alloc_size); 5851 5852 /* Read the profile chunk */ 5853 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, hw_id, 5854 (hw_id + num_entries - 1), dma_buf); 5855 if (BCM_FAILURE(rv)) { 5856 soc_cm_sfree(unit, dma_buf); 5857 return rv; 5858 } 5859 5860 count = 0; 5861 L3_LOCK(unit); 5862 for (idx=0; ((idx<num_entries) && (count < array_size)); idx++) { 5863 action = &array[idx]; 5864 entry = soc_mem_table_idx_to_pointer(unit, mem, void *, 5865 dma_buf, idx); 5866 copy_to_cpu = soc_mem_field32_get(unit, mem, entry, COPY_TO_CPUf); 5867 drop = soc_mem_field32_get(unit, mem, entry, DROPf); 5868 5869 *action = bcmIntfIPOptionActionNone; 5870 if ((copy_to_cpu == 0) && (drop == 0)) { 5871 *action = bcmIntfIPOptionActionNone; 5872 } 5873 if ((copy_to_cpu == 1) && (drop == 0)) { 5874 *action = bcmIntfIPOptionActionCopyToCPU; 5875 } 5876 if ((copy_to_cpu == 0) && (drop == 1)) { 5877 *action = bcmIntfIPOptionActionDrop; 5878 } 5879 if ((copy_to_cpu == 1) && (drop == 1)) { 5880 *action = bcmIntfIPOptionActionCopyCPUAndDrop; 5881 } 5882 count++; 5883 } 5884 L3_UNLOCK(unit); 5885 soc_cm_sfree(unit, dma_buf); 5886 5887 BCM_IF_ERROR_RETURN(rv); 5888 5889 *array_count = count; 5890 return BCM_E_NONE; 5891 } 5892 5893 5894 /* Function: 5895 * _bcm_td2_l3_ip4_options_profile_id2idx 5896 * Purpose: 5897 * Translate profile ID into hardware table index. 5898 * Parameters: 5899 * Returns: 5900 * BCM_E_XXX 5901 */ 5902 int 5903 _bcm_td2_l3_ip4_options_profile_id2idx(int unit, int profile_id, int *hw_idx) 5904 { 5905 if (hw_idx == NULL) { 5906 return BCM_E_PARAM; 5907 } 5908 /* Make sure module was initialized. */ 5909 if (L3_INFO(unit)->ip4_options_bitmap == NULL) { 5910 return (BCM_E_INIT); 5911 } 5912 5913 if (!_BCM_IP4_OPTIONS_USED_GET(unit, profile_id)) { 5914 return BCM_E_NOT_FOUND; 5915 } else { 5916 GET_HW_IDX(unit, *hw_idx, profile_id); 5917 *hw_idx = *hw_idx * _BCM_IP_OPTION_PROFILE_CHUNK; 5918 } 5919 return BCM_E_NONE; 5920 } 5921 5922 /* Function: 5923 * _bcm_td2_l3_ip4_options_profile_idx2id 5924 * Purpose: 5925 * Translate hardware table index into Profile ID used by API 5926 * Parameters: 5927 * Returns: 5928 * BCM_E_XXX 5929 */ 5930 int 5931 _bcm_td2_l3_ip4_options_profile_idx2id(int unit, int hw_idx, int *profile_id) 5932 { 5933 int id; 5934 int profiles_hw_idx; 5935 5936 if (profile_id == NULL) { 5937 return BCM_E_PARAM; 5938 } 5939 /* To avoid deadlock, There should be not any semaphore 5940 * between HW_IDX_LOCK and HW_IDX_UNLOCK 5941 */ 5942 HW_IDX_LOCK(unit); 5943 5944 for (id = 0; id < _BCM_IP4_OPTIONS_LEN; id++) { 5945 if (_BCM_IP4_OPTIONS_USED_GET(unit, id)) { 5946 profiles_hw_idx = L3_INFO(unit)->ip4_profiles_hw_idx[id]; 5947 if (profiles_hw_idx * _BCM_IP_OPTION_PROFILE_CHUNK == hw_idx) { 5948 *profile_id = id; 5949 HW_IDX_UNLOCK(unit); 5950 return BCM_E_NONE; 5951 } 5952 } 5953 } 5954 HW_IDX_UNLOCK(unit); 5955 return BCM_E_NOT_FOUND; 5956 } 5957 5958 /* 5959 * Function: 5960 * _bcm_td2_nh_nat_id_update 5961 * Purpose: 5962 * Routine updates the dst realm nat id of 5963 * next hop interfaces associating with the key. 5964 * Parameters: 5965 * unit - (IN) SOC unit number. 5966 * key_type - (IN) Type of the key which the nh entries associate with. 5967 * val - (IN) Value of the key. 5968 * nat_id - (IN) Nat realm id. 5969 * Returns: 5970 * BCM_E_XXX 5971 */ 5972 STATIC int 5973 _bcm_td2_nh_nat_id_update(int unit, int key_type, void *val, int nat_id) 5974 { 5975 uint32 *ing_entry_ptr; /* Ingress next hop entry pointer.*/ 5976 uint32 *initial_ing_entry_ptr;/* Initial Ingress next hop entry pointer.*/ 5977 char *ing_tbl_ptr = NULL; /* Dma table pointer. */ 5978 char *initial_ing_tbl_ptr = NULL; /* Dma initial ing nh table pointer. */ 5979 int ifindex; /* Interface index. */ 5980 soc_mem_t mem; /* Next hop memory. */ 5981 soc_mem_t initial_mem; /* Inital Ingress Next hop memory. */ 5982 int idx; /* Iteration index. */ 5983 char *egr_tbl_ptr = NULL; /* Dma egress nh table pointer. */ 5984 uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pointer. */ 5985 int rv = BCM_E_NONE; /* Operation return status. */ 5986 uint32 *egr_intf_entry_ptr; /* EGR_L3_INTF entry pointer. */ 5987 char *egr_intf_tbl_ptr = NULL; /* EGR_L3_INTF dma table pointer. */ 5988 uint32 *vlan_mpls_entry_ptr; /* VLAN_MPLS entry pointer. */ 5989 char *vlan_mpls_tbl_ptr = NULL; /* VLAN_MPLS dma table pointer. */ 5990 bcm_vlan_t vlan; 5991 bcm_if_t l3_iif; 5992 _bcm_l3_intf_fields_t *fld; /* Interface table common fields. */ 5993 soc_field_t intf_field = INTF_NUMf; 5994 soc_mem_t vlan_mem = VLAN_MPLSm; 5995 int table_ent_size; 5996 5997 #ifdef BCM_TRIDENT3_SUPPORT 5998 if (SOC_IS_TRIDENT3X(unit)) { 5999 vlan_mem = VLAN_TABm; 6000 } 6001 #endif 6002 6003 /* Get next table memory. */ 6004 mem = BCM_XGS3_L3_MEM(unit, nh); 6005 initial_mem = INITIAL_ING_L3_NEXT_HOPm; 6006 fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf); 6007 6008 /* Table DMA the nhtable to software copy */ 6009 rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl", 6010 &ing_tbl_ptr, NULL); 6011 BCM_IF_ERROR_RETURN(rv); 6012 6013 /* Get initial next table memory. */ 6014 rv = bcm_xgs3_l3_tbl_dma(unit, initial_mem, 6015 sizeof(initial_ing_l3_next_hop_entry_t), 6016 "initial_nh_tbl", &initial_ing_tbl_ptr, NULL); 6017 if (rv < 0) { 6018 goto cleanup; 6019 } 6020 6021 6022 /* Read egress next hop entry. */ 6023 rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm, 6024 sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl", 6025 &egr_tbl_ptr, NULL); 6026 if (rv < 0) { 6027 goto cleanup; 6028 } 6029 6030 if ((key_type == _BCM_NH_UPDATE_KEY_VLAN) || 6031 (key_type == _BCM_NH_UPDATE_KEY_L3_IIF)) { 6032 /* Read EGR_L3_INTF table. */ 6033 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, intf), 6034 sizeof(egr_l3_intf_entry_t), "egr_l3_intf_tbl", 6035 &egr_intf_tbl_ptr, NULL); 6036 if (rv < 0) { 6037 goto cleanup; 6038 } 6039 } 6040 6041 if ((BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) && 6042 (key_type == _BCM_NH_UPDATE_KEY_L3_IIF)) { 6043 /* Read VLAN_MPLS table. */ 6044 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, vlan_mem); 6045 rv = bcm_xgs3_l3_tbl_dma(unit, vlan_mem, 6046 table_ent_size, "vlan_mpls_tbl", 6047 &vlan_mpls_tbl_ptr, NULL); 6048 if (rv < 0) { 6049 goto cleanup; 6050 } 6051 } 6052 6053 6054 for (idx = 0; idx < BCM_XGS3_L3_NH_TBL_SIZE(unit); idx++) { 6055 /* Skip unused entries. */ 6056 if (!BCM_XGS3_L3_ENT_REF_CNT 6057 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) { 6058 continue; 6059 } 6060 6061 /* Skip trap to CPU entry internally installed entry. */ 6062 if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) { 6063 continue; 6064 } 6065 6066 /* Read egress next hop entry. */ 6067 egr_entry_ptr = 6068 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm, 6069 uint32 *, egr_tbl_ptr, idx); 6070 6071 /* Get interface index. */ 6072 if (SOC_IS_TRIDENT3X(unit)) { 6073 intf_field = L3__INTF_NUMf; 6074 } 6075 ifindex = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 6076 egr_entry_ptr, intf_field); 6077 if (key_type == _BCM_NH_UPDATE_KEY_L3_INTF) { 6078 if (ifindex != *(bcm_if_t *)val) { 6079 continue; 6080 } 6081 } else if ((key_type == _BCM_NH_UPDATE_KEY_VLAN) || 6082 (key_type == _BCM_NH_UPDATE_KEY_L3_IIF)) { 6083 egr_intf_entry_ptr = 6084 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, intf), 6085 uint32 *, egr_intf_tbl_ptr, 6086 ifindex); 6087 /* coverity[forward_null : FALSE] */ 6088 vlan = soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, intf), 6089 egr_intf_entry_ptr, fld->vlan_id); 6090 6091 if (key_type == _BCM_NH_UPDATE_KEY_VLAN) { 6092 if (vlan != *(bcm_vlan_t *)val) { 6093 continue; 6094 } 6095 } else if (key_type == _BCM_NH_UPDATE_KEY_L3_IIF) { 6096 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) { 6097 vlan_mpls_entry_ptr = 6098 soc_mem_table_idx_to_pointer(unit, vlan_mem, 6099 uint32 *, 6100 vlan_mpls_tbl_ptr, 6101 vlan); 6102 /* coverity[forward_null : FALSE] */ 6103 l3_iif = soc_mem_field32_get(unit, vlan_mem, 6104 vlan_mpls_entry_ptr, 6105 L3_IIFf); 6106 } else { 6107 l3_iif = vlan; 6108 } 6109 6110 if (l3_iif != *(bcm_if_t *)val) { 6111 continue; 6112 } 6113 } 6114 } else { 6115 rv = BCM_E_INTERNAL; 6116 goto cleanup; 6117 } 6118 6119 /* Calculate entry ofset. */ 6120 ing_entry_ptr = 6121 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx); 6122 soc_mem_field32_set(unit, mem, ing_entry_ptr, DST_REALM_IDf, nat_id); 6123 6124 /* Initial ingress nh table */ 6125 initial_ing_entry_ptr = soc_mem_table_idx_to_pointer( 6126 unit, initial_mem, uint32 *, 6127 initial_ing_tbl_ptr, idx); 6128 soc_mem_field32_set(unit, initial_mem, initial_ing_entry_ptr, 6129 DST_REALM_IDf, nat_id); 6130 } 6131 6132 /* Write the buffer back. */ 6133 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 6134 soc_mem_index_min(unit, mem), 6135 soc_mem_index_max(unit, mem), ing_tbl_ptr); 6136 if (SOC_FAILURE(rv)) { 6137 goto cleanup; 6138 } 6139 6140 rv = soc_mem_write_range(unit, initial_mem, MEM_BLOCK_ALL, 6141 soc_mem_index_min(unit, initial_mem), 6142 soc_mem_index_max(unit, initial_mem), 6143 initial_ing_tbl_ptr); 6144 6145 cleanup: 6146 if (ing_tbl_ptr) { 6147 soc_cm_sfree(unit, ing_tbl_ptr); 6148 } 6149 6150 if (initial_ing_tbl_ptr) { 6151 soc_cm_sfree(unit, initial_ing_tbl_ptr); 6152 } 6153 6154 if (egr_tbl_ptr) { 6155 soc_cm_sfree(unit, egr_tbl_ptr); 6156 } 6157 6158 if (egr_intf_tbl_ptr) { 6159 soc_cm_sfree(unit, egr_intf_tbl_ptr); 6160 } 6161 6162 if (vlan_mpls_tbl_ptr) { 6163 soc_cm_sfree(unit, vlan_mpls_tbl_ptr); 6164 } 6165 6166 return rv; 6167 } 6168 6169 /* 6170 * Function: 6171 * _bcm_td2_nh_nat_id_update_by_l3_intf 6172 * Purpose: 6173 * Routine updates the dst realm nat id of 6174 * next hop interfaces associating with the l3 egress intf. 6175 * Parameters: 6176 * unit - (IN) SOC unit number. 6177 * intf - (IN) Interface index. 6178 * nat_id - (IN) Nat realm id. 6179 * Returns: 6180 * BCM_E_XXX 6181 */ 6182 int 6183 _bcm_td2_nh_nat_id_update_by_l3_intf(int unit, bcm_if_t intf, int nat_id) 6184 { 6185 return _bcm_td2_nh_nat_id_update(unit, _BCM_NH_UPDATE_KEY_L3_INTF, 6186 (void *)&intf, nat_id); 6187 } 6188 6189 /* 6190 * Function: 6191 * _bcm_td2_nh_nat_id_update_by_l3_iif 6192 * Purpose: 6193 * Routine updates the dst realm nat id of 6194 * next hop interfaces associating with the l3 ingress intf. 6195 * Parameters: 6196 * unit - (IN) SOC unit number. 6197 * l3_iif - (IN) L3 ingress interface. 6198 * nat_id - (IN) Nat realm id. 6199 * Returns: 6200 * BCM_E_XXX 6201 */ 6202 int 6203 _bcm_td2_nh_nat_id_update_by_l3_iif(int unit, bcm_if_t l3_iif, int nat_id) 6204 { 6205 return _bcm_td2_nh_nat_id_update(unit, _BCM_NH_UPDATE_KEY_L3_IIF, 6206 (void *)&l3_iif, nat_id); 6207 } 6208 6209 /* 6210 * Function: 6211 * _bcm_td2_nh_nat_id_update_by_vlan 6212 * Purpose: 6213 * Routine updates the dst realm nat id of 6214 * next hop interfaces associating with the vlan. 6215 * Parameters: 6216 * unit - (IN) SOC unit number. 6217 * vlan - (IN) Vlan id. 6218 * nat_id - (IN) Nat realm id. 6219 * Returns: 6220 * BCM_E_XXX 6221 */ 6222 int 6223 _bcm_td2_nh_nat_id_update_by_vlan(int unit, bcm_vlan_t vlan, int nat_id) 6224 { 6225 return _bcm_td2_nh_nat_id_update(unit, _BCM_NH_UPDATE_KEY_VLAN, 6226 (void *)&vlan, nat_id); 6227 } 6228 6229 /* 6230 * Function: 6231 * _bcm_td2_vp_urpf_mode_set 6232 * Purpose: 6233 * Set VP routing urpf mode 6234 * Parameters: 6235 * unit : (IN) Device Unit Number 6236 * Returns: 6237 * BCM_E_XXX 6238 */ 6239 int 6240 _bcm_td2_vp_urpf_mode_set(int unit, bcm_port_t port, int arg) { 6241 6242 int vp; 6243 source_vp_entry_t svp; 6244 6245 if (BCM_GPORT_IS_NIV_PORT(port)) { 6246 vp = BCM_GPORT_NIV_PORT_ID_GET(port); 6247 if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 6248 return BCM_E_NOT_FOUND; 6249 } 6250 } else if (BCM_GPORT_IS_EXTENDER_PORT(port)) { 6251 vp = BCM_GPORT_EXTENDER_PORT_ID_GET(port); 6252 if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) { 6253 return BCM_E_NOT_FOUND; 6254 } 6255 } else if (BCM_GPORT_IS_VLAN_PORT(port)) { 6256 vp = BCM_GPORT_VLAN_PORT_ID_GET(port); 6257 if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) { 6258 return BCM_E_NOT_FOUND; 6259 } 6260 } else { 6261 return BCM_E_PARAM; 6262 } 6263 6264 BCM_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp)); 6265 soc_SOURCE_VPm_field32_set(unit, &svp, URPF_MODEf, (arg ? 1 : 0)); 6266 BCM_IF_ERROR_RETURN(WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp)); 6267 return BCM_E_NONE; 6268 } 6269 6270 /* 6271 * Function: 6272 * _bcm_td2_vp_urpf_mode_get 6273 * Purpose: 6274 * Get VP routing urpf mode 6275 * Parameters: 6276 * unit : (IN) Device Unit Number 6277 * Returns: 6278 * BCM_E_XXX 6279 */ 6280 int 6281 _bcm_td2_vp_urpf_mode_get(int unit, bcm_port_t port, int *arg) { 6282 6283 int vp; 6284 source_vp_entry_t svp; 6285 6286 if (BCM_GPORT_IS_NIV_PORT(port)) { 6287 vp = BCM_GPORT_NIV_PORT_ID_GET(port); 6288 if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 6289 return BCM_E_NOT_FOUND; 6290 } 6291 } else if (BCM_GPORT_IS_EXTENDER_PORT(port)) { 6292 vp = BCM_GPORT_EXTENDER_PORT_ID_GET(port); 6293 if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) { 6294 return BCM_E_NOT_FOUND; 6295 } 6296 } else if (BCM_GPORT_IS_VLAN_PORT(port)) { 6297 vp = BCM_GPORT_VLAN_PORT_ID_GET(port); 6298 if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) { 6299 return BCM_E_NOT_FOUND; 6300 } 6301 } else { 6302 return BCM_E_PARAM; 6303 } 6304 6305 BCM_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp)); 6306 *arg = soc_SOURCE_VPm_field32_get(unit, &svp, URPF_MODEf); 6307 return BCM_E_NONE; 6308 } 6309 6310 /* 6311 * Function: 6312 * _bcm_td2_l3_iif_profile_get 6313 * Purpose: 6314 * Read TD2 iif profile entry and convert to corresponding 6315 * legacy vlan profile flags. 6316 * Parameters: 6317 * unit : (IN) Device Unit Number 6318 * Returns: 6319 * NONE 6320 */ 6321 int 6322 _bcm_td2_l3_intf_iif_profile_get(int unit, bcm_vlan_t vid, 6323 bcm_vlan_control_vlan_t *control) { 6324 6325 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 6326 6327 if (NULL == control) { 6328 return BCM_E_INTERNAL; 6329 } 6330 6331 /* Input parameters sanity check. */ 6332 if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 6333 (vid < soc_mem_index_min(unit, L3_IIFm))) { 6334 return (BCM_E_PARAM); 6335 } 6336 6337 iif.intf_id = vid; 6338 BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif)); 6339 6340 control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST) ? 6341 BCM_VLAN_IP4_DISABLE: 0; 6342 control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST ) ? 6343 BCM_VLAN_IP6_DISABLE: 0; 6344 control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST ) ? 6345 BCM_VLAN_IP4_MCAST_DISABLE: 0; 6346 control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST ) ? 6347 BCM_VLAN_IP6_MCAST_DISABLE: 0; 6348 control->flags |= (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU ) ? 6349 BCM_VLAN_UNKNOWN_IP4_MCAST_TOCPU : 0; 6350 control->flags |= (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU ) ? 6351 BCM_VLAN_UNKNOWN_IP6_MCAST_TOCPU : 0; 6352 control->flags |= (iif.flags & BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU ) ? 6353 BCM_VLAN_ICMP_REDIRECT_TOCPU : 0; 6354 control->flags |= (iif.flags & BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE) ? 6355 BCM_VLAN_IPMC_DO_VLAN_DISABLE : 0; 6356 if (iif.flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) { 6357 control->flags &= ~BCM_VLAN_L3_URPF_DEFAULT_ROUTE_CHECK_DISABLE; 6358 } 6359 if (iif.flags & BCM_L3_INGRESS_GLOBAL_ROUTE) { 6360 control->flags &= ~BCM_VLAN_L3_VRF_GLOBAL_DISABLE; 6361 } 6362 6363 return (BCM_E_NONE); 6364 } 6365 6366 /* 6367 * Function: 6368 * _bcm_td2_l3_iif_profile_update 6369 * Purpose: 6370 * Update TD2 iif profile based on vlan intf flags 6371 * Parameters: 6372 * unit : (IN) Device Unit Number 6373 * Returns: 6374 * NONE 6375 */ 6376 int 6377 _bcm_td2_l3_intf_iif_profile_update(int unit, bcm_vlan_t vid, 6378 bcm_vlan_control_vlan_t *control) { 6379 6380 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 6381 int ret_val; /* Operation return value. */ 6382 6383 /* Input parameters sanity check. */ 6384 if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 6385 (vid < soc_mem_index_min(unit, L3_IIFm))) { 6386 return (BCM_E_PARAM); 6387 } 6388 6389 iif.intf_id = vid; 6390 soc_mem_lock(unit, L3_IIFm); 6391 6392 ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 6393 if (BCM_FAILURE(ret_val)) { 6394 soc_mem_unlock(unit, L3_IIFm); 6395 return (ret_val); 6396 } 6397 6398 /* Set default values */ 6399 iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 6400 iif.flags |= BCM_L3_INGRESS_GLOBAL_ROUTE; 6401 iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST; 6402 iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST; 6403 iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST; 6404 iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST; 6405 iif.flags &= ~BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU; 6406 iif.flags &= ~BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU; 6407 iif.flags &= ~BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC; 6408 iif.flags &= ~BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU; 6409 iif.flags &= ~BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE; 6410 6411 iif.flags |= (control->flags & BCM_VLAN_IP4_DISABLE) ? 6412 BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST : 0; 6413 iif.flags |= (control->flags & BCM_VLAN_IP6_DISABLE) ? 6414 BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST : 0; 6415 iif.flags |= (control->flags & BCM_VLAN_IP4_MCAST_DISABLE) ? 6416 BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST : 0; 6417 iif.flags |= (control->flags & BCM_VLAN_IP6_MCAST_DISABLE) ? 6418 BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST : 0; 6419 iif.flags |= (control->flags & BCM_VLAN_UNKNOWN_IP4_MCAST_TOCPU) ? 6420 BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU : 0; 6421 iif.flags |= (control->flags & BCM_VLAN_UNKNOWN_IP6_MCAST_TOCPU) ? 6422 BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU : 0; 6423 iif.flags |= (control->flags & BCM_VLAN_ICMP_REDIRECT_TOCPU) ? 6424 BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU : 0; 6425 iif.flags |= (control->flags & BCM_VLAN_IPMC_DO_VLAN_DISABLE) ? 6426 BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE : 0; 6427 6428 if (control->flags & BCM_VLAN_L3_URPF_DEFAULT_ROUTE_CHECK_DISABLE) { 6429 iif.flags &= ~BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 6430 } 6431 if (control->flags & BCM_VLAN_L3_VRF_GLOBAL_DISABLE) { 6432 iif.flags &= ~BCM_L3_INGRESS_GLOBAL_ROUTE; 6433 } 6434 6435 ret_val = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL); 6436 6437 soc_mem_unlock(unit, L3_IIFm); 6438 6439 return (ret_val); 6440 } 6441 6442 /* 6443 * Function: 6444 * _bcm_td2_l3_iif_ip4_options_profile_index_set 6445 * Purpose: 6446 * Set the IP_OPTION_PROFILE_INDEX of the table L3_IIF. 6447 * Parameters: 6448 * unit - (IN) unit number 6449 * intf_info - (IN/OUT) information of the l3 ingress interface 6450 * Returns: 6451 * BCM_E_XXX 6452 */ 6453 int 6454 _bcm_td2_l3_iif_ip4_options_profile_index_set(int unit, 6455 _bcm_l3_intf_cfg_t *intf_info) 6456 { 6457 _bcm_l3_ingress_intf_t iif; /* Ingress interface config. */ 6458 int rv = BCM_E_NONE; 6459 uint32 buf[SOC_MAX_MEM_FIELD_WORDS]; 6460 bcm_vlan_t vid; 6461 soc_mem_t vlan_attrs_mem = VLAN_MPLSm; 6462 6463 #ifdef BCM_TRIDENT3_SUPPORT 6464 if (SOC_IS_TRIDENT3X(unit)) { 6465 vlan_attrs_mem = VLAN_TABm; 6466 } 6467 #endif 6468 6469 if (!soc_feature(unit, soc_feature_l3_ip4_options_profile)) { 6470 return BCM_E_UNAVAIL; 6471 } 6472 6473 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 6474 iif.intf_id = intf_info->l3i_vid; 6475 6476 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) { 6477 if (SOC_MEM_FIELD_VALID(unit, vlan_attrs_mem, L3_IIFf)) { 6478 sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 6479 vid = intf_info->l3i_vid; 6480 SOC_IF_ERROR_RETURN( 6481 soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vid, buf)); 6482 6483 if (!soc_mem_field32_get(unit, VLAN_TABm, buf, VALIDf)) { 6484 return BCM_E_NONE; 6485 } 6486 6487 sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 6488 BCM_IF_ERROR_RETURN( 6489 soc_mem_read(unit, vlan_attrs_mem, MEM_BLOCK_ANY, vid, buf)); 6490 iif.intf_id = soc_mem_field32_get(unit, vlan_attrs_mem, 6491 buf, L3_IIFf); 6492 } 6493 } 6494 6495 soc_mem_lock(unit, L3_IIFm); 6496 6497 rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 6498 if (BCM_FAILURE(rv)) { 6499 soc_mem_unlock(unit, L3_IIFm); 6500 return rv; 6501 } 6502 6503 iif.profile_flags |= _BCM_L3_IIF_PROFILE_DO_NOT_UPDATE; 6504 iif.ip4_options_profile_id = intf_info->l3i_ip4_options_profile_id; 6505 rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL); 6506 6507 soc_mem_unlock(unit, L3_IIFm); 6508 return rv; 6509 } 6510 6511 /* 6512 * Function: 6513 * _bcm_td2_l3_iif_ip4_options_profile_index_get 6514 * Purpose: 6515 * Get the IP_OPTION_PROFILE_INDEX of the table L3_IIF. 6516 * Parameters: 6517 * unit - (IN) unit number 6518 * intf_info - (IN/OUT) information of the l3 ingress interface 6519 * Returns: 6520 * BCM_E_XXX 6521 */ 6522 int 6523 _bcm_td2_l3_iif_ip4_options_profile_index_get(int unit, 6524 _bcm_l3_intf_cfg_t *intf_info) 6525 { 6526 _bcm_l3_ingress_intf_t iif; /* Ingress interface config. */ 6527 int rv = BCM_E_NONE; 6528 vlan_tab_entry_t vt; 6529 vlan_mpls_entry_t vlan_mpls; 6530 bcm_vlan_t vid; 6531 6532 if (!soc_feature(unit, soc_feature_l3_ip4_options_profile)) { 6533 return BCM_E_UNAVAIL; 6534 } 6535 6536 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 6537 iif.intf_id = intf_info->l3i_vid; 6538 6539 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) { 6540 if (SOC_MEM_FIELD_VALID(unit, VLAN_MPLSm, L3_IIFf)) { 6541 vid = intf_info->l3i_vid; 6542 SOC_IF_ERROR_RETURN( 6543 soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vid, &vt)); 6544 6545 if (!soc_mem_field32_get(unit, VLAN_TABm, &vt, VALIDf)) { 6546 return BCM_E_NONE; 6547 } 6548 6549 sal_memset(&vlan_mpls, 0, sizeof(vlan_mpls)); 6550 BCM_IF_ERROR_RETURN( 6551 soc_mem_read(unit, VLAN_MPLSm, MEM_BLOCK_ANY, vid, &vlan_mpls)); 6552 iif.intf_id = soc_mem_field32_get(unit, VLAN_MPLSm, 6553 &vlan_mpls, L3_IIFf); 6554 } 6555 } 6556 6557 rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 6558 intf_info->l3i_ip4_options_profile_id = iif.ip4_options_profile_id; 6559 6560 return rv; 6561 } 6562 6563 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 6564 /* 6565 * Function: 6566 * _bcm_td2_l3_ip4_options_profile_sw_dump 6567 * Purpose: 6568 * Displays IP oprion profile software state info 6569 * Parameters: 6570 * unit : (IN) Device Unit Number 6571 * Returns: 6572 * NONE 6573 */ 6574 void 6575 _bcm_td2_l3_ip4_options_profile_sw_dump(int unit) 6576 { 6577 int i; 6578 6579 if (!L3_INFO(unit)->l3_initialized) { 6580 LOG_CLI((BSL_META_U(unit, 6581 "ERROR: L3 module not initialized on Unit:%d \n"), unit)); 6582 return; 6583 } 6584 6585 LOG_CLI((BSL_META_U(unit, 6586 "L3 IP Option: IP_OPTION_CONTROL_PROFILE_TABLEm info \n"))); 6587 for (i = 0; i < _BCM_IP4_OPTIONS_LEN; i++) { 6588 if (_BCM_IP4_OPTIONS_USED_GET(unit, i)) { 6589 LOG_CLI((BSL_META_U(unit, 6590 " Profile id:%4d HW index:%4d\n"), i, 6591 L3_INFO(unit)->ip4_profiles_hw_idx[i])); 6592 } 6593 } 6594 6595 } 6596 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */ 6597 6598 #ifdef BCM_WARM_BOOT_SUPPORT 6599 6600 6601 /* SCACHE size for WB */ 6602 int 6603 _bcm_td2_l3_ip4_options_profile_scache_len_get(int unit, int *wb_alloc_size) 6604 { 6605 if (wb_alloc_size == NULL) { 6606 return BCM_E_PARAM; 6607 } 6608 *wb_alloc_size = sizeof(uint32) * _BCM_IP4_OPTIONS_LEN; 6609 6610 return BCM_E_NONE; 6611 } 6612 6613 /* 6614 * Function: 6615 * _bcm_td2_l3_ip4_options_profile_reinit_hw_profiles_update 6616 * Purpose: 6617 * Updates the shared memory profile tables reference counts 6618 * Parameters: 6619 * unit : (IN) Device Unit Number 6620 * Returns: 6621 * BCM_E_XXX 6622 */ 6623 STATIC int 6624 _bcm_td2_l3_ip4_options_profile_reinit_hw_profiles_update (int unit) 6625 { 6626 int i; 6627 for (i=0; i < _BCM_IP4_OPTIONS_LEN; i++) { 6628 if (_BCM_IP4_OPTIONS_USED_GET(unit, i)) { 6629 BCM_IF_ERROR_RETURN(_bcm_l3_ip4_options_profile_entry_reference(unit, 6630 ((L3_INFO(unit)->ip4_profiles_hw_idx[i]) * 6631 _BCM_IP_OPTION_PROFILE_CHUNK), 6632 _BCM_IP_OPTION_PROFILE_CHUNK)); 6633 } 6634 } 6635 return BCM_E_NONE; 6636 } 6637 6638 6639 6640 /* 6641 * Function: 6642 * _bcm_td2_l3_ip4_options_recover 6643 * Purpose: 6644 * Recover IP Option Profile usage 6645 * Parameters: 6646 * unit : (IN) Device Unit Number 6647 * scache_ptr - (IN) Scache pointer 6648 * (OUT) Updated Scache pointer 6649 * Returns: 6650 * BCM_E_XXX 6651 */ 6652 int 6653 _bcm_td2_l3_ip4_options_recover(int unit, uint8 **scache_ptr) 6654 { 6655 uint32 hw_idx; 6656 int idx; 6657 int rv = BCM_E_NONE; 6658 int stable_size = 0; 6659 6660 if ((scache_ptr == NULL) || (*scache_ptr == NULL)) { 6661 return BCM_E_PARAM; 6662 } 6663 6664 if (SOC_WARM_BOOT(unit)) { 6665 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 6666 6667 if (stable_size == 0) { /* level 1 */ 6668 /* Nothing to recover */ 6669 } else { /* Level 2 */ 6670 /* recover from scache into book-keeping structs */ 6671 for (idx = 0; idx < _BCM_IP4_OPTIONS_LEN; idx++) { 6672 sal_memcpy(&hw_idx, (*scache_ptr), sizeof(uint32)); 6673 (*scache_ptr) += sizeof(hw_idx); 6674 if (hw_idx != _BCM_IP_OPTION_REINIT_INVALID_HW_IDX) { 6675 _BCM_IP4_OPTIONS_USED_SET(unit, idx); 6676 L3_INFO(unit)->ip4_profiles_hw_idx[idx] = hw_idx; 6677 } 6678 } 6679 rv = _bcm_td2_l3_ip4_options_profile_reinit_hw_profiles_update(unit); 6680 } 6681 } 6682 return rv; 6683 } 6684 6685 /* 6686 * Function: 6687 * _bcm_td2_l3_ip4_options_sync 6688 * Purpose: 6689 * Store IP Option Profile usage table into scache. 6690 * Parameters: 6691 * unit : (IN) Device Unit Number 6692 * scache_ptr - (IN) Scache pointer 6693 * (OUT) Updated Scache pointer 6694 * Returns: 6695 * BCM_E_XXX 6696 */ 6697 int 6698 _bcm_td2_l3_ip4_options_sync(int unit, uint8 **scache_ptr) 6699 { 6700 uint32 hw_idx; 6701 int idx; 6702 6703 if ((scache_ptr == NULL) || (*scache_ptr == NULL)) { 6704 return BCM_E_PARAM; 6705 } 6706 6707 /* now store the state into the compressed format */ 6708 for (idx = 0; idx < _BCM_IP4_OPTIONS_LEN; idx++) { 6709 if (_BCM_IP4_OPTIONS_USED_GET(unit, idx)) { 6710 hw_idx = L3_INFO(unit)->ip4_profiles_hw_idx[idx]; 6711 } else { 6712 hw_idx = _BCM_IP_OPTION_REINIT_INVALID_HW_IDX; 6713 } 6714 sal_memcpy((*scache_ptr), &hw_idx, sizeof(uint32)); 6715 (*scache_ptr) += sizeof(hw_idx); 6716 } 6717 return BCM_E_NONE; 6718 } 6719 #endif /* BCM_WARM_BOOT_SUPPORT */ 6720 6721 #ifdef ALPM_ENABLE 6722 /* ALPM Functions */ 6723 6724 6725 /* 6726 * Function: 6727 * _bcm_td2_alpm_lpm_vrf_init 6728 * Purpose: 6729 * Service routine used to translate API vrf id to hw specific. 6730 * Parameters: 6731 * unit - (IN)SOC unit number. 6732 * lpm_cfg - (IN)Prefix info. 6733 * vrf_id - (OUT)Internal vrf id. 6734 * vrf_mask - (OUT)Internal vrf mask. 6735 * Returns: 6736 * BCM_E_XXX 6737 */ 6738 STATIC int 6739 _bcm_td2_alpm_lpm_vrf_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 6740 int *vrf_id, int *vrf_mask) 6741 { 6742 /* Handle special vrf id cases. */ 6743 switch (lpm_cfg->defip_vrf) { 6744 case BCM_L3_VRF_OVERRIDE: 6745 case BCM_L3_VRF_GLOBAL: /* only for td2 */ 6746 *vrf_id = 0; 6747 *vrf_mask = 0; 6748 break; 6749 default: 6750 *vrf_id = lpm_cfg->defip_vrf; 6751 *vrf_mask = SOC_VRF_MAX(unit); 6752 break; 6753 } 6754 6755 /* In any case vrf id shouldn't exceed max field mask. */ 6756 if ((*vrf_id < 0) || (*vrf_id > SOC_VRF_MAX(unit))) { 6757 return (BCM_E_PARAM); 6758 } 6759 return (BCM_E_NONE); 6760 } 6761 6762 6763 /* 6764 * Function: 6765 * _bcm_td2_alpm_mem_ip6_defip_set 6766 * Purpose: 6767 * Set IP6 address mask field in L3_DEFIPm from defip_cfg 6768 * Parameters: 6769 * unit - (IN) SOC unit number; 6770 * lpm_key - (OUT) Buffer to fill. 6771 * lpm_cfg - (IN) Route information. 6772 * alpm_entry - (OUT) ALPM entry to fill 6773 * Note: 6774 * See soc_mem_ip6_addr_set() 6775 */ 6776 STATIC void 6777 _bcm_td2_alpm_lpm64_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 6778 defip_entry_t *lpm_key) 6779 { 6780 bcm_ip6_t mask; /* Subnet mask. */ 6781 uint8 *ip6; /* Ip6 address. */ 6782 uint32 ip6_word[2]; /* Temp storage. */ 6783 int idx; /* Iteration index . */ 6784 6785 /* Just to keep variable name short. */ 6786 ip6 = lpm_cfg->defip_ip6_addr; 6787 6788 /* Create mask from prefix length. */ 6789 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 6790 6791 /* Apply subnet mask */ 6792 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 6793 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 6794 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 6795 ip6[idx] = 0; /* Reset rest of bytes. */ 6796 } 6797 6798 ip6_word[1] = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 6799 ip6_word[0]= ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 6800 6801 /* Set IP Addr */ 6802 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word[1]); 6803 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word[0]); 6804 6805 /* Set IP MASK */ 6806 ip6_word[0] = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3])); 6807 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f, (void *)&ip6_word[0]); 6808 6809 ip6_word[0] = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7])); 6810 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f, (void *)&ip6_word[0]); 6811 } 6812 6813 6814 /* 6815 * Function: 6816 * _bcm_td2_alpm_lpm_ent_init 6817 * Purpose: 6818 * Service routine used to initialize lkup key for lpm entry. 6819 * Also initializes the ALPM SRAM entry. 6820 * Parameters: 6821 * unit - (IN)SOC unit number. 6822 * lpm_cfg - (IN)Prefix info. 6823 * lpm_entry - (OUT)Hw buffer to fill. 6824 * Returns: 6825 * BCM_E_XXX 6826 */ 6827 STATIC int 6828 _bcm_td2_alpm_lpm_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 6829 defip_entry_t *lpm_entry, int nh_ecmp_idx, uint32 *flags) 6830 { 6831 bcm_ip_t ip4_mask; 6832 int vrf_id; 6833 int vrf_mask; 6834 int ipv6; 6835 6836 ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 6837 6838 /* Extract entry vrf id & vrf mask. */ 6839 BCM_IF_ERROR_RETURN 6840 (_bcm_td2_alpm_lpm_vrf_init(unit, lpm_cfg, &vrf_id, &vrf_mask)); 6841 6842 6843 /* Zero buffers. */ 6844 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 6845 6846 /* Set hit bit. */ 6847 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 6848 soc_L3_DEFIPm_field32_set(unit, lpm_entry, HIT0f, 1); 6849 } 6850 6851 /* Set priority override bit. */ 6852 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 6853 soc_L3_DEFIPm_field32_set(unit, lpm_entry, RPE0f, 1); 6854 } 6855 6856 /* Write priority field. */ 6857 soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio); 6858 6859 /* Fill next hop information. */ 6860 if (soc_feature(unit, soc_feature_generic_dest)) { 6861 uint32 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 6862 uint32 dest_val = 0; 6863 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 6864 dest_type = SOC_MEM_FIF_DEST_ECMP; 6865 dest_val = nh_ecmp_idx; 6866 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 6867 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 6868 dest_val = nh_ecmp_idx; 6869 } else { 6870 dest_type = SOC_MEM_FIF_DEST_INVALID; 6871 } 6872 6873 if (dest_type != SOC_MEM_FIF_DEST_INVALID) { 6874 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 6875 dest_type, dest_val); 6876 } 6877 } else { 6878 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 6879 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1); 6880 soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, 6881 nh_ecmp_idx); 6882 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 6883 soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, 6884 nh_ecmp_idx); 6885 } 6886 } 6887 6888 /* Set destination discard flag. */ 6889 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 6890 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DST_DISCARD0f, 1); 6891 } 6892 6893 /* remember src discard flag */ 6894 if (lpm_cfg->defip_flags & BCM_L3_SRC_DISCARD) { 6895 *flags |= SOC_ALPM_RPF_SRC_DISCARD; 6896 } 6897 6898 if (soc_feature(unit, soc_feature_alpm_flex_stat)) { 6899 *flags |= SOC_ALPM_STAT_FLEX; 6900 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f, 0x1); 6901 } 6902 6903 /* Set classification group id. */ 6904 soc_L3_DEFIPm_field32_set(unit, lpm_entry, CLASS_ID0f, 6905 lpm_cfg->defip_lookup_class); 6906 6907 /* Set Global route flag. */ 6908 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 6909 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_ROUTE0f, 0x1); 6910 } 6911 6912 /* Indicate this is an override entry */ 6913 if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 6914 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_HIGH0f, 0x1); 6915 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_ROUTE0f, 0x1); 6916 } 6917 6918 /* Set VRF */ 6919 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_0f, vrf_id); 6920 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK0f, vrf_mask); 6921 6922 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 6923 if (soc_feature(unit, soc_feature_ipmc_defip) && 6924 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 6925 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 6926 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MULTICAST_ROUTE0f, 1); 6927 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 6928 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 2); 6929 } 6930 6931 if (soc_feature(unit, soc_feature_generic_dest)) { 6932 if (lpm_cfg->defip_mc_group > 0) { 6933 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 6934 SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group); 6935 } 6936 } else { 6937 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f, lpm_cfg->defip_mc_group); 6938 } 6939 6940 /* 6941 * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf 6942 */ 6943 if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) { 6944 soc_L3_DEFIPm_field32_set(unit, lpm_entry, EXPECTED_L3_IIF0f, 6945 _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp)); 6946 } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 6947 (lpm_cfg->defip_expected_intf != 0)) { 6948 6949 soc_L3_DEFIPm_field32_set(unit, lpm_entry, EXPECTED_L3_IIF0f, lpm_cfg->defip_expected_intf); 6950 6951 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) { 6952 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, 1); 6953 } 6954 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 6955 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, 1); 6956 } 6957 } 6958 } 6959 #endif 6960 6961 if (ipv6) { 6962 /* Set prefix ip address & mask. */ 6963 _bcm_td2_alpm_lpm64_key_init(unit, lpm_cfg,lpm_entry); 6964 6965 /* Set second part valid bit. */ 6966 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 1); 6967 6968 /* Set mode to ipv6 */ 6969 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODE0_f(unit), 1); 6970 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODE1_f(unit), 1); 6971 6972 /* Set Virtual Router id */ 6973 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_1f, vrf_id); 6974 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK1f, vrf_mask); 6975 } else { 6976 ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len); 6977 /* Apply subnet mask. */ 6978 lpm_cfg->defip_ip_addr &= ip4_mask; 6979 6980 /* Set address to the buffer. */ 6981 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR0f, 6982 lpm_cfg->defip_ip_addr); 6983 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_MASK0f, ip4_mask); 6984 } 6985 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID0f, 1); 6986 6987 /* Set Mode Masks */ 6988 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, MODE_MASK0_f(unit), 6989 (1 << soc_mem_field_length(unit, L3_DEFIPm, MODE_MASK0_f(unit))) - 1); 6990 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, MODE_MASK1_f(unit), 6991 (1 << soc_mem_field_length(unit, L3_DEFIPm, MODE_MASK1_f(unit))) - 1); 6992 6993 /* Set Entry Type Masks */ 6994 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_TYPE0_f(unit), 6995 (1 << soc_mem_field_length(unit, L3_DEFIPm, ENTRY_TYPE0_f(unit))) - 1); 6996 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_TYPE1_f(unit), 6997 (1 << soc_mem_field_length(unit, L3_DEFIPm, ENTRY_TYPE1_f(unit))) - 1); 6998 /* 6999 * Note ipv4 entries are expected to reside in part 0 of the entry. 7000 */ 7001 7002 /* apply for ALPM and Global high */ 7003 /* Base counter index. */ 7004 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f, 7005 lpm_cfg->defip_flex_ctr_base_id); 7006 /* Counter offset mode. */ 7007 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_OFFSET_MODE0f, 7008 lpm_cfg->defip_flex_ctr_mode); 7009 /* Counter pool number. */ 7010 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_POOL_NUMBER0f, 7011 lpm_cfg->defip_flex_ctr_pool); 7012 return (BCM_E_NONE); 7013 } 7014 7015 /* 7016 * Function: 7017 * _bcm_td2_alpm_lpm128_addr_init 7018 * Purpose: 7019 * Set IP6 address field in memory from ip6 addr type. 7020 * Parameters: 7021 * unit - (IN) BCM device number. 7022 * mem - (IN) Memory id. 7023 * entry - (IN) HW entry buffer. 7024 * ip6 - (IN) SW ip6 address buffer. 7025 * Returns: void 7026 */ 7027 STATIC void 7028 _bcm_td2_alpm_lpm128_addr_init(int unit, soc_mem_t mem, uint32 *entry, 7029 const ip6_addr_t ip6) 7030 { 7031 uint32 ip6_field[4]; 7032 ip6_field[3] = ((ip6[12] << 24)| (ip6[13] << 16) | 7033 (ip6[14] << 8) | (ip6[15] << 0)); 7034 soc_mem_field_set(unit, mem, entry, IP_ADDR0_LWRf, &ip6_field[3]); 7035 ip6_field[2] = ((ip6[8] << 24) | (ip6[9] << 16) | 7036 (ip6[10] << 8) | (ip6[11] << 0)); 7037 soc_mem_field_set(unit, mem, entry, IP_ADDR1_LWRf, &ip6_field[2]); 7038 ip6_field[1] = ((ip6[4] << 24) | (ip6[5] << 16) | 7039 (ip6[6] << 8) | (ip6[7] << 0)); 7040 soc_mem_field_set(unit, mem, entry, IP_ADDR0_UPRf, &ip6_field[1]); 7041 ip6_field[0] = ((ip6[0] << 24) | (ip6[1] << 16) | 7042 (ip6[2] << 8) | (ip6[3] << 0)); 7043 soc_mem_field_set(unit, mem, entry, IP_ADDR1_UPRf, ip6_field); 7044 } 7045 7046 /* 7047 * Function: 7048 * _bcm_td2_alpm_lpm128_mask_init 7049 * Purpose: 7050 * Set IP6 mask field in memory from ip6 addr type. 7051 * Parameters: 7052 * unit - (IN) BCM device number. 7053 * mem - (IN) Memory id. 7054 * entry - (IN) HW entry buffer. 7055 * ip6 - (IN) SW ip6 address buffer. 7056 * Returns: void 7057 */ 7058 STATIC void 7059 _bcm_td2_alpm_lpm128_mask_init(int unit, soc_mem_t mem, uint32 *entry, 7060 const ip6_addr_t ip6) 7061 { 7062 uint32 ip6_field[4]; 7063 ip6_field[3] = ((ip6[12] << 24)| (ip6[13] << 16) | 7064 (ip6[14] << 8) | (ip6[15] << 0)); 7065 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK0_LWRf, &ip6_field[3]); 7066 ip6_field[2] = ((ip6[8] << 24) | (ip6[9] << 16) | 7067 (ip6[10] << 8) | (ip6[11] << 0)); 7068 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK1_LWRf, &ip6_field[2]); 7069 ip6_field[1] = ((ip6[4] << 24) | (ip6[5] << 16) | 7070 (ip6[6] << 8) | (ip6[7] << 0)); 7071 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK0_UPRf, &ip6_field[1]); 7072 ip6_field[0] = ((ip6[0] << 24) | (ip6[1] << 16) | 7073 (ip6[2] << 8) | (ip6[3] << 0)); 7074 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK1_UPRf, ip6_field); 7075 } 7076 7077 STATIC int 7078 _bcm_td2_alpm_lpm128_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 7079 defip_pair_128_entry_t *lpm_entry, int nh_ecmp_idx, uint32 *flags) 7080 { 7081 int vrf_id; 7082 int vrf_mask; 7083 bcm_ip6_t mask; /* Subnet mask. */ 7084 7085 /* Extract entry vrf id & vrf mask. */ 7086 BCM_IF_ERROR_RETURN 7087 (_bcm_td2_alpm_lpm_vrf_init(unit, lpm_cfg, &vrf_id, &vrf_mask)); 7088 7089 /* Zero buffers. */ 7090 sal_memset(lpm_entry, 0, sizeof(*lpm_entry)); 7091 7092 /* Set hit bit. */ 7093 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 7094 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, HITf, 1); 7095 } 7096 7097 /* Set priority override bit. */ 7098 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 7099 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, RPEf, 1); 7100 } 7101 7102 /* Write priority field. */ 7103 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, PRIf, lpm_cfg->defip_prio); 7104 7105 /* Fill next hop information. */ 7106 if (soc_feature(unit, soc_feature_generic_dest)) { 7107 uint32 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 7108 uint32 dest_val = 0; 7109 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 7110 dest_type = SOC_MEM_FIF_DEST_ECMP; 7111 dest_val = nh_ecmp_idx; 7112 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 7113 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 7114 dest_val = nh_ecmp_idx; 7115 } else { 7116 dest_type = SOC_MEM_FIF_DEST_INVALID; 7117 } 7118 7119 if (dest_type != SOC_MEM_FIF_DEST_INVALID) { 7120 soc_mem_field32_dest_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 7121 DESTINATIONf, dest_type, dest_val); 7122 } 7123 } else { 7124 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 7125 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, ECMPf, 1); 7126 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, NEXT_HOP_INDEXf, 7127 nh_ecmp_idx); 7128 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 7129 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, NEXT_HOP_INDEXf, 7130 nh_ecmp_idx); 7131 } 7132 } 7133 7134 /* Set destination discard flag. */ 7135 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 7136 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, DST_DISCARDf, 1); 7137 } 7138 7139 /* remember src discard flag */ 7140 if (lpm_cfg->defip_flags & BCM_L3_SRC_DISCARD) { 7141 *flags |= SOC_ALPM_RPF_SRC_DISCARD; 7142 } 7143 7144 if (soc_feature(unit, soc_feature_alpm_flex_stat)) { 7145 *flags |= SOC_ALPM_STAT_FLEX; 7146 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_VIEWf, 0x1); 7147 } 7148 7149 /* Set classification group id. */ 7150 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, CLASS_IDf, 7151 lpm_cfg->defip_lookup_class); 7152 7153 /* Set Global route flag. */ 7154 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 7155 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_ROUTEf, 0x1); 7156 } 7157 7158 /* Indicate this is an override entry */ 7159 if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 7160 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_HIGHf, 0x1); 7161 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_ROUTEf, 0x1); 7162 } 7163 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 7164 if (soc_feature(unit, soc_feature_ipmc_defip) && 7165 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 7166 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 7167 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MULTICAST_ROUTEf, 1); 7168 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 7169 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, DATA_TYPEf, 2); 7170 } 7171 7172 if (soc_feature(unit, soc_feature_generic_dest)) { 7173 if (lpm_cfg->defip_mc_group > 0) { 7174 soc_mem_field32_dest_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 7175 DESTINATIONf, SOC_MEM_FIF_DEST_IPMC, 7176 lpm_cfg->defip_mc_group); 7177 } 7178 } else { 7179 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, L3MC_INDEXf, lpm_cfg->defip_mc_group); 7180 } 7181 7182 /* 7183 * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf 7184 */ 7185 if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) { 7186 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 7187 EXPECTED_L3_IIFf, _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp)); 7188 } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 7189 (lpm_cfg->defip_expected_intf != 0)) { 7190 7191 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, EXPECTED_L3_IIFf, lpm_cfg->defip_expected_intf); 7192 7193 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) { 7194 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf, 1); 7195 } 7196 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 7197 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf, 1); 7198 } 7199 } 7200 } 7201 #endif 7202 7203 /* Create mask from prefix length. */ 7204 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 7205 7206 /* Apply mask on address. */ 7207 bcm_xgs3_l3_mask6_apply(mask, lpm_cfg->defip_ip6_addr); 7208 7209 /* Set prefix ip address & mask. */ 7210 _bcm_td2_alpm_lpm128_addr_init(unit, L3_DEFIP_PAIR_128m, 7211 (uint32 *) lpm_entry, lpm_cfg->defip_ip6_addr); 7212 7213 _bcm_td2_alpm_lpm128_mask_init(unit, L3_DEFIP_PAIR_128m, 7214 (uint32 *) lpm_entry, mask); 7215 7216 /* Set Virtual Router id */ 7217 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_0_LWRf, vrf_id); 7218 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_1_LWRf, vrf_id); 7219 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_0_UPRf, vrf_id); 7220 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_1_UPRf, vrf_id); 7221 7222 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK0_LWRf, 7223 vrf_mask); 7224 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK1_LWRf, 7225 vrf_mask); 7226 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK0_UPRf, 7227 vrf_mask); 7228 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK1_UPRf, 7229 vrf_mask); 7230 7231 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID0_LWRf, 1); 7232 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID1_LWRf, 1); 7233 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID0_UPRf, 1); 7234 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID1_UPRf, 1); 7235 7236 /* Set mode to ipv6-128 */ 7237 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE0_LWR_f(unit), 3); 7238 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE1_LWR_f(unit), 3); 7239 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE0_UPR_f(unit), 3); 7240 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE1_UPR_f(unit), 3); 7241 7242 /* Set Mode Masks */ 7243 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK0_LWR_f(unit), 7244 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK0_LWR_f(unit))) - 1); 7245 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK1_LWR_f(unit), 7246 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK1_LWR_f(unit))) - 1); 7247 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK0_UPR_f(unit), 7248 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK0_UPR_f(unit))) - 1); 7249 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK1_UPR_f(unit), 7250 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK1_UPR_f(unit))) - 1); 7251 7252 /* Set Entry Type Masks */ 7253 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE0_LWR_f(unit), 7254 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE0_LWR_f(unit))) - 1); 7255 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE1_LWR_f(unit), 7256 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE1_LWR_f(unit))) - 1); 7257 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE0_UPR_f(unit), 7258 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE0_UPR_f(unit))) - 1); 7259 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE1_UPR_f(unit), 7260 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE1_UPR_f(unit))) - 1); 7261 7262 /* Base counter index. */ 7263 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_BASE_COUNTER_IDXf, 7264 lpm_cfg->defip_flex_ctr_base_id); 7265 /* Counter offset mode. */ 7266 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_OFFSET_MODEf, 7267 lpm_cfg->defip_flex_ctr_mode); 7268 /* Counter pool number. */ 7269 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_POOL_NUMBERf, 7270 lpm_cfg->defip_flex_ctr_pool); 7271 return (BCM_E_NONE); 7272 } 7273 7274 7275 /* 7276 * Function: 7277 * _bcm_td2_alpm_lpm64_key_parse 7278 * Purpose: 7279 * Set an IP6 address field in L3_DEFIPm 7280 * Note: 7281 * See soc_mem_ip6_addr_set() 7282 */ 7283 STATIC void 7284 _bcm_td2_alpm_lpm64_key_parse(int unit, const void *lpm_key, 7285 _bcm_defip_cfg_t *lpm_cfg) 7286 { 7287 uint8 *ip6; /* Ip6 address. */ 7288 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 7289 uint32 ip6_word; /* Temp storage. */ 7290 7291 sal_memset(mask, 0, sizeof (bcm_ip6_t)); 7292 7293 /* Just to keep variable name short. */ 7294 ip6 = lpm_cfg->defip_ip6_addr; 7295 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 7296 7297 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word); 7298 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 7299 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 7300 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 7301 ip6[3] = (uint8) (ip6_word & 0xff); 7302 7303 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word); 7304 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 7305 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 7306 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 7307 ip6[7] = (uint8) (ip6_word & 0xff); 7308 7309 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word); 7310 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 7311 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 7312 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 7313 mask[3] = (uint8) (ip6_word & 0xff); 7314 7315 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word); 7316 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 7317 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 7318 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 7319 mask[7] = (uint8) (ip6_word & 0xff); 7320 7321 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 7322 } 7323 7324 /* 7325 * Function: 7326 * _bcm_td2_alpm_lpm_key_parse 7327 * Purpose: 7328 * Parse entry key from DEFIP table. 7329 * Parameters: 7330 * unit - (IN)SOC unit number. 7331 * lpm_cfg - (OUT)Buffer to fill defip information. 7332 * lpm_entry - (IN) Buffer read from hw. 7333 * Returns: 7334 * void 7335 */ 7336 STATIC void 7337 _bcm_td2_alpm_lpm_key_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 7338 defip_entry_t *lpm_entry) 7339 { 7340 bcm_ip_t v4_mask; 7341 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 7342 7343 /* Set prefix ip address & mask. */ 7344 if (ipv6) { 7345 _bcm_td2_alpm_lpm64_key_parse(unit, lpm_entry, lpm_cfg); 7346 } else { 7347 /* Get ipv4 address. */ 7348 lpm_cfg->defip_ip_addr = 7349 soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR0f); 7350 7351 /* Get subnet mask. */ 7352 v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_MASK0f); 7353 7354 /* Fill mask length. */ 7355 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 7356 } 7357 7358 /* Get Virtual Router id */ 7359 soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf, NULL); 7360 return; 7361 } 7362 7363 7364 /* 7365 * Function: 7366 * _bcm_td2_alpm_lpm_data_parse 7367 * Purpose: 7368 * Parse an entry from DEFIP table. 7369 * Parameters: 7370 * unit - (IN)SOC unit number. 7371 * lpm_cfg - (OUT)Buffer to fill defip information. 7372 * nh_ecmp_idx - (OUT)Next hop index or ecmp group id. 7373 * lpm_entry - (IN) Buffer read from hw. 7374 * Returns: 7375 * void 7376 */ 7377 STATIC INLINE void 7378 _bcm_td2_alpm_lpm_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx, 7379 defip_entry_t *lpm_entry) 7380 { 7381 int is_ecmp = 0; 7382 uint32 nh_ecmp_idx = 0; 7383 int ipv6 = soc_L3_DEFIPm_field32_get(unit, lpm_entry, MODE0_f(unit)); 7384 7385 /* Reset entry flags first. */ 7386 lpm_cfg->defip_flags = 0; 7387 7388 /* Check if entry points to ecmp group. */ 7389 if (soc_feature(unit, soc_feature_generic_dest)) { 7390 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 7391 nh_ecmp_idx = soc_mem_field32_dest_get(unit, L3_DEFIPm, lpm_entry, 7392 DESTINATION0f, &dest_type); 7393 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 7394 is_ecmp = 1; 7395 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 7396 nh_ecmp_idx = 0; 7397 } 7398 } else { 7399 is_ecmp = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f); 7400 if (is_ecmp) { 7401 nh_ecmp_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f); 7402 } else { 7403 nh_ecmp_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f); 7404 } 7405 } 7406 7407 if (is_ecmp) { 7408 /* Mark entry as ecmp */ 7409 lpm_cfg->defip_ecmp = 1; 7410 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 7411 7412 /* Get ecmp group id. */ 7413 if (p_nh_ecmp_idx) { 7414 *p_nh_ecmp_idx = nh_ecmp_idx; 7415 } 7416 } else { 7417 /* Mark entry as non-ecmp. */ 7418 lpm_cfg->defip_ecmp = 0; 7419 7420 /* Reset ecmp group next hop count. */ 7421 lpm_cfg->defip_ecmp_count = 0; 7422 7423 /* Get next hop index. */ 7424 if (p_nh_ecmp_idx) { 7425 *p_nh_ecmp_idx = nh_ecmp_idx; 7426 } 7427 } 7428 /* Get entry priority. */ 7429 lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f); 7430 7431 /* Get hit bit. */ 7432 if (!ALPM_CTRL(unit).hit_bits_skip && 7433 soc_L3_DEFIPm_field32_get(unit, lpm_entry, HIT0f)) { 7434 lpm_cfg->defip_flags |= BCM_L3_HIT; 7435 } 7436 7437 /* Get priority override bit. */ 7438 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE0f)) { 7439 lpm_cfg->defip_flags |= BCM_L3_RPE; 7440 } 7441 7442 /* Get destination discard flag. */ 7443 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) { 7444 if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) { 7445 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 7446 } 7447 } 7448 7449 #if defined(BCM_TRX_SUPPORT) 7450 /* Set classification group id. */ 7451 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) { 7452 lpm_cfg->defip_lookup_class = 7453 soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f); 7454 } 7455 #endif /* BCM_TRX_SUPPORT */ 7456 7457 7458 if (ipv6) { 7459 lpm_cfg->defip_flags |= BCM_L3_IP6; 7460 /* Get hit bit from the second part of the entry. */ 7461 if (!ALPM_CTRL(unit).hit_bits_skip && 7462 soc_L3_DEFIPm_field32_get(unit, lpm_entry, HIT1f)) { 7463 lpm_cfg->defip_flags |= BCM_L3_HIT; 7464 } 7465 7466 /* Get priority override bit from the second part of the entry. */ 7467 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE1f)) { 7468 lpm_cfg->defip_flags |= BCM_L3_RPE; 7469 } 7470 } 7471 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT) 7472 if (soc_feature(unit, soc_feature_ipmc_defip)) { 7473 int ipmc_route = 0; 7474 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 7475 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 7476 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 7477 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 7478 ipmc_route = 1; 7479 } else { 7480 ipmc_route = 0; 7481 } 7482 } 7483 7484 if (ipmc_route) { 7485 int val; 7486 7487 lpm_cfg->defip_flags |= BCM_L3_IPMC; 7488 if (p_nh_ecmp_idx) { 7489 *p_nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; 7490 } 7491 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f)) { 7492 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP; 7493 } 7494 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f)) { 7495 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 7496 } 7497 /* 7498 * RP ID and ExpectedIIF are overlaid. 7499 */ 7500 val = soc_L3_DEFIPm_field32_get(unit, lpm_entry, EXPECTED_L3_IIF0f); 7501 7502 if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) { 7503 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIPm, RPA_ID0f)) - 1; 7504 /* 7505 * 1) If value is more than RPA_ID field then its l3_iif. 7506 * N/A for TD3/MV2/HX5 to support warmboot. 7507 * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid 7508 */ 7509 if ((lpm_cfg->defip_ipmc_flags & 7510 (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) || 7511 (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) || 7512 SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) { 7513 lpm_cfg->defip_expected_intf = val; 7514 if (0 != lpm_cfg->defip_expected_intf) { 7515 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 7516 } 7517 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 7518 } else { 7519 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE; 7520 lpm_cfg->defip_l3a_rp = val & rpa_id_mask; 7521 lpm_cfg->defip_expected_intf = val; 7522 } 7523 } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) { 7524 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val); 7525 } else { 7526 lpm_cfg->defip_expected_intf = val; 7527 7528 if (0 != lpm_cfg->defip_expected_intf) { 7529 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 7530 } 7531 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 7532 } 7533 7534 if (soc_feature(unit, soc_feature_generic_dest)) { 7535 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 7536 uint32 dest_value = 0; 7537 dest_value = soc_mem_field32_dest_get(unit, 7538 L3_DEFIPm, lpm_entry, 7539 DESTINATION0f, &dest_type); 7540 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 7541 lpm_cfg->defip_mc_group = dest_value; 7542 } else { 7543 lpm_cfg->defip_mc_group = 0; 7544 } 7545 } else { 7546 lpm_cfg->defip_mc_group = soc_mem_field32_get(unit, L3_DEFIPm, 7547 lpm_entry, L3MC_INDEX0f); 7548 } 7549 } 7550 } 7551 #endif 7552 7553 7554 /* Read base counter index. */ 7555 lpm_cfg->defip_flex_ctr_base_id = 7556 soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f); 7557 /* Read counter offset mode. */ 7558 lpm_cfg->defip_flex_ctr_mode = 7559 soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_OFFSET_MODE0f); 7560 /* Read counter pool number. */ 7561 lpm_cfg->defip_flex_ctr_pool = 7562 soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_POOL_NUMBER0f); 7563 7564 return; 7565 } 7566 7567 7568 /* 7569 * Function: 7570 * _bcm_td2_alpm_lpm128_mask_parse 7571 * Purpose: 7572 * Read IP6 mask field from memory field to ip6_addr_t buffer. 7573 * Parameters: 7574 * unit - (IN) BCM device number. 7575 * mem - (IN) Memory id. 7576 * entry - (IN) HW entry buffer. 7577 * ip6 - (OUT) SW ip6 address buffer. 7578 * Returns: void 7579 */ 7580 STATIC void 7581 _bcm_td2_alpm_lpm128_mask_parse(int unit, soc_mem_t mem, const void *entry, 7582 ip6_addr_t ip6) 7583 { 7584 uint32 ip6_field[4]; 7585 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK0_LWRf, (uint32 *)&ip6_field[3]); 7586 ip6[12] = (uint8) (ip6_field[3] >> 24); 7587 ip6[13] = (uint8) (ip6_field[3] >> 16 & 0xff); 7588 ip6[14] = (uint8) (ip6_field[3] >> 8 & 0xff); 7589 ip6[15] = (uint8) (ip6_field[3] & 0xff); 7590 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK1_LWRf, (uint32 *)&ip6_field[2]); 7591 ip6[8] = (uint8) (ip6_field[2] >> 24); 7592 ip6[9] = (uint8) (ip6_field[2] >> 16 & 0xff); 7593 ip6[10] = (uint8) (ip6_field[2] >> 8 & 0xff); 7594 ip6[11] = (uint8) (ip6_field[2] & 0xff); 7595 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK0_UPRf, (uint32 *)&ip6_field[1]); 7596 ip6[4] = (uint8) (ip6_field[1] >> 24); 7597 ip6[5] = (uint8) (ip6_field[1] >> 16 & 0xff); 7598 ip6[6] =(uint8) (ip6_field[1] >> 8 & 0xff); 7599 ip6[7] =(uint8) (ip6_field[1] & 0xff); 7600 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK1_UPRf, ip6_field); 7601 ip6[0] =(uint8) (ip6_field[0] >> 24); 7602 ip6[1] =(uint8) (ip6_field[0] >> 16 & 0xff); 7603 ip6[2] =(uint8) (ip6_field[0] >> 8 & 0xff); 7604 ip6[3] =(uint8) (ip6_field[0] & 0xff); 7605 } 7606 7607 /* 7608 * Function: 7609 * _bcm_td2_alpm_lpm128_addr_parse 7610 * Purpose: 7611 * Read IP6 address field from memory field to ip6_addr_t buffer. 7612 * Parameters: 7613 * unit - (IN) BCM device number. 7614 * mem - (IN) Memory id. 7615 * entry - (IN) HW entry buffer. 7616 * ip6 - (OUT) SW ip6 address buffer. 7617 * Returns: void 7618 */ 7619 STATIC void 7620 _bcm_td2_alpm_lpm128_addr_parse(int unit, soc_mem_t mem, const void *entry, 7621 ip6_addr_t ip6) 7622 { 7623 uint32 ip6_field[4]; 7624 soc_mem_field_get(unit, mem, entry, IP_ADDR0_LWRf, (uint32 *)&ip6_field[3]); 7625 ip6[12] = (uint8) (ip6_field[3] >> 24); 7626 ip6[13] = (uint8) (ip6_field[3] >> 16 & 0xff); 7627 ip6[14] = (uint8) (ip6_field[3] >> 8 & 0xff); 7628 ip6[15] = (uint8) (ip6_field[3] & 0xff); 7629 soc_mem_field_get(unit, mem, entry, IP_ADDR1_LWRf, (uint32 *)&ip6_field[2]); 7630 ip6[8] = (uint8) (ip6_field[2] >> 24); 7631 ip6[9] = (uint8) (ip6_field[2] >> 16 & 0xff); 7632 ip6[10] = (uint8) (ip6_field[2] >> 8 & 0xff); 7633 ip6[11] = (uint8) (ip6_field[2] & 0xff); 7634 soc_mem_field_get(unit, mem, entry, IP_ADDR0_UPRf, (uint32 *)&ip6_field[1]); 7635 ip6[4] = (uint8) (ip6_field[1] >> 24); 7636 ip6[5] = (uint8) (ip6_field[1] >> 16 & 0xff); 7637 ip6[6] =(uint8) (ip6_field[1] >> 8 & 0xff); 7638 ip6[7] =(uint8) (ip6_field[1] & 0xff); 7639 soc_mem_field_get(unit, mem, entry, IP_ADDR1_UPRf, ip6_field); 7640 ip6[0] =(uint8) (ip6_field[0] >> 24); 7641 ip6[1] =(uint8) (ip6_field[0] >> 16 & 0xff); 7642 ip6[2] =(uint8) (ip6_field[0] >> 8 & 0xff); 7643 ip6[3] =(uint8) (ip6_field[0] & 0xff); 7644 } 7645 7646 /* 7647 * Function: 7648 * _bcm_td2_alpm_lpm128_key_parse 7649 * Purpose: 7650 * Parse route entry key from L3_DEFIP_PAIR_128 table. 7651 * Parameters: 7652 * unit - (IN)SOC unit number. 7653 * entry - (IN)Hw entry buffer. 7654 * lpm_cfg - (IN/OUT)Buffer to fill defip information. 7655 * Returns: 7656 * BCM_E_XXX 7657 */ 7658 STATIC int 7659 _bcm_td2_alpm_lpm128_key_parse(int unit, uint32 *hw_entry, 7660 _bcm_defip_cfg_t *lpm_cfg) 7661 { 7662 soc_mem_t mem = L3_DEFIP_PAIR_128m; /* Route table memory. */ 7663 bcm_ip6_t mask; /* Subnet mask. */ 7664 7665 /* Input parameters check. */ 7666 if ((lpm_cfg == NULL) || (hw_entry == NULL)) { 7667 return (BCM_E_PARAM); 7668 } 7669 7670 /* Extract ip6 address. */ 7671 _bcm_td2_alpm_lpm128_addr_parse(unit,mem, hw_entry, 7672 lpm_cfg->defip_ip6_addr); 7673 7674 /* Extract subnet mask. */ 7675 _bcm_td2_alpm_lpm128_mask_parse(unit, mem, hw_entry, mask); 7676 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 7677 7678 /* Extract vrf id & vrf mask. */ 7679 if(!soc_mem_field32_get(unit, mem, hw_entry, VRF_ID_MASK0_LWRf)) { 7680 lpm_cfg->defip_vrf = BCM_L3_VRF_OVERRIDE; 7681 } else { 7682 lpm_cfg->defip_vrf = soc_mem_field32_get(unit, mem, hw_entry, 7683 VRF_ID_0_LWRf); 7684 } 7685 return (BCM_E_NONE); 7686 } 7687 7688 7689 STATIC INLINE void 7690 _bcm_td2_alpm_lpm128_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 7691 int *p_nh_ecmp_idx, defip_pair_128_entry_t *lpm_entry) 7692 { 7693 int is_ecmp = 0; 7694 uint32 nh_ecmp_idx = 0; 7695 soc_mem_t mem = L3_DEFIP_PAIR_128m; 7696 int ipv6 = soc_mem_field32_get(unit, mem, lpm_entry, MODE0_LWR_f(unit)); 7697 7698 /* Reset entry flags first. */ 7699 lpm_cfg->defip_flags = 0; 7700 7701 /* Check if entry points to ecmp group. */ 7702 if (soc_feature(unit, soc_feature_generic_dest)) { 7703 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 7704 nh_ecmp_idx = soc_mem_field32_dest_get(unit, mem, lpm_entry, 7705 DESTINATIONf, &dest_type); 7706 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 7707 is_ecmp = 1; 7708 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 7709 nh_ecmp_idx = 0; 7710 } 7711 } else { 7712 is_ecmp = soc_mem_field32_get(unit, mem, lpm_entry, ECMPf); 7713 if (is_ecmp) { 7714 nh_ecmp_idx = soc_mem_field32_get(unit, mem, lpm_entry, ECMP_PTRf); 7715 } else { 7716 nh_ecmp_idx = soc_mem_field32_get(unit, mem, lpm_entry, NEXT_HOP_INDEXf); 7717 } 7718 } 7719 7720 if (is_ecmp) { 7721 /* Mark entry as ecmp */ 7722 lpm_cfg->defip_ecmp = 1; 7723 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 7724 7725 /* Get ecmp group id. */ 7726 if (p_nh_ecmp_idx) { 7727 *p_nh_ecmp_idx = nh_ecmp_idx; 7728 } 7729 } else { 7730 /* Mark entry as non-ecmp. */ 7731 lpm_cfg->defip_ecmp = 0; 7732 7733 /* Reset ecmp group next hop count. */ 7734 lpm_cfg->defip_ecmp_count = 0; 7735 7736 /* Get next hop index. */ 7737 if (p_nh_ecmp_idx) { 7738 *p_nh_ecmp_idx = nh_ecmp_idx; 7739 } 7740 } 7741 /* Get entry priority. */ 7742 lpm_cfg->defip_prio = 7743 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, PRIf); 7744 7745 /* Get hit bit. */ 7746 if (!ALPM_CTRL(unit).hit_bits_skip && 7747 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, HITf)) { 7748 lpm_cfg->defip_flags |= BCM_L3_HIT; 7749 } 7750 7751 /* Get priority override bit. */ 7752 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, RPEf)) { 7753 lpm_cfg->defip_flags |= BCM_L3_RPE; 7754 } 7755 7756 /* Get destination discard flag. */ 7757 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, DST_DISCARDf)) { 7758 if(soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, DST_DISCARDf)) { 7759 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 7760 } 7761 } 7762 7763 #if defined(BCM_TRX_SUPPORT) 7764 /* Set classification group id. */ 7765 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, CLASS_IDf)) { 7766 lpm_cfg->defip_lookup_class = 7767 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, CLASS_IDf); 7768 } 7769 #endif /* BCM_TRX_SUPPORT */ 7770 7771 if (ipv6) { 7772 lpm_cfg->defip_flags |= BCM_L3_IP6; 7773 /* Get hit bit from the second part of the entry. */ 7774 if (!ALPM_CTRL(unit).hit_bits_skip && 7775 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, HITf)) { 7776 lpm_cfg->defip_flags |= BCM_L3_HIT; 7777 } 7778 7779 /* Get priority override bit from the second part of the entry. */ 7780 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, RPEf)) { 7781 lpm_cfg->defip_flags |= BCM_L3_RPE; 7782 } 7783 } 7784 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT) 7785 if (soc_feature(unit, soc_feature_ipmc_defip)) { 7786 int is_ipmc = 0; 7787 7788 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 7789 is_ipmc = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 7790 lpm_entry, MULTICAST_ROUTEf); 7791 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 7792 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 7793 lpm_entry, DATA_TYPEf) == 2) { 7794 is_ipmc = 1; 7795 } else { 7796 is_ipmc = 0; 7797 } 7798 } 7799 7800 if (is_ipmc) { 7801 int val; 7802 lpm_cfg->defip_flags |= BCM_L3_IPMC; 7803 7804 if (p_nh_ecmp_idx) { 7805 *p_nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; 7806 } 7807 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, 7808 lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf)) { 7809 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP; 7810 } 7811 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, 7812 lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf)) { 7813 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 7814 } 7815 /* 7816 * RP ID and ExpectedIIF are overlaid. 7817 */ 7818 val = soc_L3_DEFIP_PAIR_128m_field32_get(unit, 7819 lpm_entry, EXPECTED_L3_IIFf); 7820 if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) { 7821 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, RPA_IDf)) - 1; 7822 /* 7823 * 1) If value is more than RPA_ID field then its l3_iif. 7824 * N/A for TD3/MV2/HX5 to support warmboot. 7825 * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid 7826 */ 7827 if ((lpm_cfg->defip_ipmc_flags & 7828 (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) || 7829 (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) || 7830 SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) { 7831 lpm_cfg->defip_expected_intf = val; 7832 if (0 != lpm_cfg->defip_expected_intf) { 7833 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 7834 } 7835 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 7836 } else { 7837 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE; 7838 lpm_cfg->defip_l3a_rp = val & rpa_id_mask; 7839 lpm_cfg->defip_expected_intf = val; 7840 } 7841 } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) { 7842 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val); 7843 } else { 7844 lpm_cfg->defip_expected_intf = val; 7845 7846 if (0 != lpm_cfg->defip_expected_intf) { 7847 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 7848 } 7849 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 7850 } 7851 7852 if (soc_feature(unit, soc_feature_generic_dest)) { 7853 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 7854 uint32 dest_value = 0; 7855 dest_value = soc_mem_field32_dest_get(unit, mem, lpm_entry, 7856 DESTINATIONf, &dest_type); 7857 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 7858 lpm_cfg->defip_mc_group = dest_value; 7859 } else { 7860 lpm_cfg->defip_mc_group = 0; 7861 } 7862 } else { 7863 lpm_cfg->defip_mc_group = soc_L3_DEFIP_PAIR_128m_field32_get(unit, 7864 lpm_entry, L3MC_INDEXf); 7865 } 7866 } 7867 } 7868 #endif 7869 7870 7871 /* Read base counter index. */ 7872 lpm_cfg->defip_flex_ctr_base_id = 7873 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_BASE_COUNTER_IDXf); 7874 /* Read counter offset mode. */ 7875 lpm_cfg->defip_flex_ctr_mode = 7876 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_OFFSET_MODEf); 7877 /* Read counter pool number. */ 7878 lpm_cfg->defip_flex_ctr_pool = 7879 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_POOL_NUMBERf); 7880 7881 return; 7882 } 7883 7884 /* 7885 * Function: 7886 * _bcm_td2_alpm_l3_defip_mem_get 7887 * Purpose: 7888 * Resolve route table memory for a given route entry. 7889 * Parameters: 7890 * unit - (IN)SOC unit number. 7891 * flags - (IN)IPv6/IPv4 route. 7892 * plen - (IN)Prefix length. 7893 * mem - (OUT)Route table memory. 7894 * Returns: 7895 * BCM_E_XXX 7896 */ 7897 STATIC int 7898 _bcm_td2_alpm_l3_defip_mem_get(int unit, uint32 flags, int plen, soc_mem_t *mem) 7899 { 7900 soc_mem_t defip_mem = L3_DEFIPm; 7901 soc_mem_t defip_pair_mem = L3_DEFIP_PAIR_128m; 7902 7903 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) { 7904 defip_mem = L3_DEFIP_LEVEL1m; 7905 defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m; 7906 } 7907 7908 /* Default value */ 7909 if (mem) { 7910 *mem = defip_mem; 7911 } 7912 if ((flags & BCM_L3_IP6)) { 7913 if (soc_mem_index_count(unit, defip_pair_mem) > 0) { 7914 if (mem) { 7915 *mem = defip_pair_mem; 7916 } 7917 return BCM_E_NONE; 7918 } 7919 /* no v6-128 config. allow only v6-64 */ 7920 if (plen > 64) { 7921 LOG_ERROR(BSL_LS_BCM_L3, 7922 (BSL_META_U(unit, 7923 "Cannot allow prefix length > 64 in " 7924 "%s\n"), SOC_MEM_NAME(unit, defip_mem))); 7925 return BCM_E_PARAM; 7926 } 7927 } else if (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0) { 7928 /* no l3_defip. cannot insert ipv4 */ 7929 LOG_ERROR(BSL_LS_BCM_L3, 7930 (BSL_META_U(unit, 7931 "Cannot allow ipv4 routes in " 7932 "%s\n"), SOC_MEM_NAME(unit, defip_pair_mem))); 7933 return BCM_E_PARAM; 7934 } 7935 7936 return BCM_E_NONE; 7937 } 7938 7939 7940 /* 7941 * Function: 7942 * _bcm_td2_alpm_128_clear_hit 7943 * Purpose: 7944 * Clear prefix entry hit bit. 7945 * Parameters: 7946 * unit - (IN)SOC unit number. 7947 * key_data - (IN) LPM key_data. 7948 * Returns: 7949 * BCM_E_XXX 7950 */ 7951 STATIC int 7952 _bcm_td2_alpm_128_clear_hit(int u, void *key_data, int index, int flex) 7953 { 7954 soc_mem_t mem; 7955 uint32 e[SOC_MAX_MEM_FIELD_WORDS]; 7956 uint32 hit = 0; 7957 7958 mem = L3_DEFIP_ALPM_IPV6_128m; 7959 7960 BCM_IF_ERROR_RETURN( 7961 soc_mem_read_no_cache(u, 0, mem, 0, MEM_BLOCK_ANY, index, e)); 7962 if (SOC_MEM_FIELD_VALID(u, mem, HITf)) { 7963 hit = soc_mem_field32_get(u, mem, e, HITf); 7964 if (hit) { 7965 soc_mem_field32_set(u, mem, e, HITf, 0); 7966 BCM_IF_ERROR_RETURN(soc_mem_write(u, mem, MEM_BLOCK_ALL, index, e)); 7967 } 7968 } 7969 7970 return SOC_E_NONE; 7971 } 7972 7973 /* 7974 * Function: 7975 * _bcm_td2_alpm_clear_hit 7976 * Purpose: 7977 * Clear prefix entry hit bit. 7978 * Parameters: 7979 * unit - (IN)SOC unit number. 7980 * key_data - (IN) LPM key_data. 7981 * Returns: 7982 * BCM_E_XXX 7983 */ 7984 STATIC int 7985 _bcm_td2_alpm_clear_hit(int u, void *key_data, int index, int flex) 7986 { 7987 int ipv6; 7988 soc_mem_t mem; 7989 uint32 e[SOC_MAX_MEM_FIELD_WORDS]; 7990 uint32 hit = 0; 7991 7992 ipv6 = soc_mem_field32_get(u, L3_DEFIPm, key_data, MODE0_f(u)); 7993 7994 mem = (ipv6) ? (flex ? L3_DEFIP_ALPM_IPV6_64_1m : L3_DEFIP_ALPM_IPV6_64m) : 7995 (flex ? L3_DEFIP_ALPM_IPV4_1m : L3_DEFIP_ALPM_IPV4m); 7996 7997 BCM_IF_ERROR_RETURN( 7998 soc_mem_read_no_cache(u, 0, mem, 0, MEM_BLOCK_ANY, index, e)); 7999 if (SOC_MEM_FIELD_VALID(u, mem, HITf)) { 8000 hit = soc_mem_field32_get(u, mem, e, HITf); 8001 if (hit) { 8002 soc_mem_field32_set(u, mem, e, HITf, 0); 8003 BCM_IF_ERROR_RETURN(soc_mem_write(u, mem, MEM_BLOCK_ALL, index, e)); 8004 } 8005 } 8006 8007 return SOC_E_NONE; 8008 } 8009 8010 8011 /* 8012 * Function: 8013 * _bcm_td2_alpm_get 8014 * Purpose: 8015 * Get an entry from DEFIP table. 8016 * Parameters: 8017 * unit - (IN)SOC unit number. 8018 * lpm_cfg - (IN)Buffer to fill defip information. 8019 * nh_ecmp_idx - (IN)Next hop or ecmp group index 8020 * Returns: 8021 * BCM_E_XXX 8022 */ 8023 int 8024 _bcm_td2_alpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 8025 { 8026 defip_entry_t lpm_key; /* Route lookup key. */ 8027 defip_entry_t lpm_entry; /* Search result buffer. */ 8028 defip_pair_128_entry_t lpm_128_key; 8029 defip_pair_128_entry_t lpm_128_entry; 8030 int clear_hit; /* Clear hit indicator. */ 8031 int rv = 0; /* Operation return status. */ 8032 uint32 flags = 0; 8033 soc_mem_t mem; 8034 8035 /* Input parameters check */ 8036 if (NULL == lpm_cfg) { 8037 return (BCM_E_PARAM); 8038 } 8039 8040 /* Zero buffers. */ 8041 sal_memset(&lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 8042 sal_memset(&lpm_key, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 8043 sal_memset(&lpm_128_entry, 0, sizeof(lpm_128_entry)); 8044 sal_memset(&lpm_128_key, 0, sizeof(lpm_128_key)); 8045 8046 /* Check if clear hit bit required. */ 8047 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 8048 8049 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 8050 lpm_cfg->defip_sub_len, &mem)); 8051 switch (mem) { 8052 case L3_DEFIP_PAIR_128m: 8053 /* Initialize lkup key. */ 8054 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg, 8055 &lpm_128_key, 0, &flags)); 8056 /* Perform hw lookup. */ 8057 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 8058 rv = soc_alpm_128_lookup(unit, &lpm_128_key, &lpm_128_entry, 8059 &lpm_cfg->defip_index, &lpm_cfg->defip_alpm_cookie); 8060 } 8061 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 8062 else { 8063 rv = soc_th_alpm_128_lookup(unit, &lpm_128_key, &lpm_128_entry, 8064 &lpm_cfg->defip_index, &lpm_cfg->defip_alpm_cookie); 8065 } 8066 #endif 8067 8068 BCM_IF_ERROR_RETURN(rv); 8069 8070 /* Parse hw buffer to defip entry. */ 8071 _bcm_td2_alpm_lpm128_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_128_entry); 8072 8073 break; 8074 8075 default: 8076 /* Initialize lkup key. */ 8077 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_key, 0, 8078 &flags)); 8079 /* Perform hw lookup. */ 8080 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 8081 rv = soc_alpm_lookup(unit, &lpm_key, &lpm_entry, &lpm_cfg->defip_index, 8082 &lpm_cfg->defip_alpm_cookie); 8083 } 8084 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 8085 else { 8086 rv = soc_th_alpm_lookup(unit, &lpm_key, &lpm_entry, &lpm_cfg->defip_index, 8087 &lpm_cfg->defip_alpm_cookie); 8088 } 8089 #endif 8090 8091 BCM_IF_ERROR_RETURN(rv); 8092 8093 /* Parse hw buffer to defip entry. */ 8094 _bcm_td2_alpm_lpm_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_entry); 8095 break; 8096 } 8097 8098 /* Clear the HIT bit */ 8099 if (clear_hit && BCM_SUCCESS(rv)) { 8100 if (mem == L3_DEFIP_PAIR_128m) { 8101 BCM_IF_ERROR_RETURN( 8102 _bcm_td2_alpm_128_clear_hit(unit, &lpm_128_key, 8103 ALPM_ENT_INDEX(lpm_cfg->defip_index), 8104 flags & SOC_ALPM_STAT_FLEX)); 8105 } else { 8106 BCM_IF_ERROR_RETURN( 8107 _bcm_td2_alpm_clear_hit(unit, &lpm_key, 8108 ALPM_ENT_INDEX(lpm_cfg->defip_index), 8109 flags & SOC_ALPM_STAT_FLEX)); 8110 } 8111 } 8112 return (BCM_E_NONE); 8113 } 8114 8115 /* 8116 * Function: 8117 * _bcm_td2_alpm_add 8118 * Purpose: 8119 * Add an entry to DEFIP table. 8120 * Parameters: 8121 * unit - (IN)SOC unit number. 8122 * lpm_cfg - (IN)Buffer to fill defip information. 8123 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 8124 * Returns: 8125 * BCM_E_XXX 8126 */ 8127 int 8128 _bcm_td2_alpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 8129 { 8130 defip_entry_t lpm_entry; 8131 defip_pair_128_entry_t lpm_128_entry; 8132 int rv = 0; /* Operation return status. */ 8133 uint32 flags= 0; 8134 soc_mem_t mem; 8135 8136 /* Input parameters check */ 8137 if (NULL == lpm_cfg) { 8138 return (BCM_E_PARAM); 8139 } 8140 8141 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 8142 lpm_cfg->defip_sub_len, &mem)); 8143 switch (mem) { 8144 case L3_DEFIP_PAIR_128m: 8145 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg, 8146 &lpm_128_entry, nh_ecmp_idx, &flags)); 8147 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 8148 rv = soc_alpm_128_insert(unit, &lpm_128_entry, flags, 8149 lpm_cfg->defip_index, lpm_cfg->defip_alpm_cookie); 8150 } 8151 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 8152 else { 8153 rv = soc_th_alpm_128_insert(unit, &lpm_128_entry, flags, 8154 lpm_cfg->defip_index, lpm_cfg->defip_alpm_cookie); 8155 } 8156 #endif 8157 break; 8158 default: 8159 /* 8160 * Initialize hw buffer from lpm configuration. 8161 * NOTE: DON'T MOVE _bcm_fb_defip_ent_init CALL UP, 8162 * We want to copy flags & nh info, avoid ipv6 mask & address 8163 * corruption 8164 */ 8165 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_entry, 8166 nh_ecmp_idx, &flags)); 8167 8168 /* Write buffer to hw. */ 8169 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 8170 rv = soc_alpm_insert(unit, &lpm_entry, flags, lpm_cfg->defip_index, 8171 lpm_cfg->defip_alpm_cookie); 8172 } 8173 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 8174 else { 8175 rv = soc_th_alpm_insert(unit, &lpm_entry, flags, lpm_cfg->defip_index, 8176 lpm_cfg->defip_alpm_cookie); 8177 } 8178 #endif 8179 break; 8180 } 8181 8182 /* If new route added increment total number of routes. */ 8183 /* Lack of index indicates a new route. */ 8184 if ((rv >= 0) && !(lpm_cfg->defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT || 8185 lpm_cfg->defip_alpm_cookie & SOC_ALPM_LPM_LOOKUP_HIT)) { 8186 BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 8187 } 8188 return rv; 8189 } 8190 8191 /* 8192 * Function: 8193 * _bcm_fb_lpm_del 8194 * Purpose: 8195 * Delete an entry from DEFIP table. 8196 * Parameters: 8197 * unit - (IN)SOC unit number. 8198 * lpm_cfg - (IN)Buffer to fill defip information. 8199 * Returns: 8200 * BCM_E_XXX 8201 */ 8202 int 8203 _bcm_td2_alpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 8204 { 8205 int rv = 0; /* Operation return status. */ 8206 defip_entry_t lpm_entry; /* Search result buffer. */ 8207 defip_pair_128_entry_t lpm_128_entry; /* Search result buffer. */ 8208 uint32 flags; 8209 soc_mem_t mem; 8210 8211 /* Input parameters check */ 8212 if (NULL == lpm_cfg) { 8213 return (BCM_E_PARAM); 8214 } 8215 8216 /* Zero buffers. */ 8217 sal_memset(&lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 8218 sal_memset(&lpm_128_entry, 0, sizeof(lpm_128_entry)); 8219 8220 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 8221 lpm_cfg->defip_sub_len, &mem)); 8222 8223 switch (mem) { 8224 case L3_DEFIP_PAIR_128m: 8225 /* Initialize hw buffer deletion key. */ 8226 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg, 8227 &lpm_128_entry, 0, &flags)); 8228 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 8229 rv = soc_alpm_128_delete(unit, &lpm_128_entry, lpm_cfg->defip_index, 8230 lpm_cfg->defip_alpm_cookie); 8231 } 8232 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 8233 else { 8234 rv = soc_th_alpm_128_delete(unit, &lpm_128_entry, lpm_cfg->defip_index, 8235 lpm_cfg->defip_alpm_cookie); 8236 } 8237 #endif 8238 break; 8239 default: 8240 /* Initialize hw buffer deletion key. */ 8241 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_entry, 0, 8242 &flags)); 8243 /* Write buffer to hw. */ 8244 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) { 8245 rv = soc_alpm_delete(unit, &lpm_entry, lpm_cfg->defip_index, 8246 lpm_cfg->defip_alpm_cookie); 8247 } 8248 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 8249 else { 8250 rv = soc_th_alpm_delete(unit, &lpm_entry, lpm_cfg->defip_index, 8251 lpm_cfg->defip_alpm_cookie); 8252 } 8253 #endif 8254 break; 8255 } 8256 8257 /* If route deleted, decrement total number of routes. */ 8258 if (rv >= 0) { 8259 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6); 8260 } 8261 return rv; 8262 } 8263 8264 /* 8265 * Function: 8266 * _bcm_fb_mem_ip6_defip_get 8267 * Purpose: 8268 * Get IP6 address mask field in ALPM mem to defip_cfg 8269 * Note: 8270 * See soc_mem_ip6_addr_set() 8271 */ 8272 STATIC void 8273 _bcm_td2_alpm_ent64_key_parse(int unit, const void *alpm_key, soc_mem_t mem, 8274 _bcm_defip_cfg_t *lpm_cfg) 8275 { 8276 uint8 *ip6; /* Ip6 address. */ 8277 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 8278 uint32 ip6_word[2]; /* Temp storage. */ 8279 8280 sal_memset(mask, 0, sizeof (bcm_ip6_t)); 8281 8282 /* Just to keep variable name short. */ 8283 ip6 = lpm_cfg->defip_ip6_addr; 8284 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 8285 8286 soc_mem_field_get(unit, mem, alpm_key, KEYf, &ip6_word[0]); 8287 ip6[0] = (uint8) ((ip6_word[1] >> 24) & 0xff); 8288 ip6[1] = (uint8) ((ip6_word[1] >> 16) & 0xff); 8289 ip6[2] = (uint8) ((ip6_word[1] >> 8) & 0xff); 8290 ip6[3] = (uint8) (ip6_word[1] & 0xff); 8291 8292 ip6[4] = (uint8) ((ip6_word[0] >> 24) & 0xff); 8293 ip6[5] = (uint8) ((ip6_word[0] >> 16) & 0xff); 8294 ip6[6] = (uint8) ((ip6_word[0] >> 8) & 0xff); 8295 ip6[7] = (uint8) (ip6_word[0] & 0xff); 8296 8297 lpm_cfg->defip_sub_len = soc_mem_field32_get(unit, mem, alpm_key, LENGTHf); 8298 } 8299 8300 /* 8301 * Function: 8302 * _bcm_td2_alpm_ent_key_parse 8303 * Purpose: 8304 * Parse entry key from ALPM table. 8305 * Parameters: 8306 * unit - (IN) SOC unit number. 8307 * lpm_cfg - (OUT)Buffer to fill defip information. 8308 * *lpm_entry - (IN) Pointer to lpm buffer read from hw. 8309 * alpm_mem - (IN) ALPM memory type. 8310 * *alpm_entry - (IN) Pointer to alpm entry read from SRAM bank. 8311 * Returns: 8312 * void 8313 */ 8314 STATIC void 8315 _bcm_td2_alpm_ent_key_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 8316 defip_entry_t *lpm_entry, soc_mem_t alpm_mem, 8317 void *alpm_entry) 8318 { 8319 bcm_ip_t v4_mask; 8320 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 8321 8322 /* Set prefix ip address & mask. */ 8323 if (ipv6) { 8324 _bcm_td2_alpm_ent64_key_parse(unit, alpm_entry, alpm_mem, lpm_cfg); 8325 } else { 8326 /* Get ipv4 address. */ 8327 lpm_cfg->defip_ip_addr = soc_mem_field32_get(unit, alpm_mem, 8328 alpm_entry, KEYf); 8329 8330 /* Get subnet mask. */ 8331 v4_mask = soc_mem_field32_get(unit, alpm_mem, alpm_entry, LENGTHf); 8332 if (v4_mask) { 8333 v4_mask = ~((1 << (32 - v4_mask)) - 1); 8334 } 8335 8336 /* Fill mask length. */ 8337 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 8338 } 8339 8340 /* Get Virtual Router id */ 8341 soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf, NULL); 8342 return; 8343 } 8344 8345 /* 8346 * Function: 8347 * _bcm_td2_alpm_ent_data_parse 8348 * Purpose: 8349 * Parse an entry from DEFIP table. 8350 * Parameters: 8351 * unit - (IN)SOC unit number. 8352 * lpm_cfg - (OUT)Buffer to fill defip information. 8353 * nh_ecmp_idx - (OUT)Next hop index or ecmp group id. 8354 * alpm_entry - (IN) Buffer read from hw. 8355 * Returns: 8356 * void 8357 */ 8358 STATIC void 8359 _bcm_td2_alpm_ent_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx, 8360 soc_mem_t alpm_mem, void *alpm_entry) 8361 { 8362 8363 int is_ecmp = 0; 8364 uint32 nh_ecmp_idx = 0; 8365 8366 /* Check if entry points to ecmp group. */ 8367 if (soc_feature(unit, soc_feature_generic_dest)) { 8368 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 8369 nh_ecmp_idx = soc_mem_field32_dest_get(unit, alpm_mem, alpm_entry, 8370 DESTINATIONf, &dest_type); 8371 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 8372 is_ecmp = 1; 8373 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 8374 nh_ecmp_idx = 0; 8375 } 8376 } else if (!(SOC_IS_HURRICANEX(unit))) { 8377 is_ecmp = soc_mem_field32_get(unit, alpm_mem, alpm_entry, ECMPf); 8378 if (is_ecmp) { 8379 nh_ecmp_idx = soc_mem_field32_get(unit, alpm_mem, alpm_entry, ECMP_PTRf); 8380 } else { 8381 nh_ecmp_idx = soc_mem_field32_get(unit, alpm_mem, alpm_entry, NEXT_HOP_INDEXf); 8382 } 8383 } else { 8384 nh_ecmp_idx = soc_mem_field32_get(unit, alpm_mem, alpm_entry, NEXT_HOP_INDEXf); 8385 } 8386 8387 /* Reset entry flags first. */ 8388 lpm_cfg->defip_flags = 0; 8389 8390 /* Check if entry points to ecmp group. */ 8391 /* hurricane does not have ecmp flag*/ 8392 if ((!(SOC_IS_HURRICANEX(unit))) && is_ecmp) { 8393 /* Mark entry as ecmp */ 8394 lpm_cfg->defip_ecmp = 1; 8395 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 8396 8397 /* Get ecmp group id. */ 8398 if (p_nh_ecmp_idx) { 8399 *p_nh_ecmp_idx = nh_ecmp_idx; 8400 } 8401 } else { 8402 /* Mark entry as non-ecmp. */ 8403 lpm_cfg->defip_ecmp = 0; 8404 8405 /* Reset ecmp group next hop count. */ 8406 lpm_cfg->defip_ecmp_count = 0; 8407 8408 /* Get next hop index. */ 8409 if (p_nh_ecmp_idx) { 8410 *p_nh_ecmp_idx = nh_ecmp_idx; 8411 } 8412 } 8413 /* Get entry priority. */ 8414 lpm_cfg->defip_prio = soc_mem_field32_get(unit, alpm_mem, alpm_entry, 8415 PRIf); 8416 8417 /* Get hit bit. */ 8418 if (!ALPM_CTRL(unit).hit_bits_skip && 8419 soc_mem_field32_get(unit, alpm_mem, alpm_entry, HITf)) { 8420 lpm_cfg->defip_flags |= BCM_L3_HIT; 8421 } 8422 8423 /* Get priority override bit. */ 8424 if (soc_mem_field32_get(unit, alpm_mem, alpm_entry, RPEf)) { 8425 lpm_cfg->defip_flags |= BCM_L3_RPE; 8426 } 8427 8428 /* Get destination discard flag. */ 8429 if (SOC_MEM_FIELD_VALID(unit, alpm_mem, DST_DISCARDf)) { 8430 if(soc_mem_field32_get(unit, alpm_mem, alpm_entry, DST_DISCARDf)) { 8431 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 8432 } 8433 } 8434 8435 /* Set classification group id. */ 8436 lpm_cfg->defip_lookup_class = soc_mem_field32_get(unit, alpm_mem, 8437 alpm_entry, CLASS_IDf); 8438 8439 if (alpm_mem == L3_DEFIP_ALPM_IPV6_64m || 8440 alpm_mem == L3_DEFIP_ALPM_IPV6_64_1m || 8441 alpm_mem == L3_DEFIP_ALPM_IPV6_128m) { 8442 lpm_cfg->defip_flags |= BCM_L3_IP6; 8443 } 8444 return; 8445 } 8446 8447 STATIC int 8448 _bcm_td2_alpm_ent128_key_parse(int unit, soc_mem_t mem, uint32 *alpm_entry, 8449 _bcm_defip_cfg_t *lpm_cfg) 8450 { 8451 uint32 ip6_word[4]; 8452 8453 uint8 *ip6; 8454 8455 ip6 = lpm_cfg->defip_ip6_addr; 8456 8457 soc_mem_field_get(unit, mem, alpm_entry, KEYf, ip6_word); 8458 ip6[0] = (ip6_word[3] >> 24); 8459 ip6[1] = (ip6_word[3] >> 16) & 0xff; 8460 ip6[2] = (ip6_word[3] >> 8) & 0xff; 8461 ip6[3] = ip6_word[3]; 8462 8463 ip6[4] = ip6_word[2] >> 24; 8464 ip6[5] = (ip6_word[2] >> 16) & 0xff; 8465 ip6[6] = (ip6_word[2] >> 8) & 0xff; 8466 ip6[7] = ip6_word[2]; 8467 8468 ip6[8] = ip6_word[1] >> 24; 8469 ip6[9] = (ip6_word[1] >> 16) & 0xff; 8470 ip6[10] = (ip6_word[1] >> 8) & 0xff; 8471 ip6[11] = ip6_word[1]; 8472 8473 ip6[12] = ip6_word[0] >> 24; 8474 ip6[13] = (ip6_word[0] >> 16) & 0xff; 8475 ip6[14] = (ip6_word[0] >> 8) & 0xff; 8476 ip6[15] = ip6_word[0]; 8477 8478 lpm_cfg->defip_sub_len = 8479 soc_mem_field32_get(unit, mem, alpm_entry, LENGTHf); 8480 8481 return SOC_E_NONE; 8482 } 8483 8484 STATIC int 8485 _bcm_td2_alpm_ent128_data_parse(int unit, soc_mem_t mem, uint32 *hw_entry, 8486 _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx) 8487 { 8488 int is_ecmp = 0; 8489 uint32 nh_ecmp_idx = 0; 8490 8491 /* Input parameters check. */ 8492 if ((lpm_cfg == NULL) || (hw_entry == NULL)) { 8493 return (BCM_E_PARAM); 8494 } 8495 8496 /* Check if entry points to ecmp group. */ 8497 if (soc_feature(unit, soc_feature_generic_dest)) { 8498 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 8499 nh_ecmp_idx = soc_mem_field32_dest_get(unit, mem, hw_entry, 8500 DESTINATIONf, &dest_type); 8501 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 8502 is_ecmp = 1; 8503 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 8504 nh_ecmp_idx = 0; 8505 } 8506 } else { 8507 is_ecmp = soc_mem_field32_get(unit, mem, hw_entry, ECMPf); 8508 if (is_ecmp) { 8509 nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, ECMP_PTRf); 8510 } else { 8511 nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, NEXT_HOP_INDEXf); 8512 } 8513 } 8514 8515 /* Reset entry flags first. */ 8516 lpm_cfg->defip_flags = 0; 8517 8518 /* Check if entry points to ecmp group. */ 8519 if (is_ecmp) { 8520 /* Mark entry as ecmp */ 8521 lpm_cfg->defip_ecmp = TRUE; 8522 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 8523 8524 /* Get ecmp group id. */ 8525 if (p_nh_ecmp_idx != NULL) { 8526 *p_nh_ecmp_idx = nh_ecmp_idx; 8527 } 8528 } else { 8529 /* Mark entry as non-ecmp. */ 8530 lpm_cfg->defip_ecmp = 0; 8531 8532 /* Reset ecmp group next hop count. */ 8533 lpm_cfg->defip_ecmp_count = 0; 8534 8535 /* Get next hop index. */ 8536 if (p_nh_ecmp_idx != NULL) { 8537 *p_nh_ecmp_idx = nh_ecmp_idx; 8538 } 8539 } 8540 8541 /* Mark entry as IPv6 */ 8542 lpm_cfg->defip_flags |= BCM_L3_IP6; 8543 8544 /* Get entry priority. */ 8545 lpm_cfg->defip_prio = soc_mem_field32_get(unit, mem, hw_entry, PRIf); 8546 8547 /* Get classification group id. */ 8548 lpm_cfg->defip_lookup_class = 8549 soc_mem_field32_get(unit, mem, hw_entry, CLASS_IDf); 8550 8551 /* Get hit bit. */ 8552 if (!ALPM_CTRL(unit).hit_bits_skip && 8553 soc_mem_field32_get(unit, mem, hw_entry, HITf)) { 8554 lpm_cfg->defip_flags |= BCM_L3_HIT; 8555 } 8556 8557 /* Get priority override bit. */ 8558 if (soc_mem_field32_get(unit, mem, hw_entry, RPEf)) { 8559 lpm_cfg->defip_flags |= BCM_L3_RPE; 8560 } 8561 8562 /* Get destination discard field. */ 8563 if(soc_mem_field32_get(unit, mem, hw_entry, DST_DISCARDf)) { 8564 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 8565 } 8566 8567 return (BCM_E_NONE); 8568 } 8569 8570 /* 8571 * Function: 8572 * _bcm_td2_alpm_warmboot_walk 8573 * Purpose: 8574 * Recover LPM and ALPM entries 8575 * Parameters: 8576 * unit - (IN)SOC unit number. 8577 * trv_data - (IN)pattern + compare,act,notify routines. 8578 * Returns: 8579 * BCM_E_XXX 8580 */ 8581 int 8582 _bcm_td2_alpm_warmboot_walk(int unit, _bcm_l3_trvrs_data_t *trv_data) 8583 { 8584 int ipv6; /* IPv6 flag. */ 8585 int idx; /* Iteration index. */ 8586 int tmp_idx; /* IPv4 entries iterator. */ 8587 int vrf_id; /* */ 8588 int vrf; /* */ 8589 int idx_end; /* */ 8590 int bkt_addr; /* */ 8591 int bkt_count; /* */ 8592 int bkt_idx = 0; /* */ 8593 int bkt_ptr = 0; /* Bucket pointer */ 8594 int bank_num = 0; /* Number of active SRAM banks */ 8595 int pivot_idx = 0; /* Pivot Index */ 8596 int entry_num = 0; /* ALPM entry number in bucket */ 8597 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 8598 int entry_count; /* ALPM entry count in bucket */ 8599 int bank_count; /* SRAM bank count */ 8600 int step_count; /* */ 8601 int cmp_result; /* Test routine result. */ 8602 int rv = BCM_E_FAIL; /* Operation return status. */ 8603 int defip_table_size = 0; /* Defip table size. */ 8604 char *lpm_tbl_ptr = NULL; /* DMA table pointer. */ 8605 void *alpm_entry = NULL; /* */ 8606 soc_mem_t alpm_mem; /* */ 8607 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 8608 defip_entry_t *lpm_entry; /* Hw entry buffer. */ 8609 defip_alpm_ipv4_1_entry_t alpm_entry_v4; 8610 defip_alpm_ipv6_64_1_entry_t alpm_entry_v6_64; 8611 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 8612 int ipmc_route = 0; /* Route is ip multicast type */ 8613 #endif 8614 int flex; 8615 int bkt_ptr_tmp = 0; 8616 uint8 bkt_occupied = 0; 8617 8618 /* DMA LPM table to software copy */ 8619 BCM_IF_ERROR_RETURN 8620 (bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 8621 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 8622 &lpm_tbl_ptr, &defip_table_size)); 8623 8624 if (SOC_URPF_STATUS_GET(unit)) { 8625 defip_table_size >>= 1; 8626 } 8627 8628 idx_end = defip_table_size; 8629 bank_count = 4; 8630 8631 /* Walk all lpm entries */ 8632 for (idx = 0; idx < idx_end; idx++) { 8633 /* Calculate entry ofset */ 8634 lpm_entry = 8635 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 8636 defip_entry_t *, lpm_tbl_ptr, idx); 8637 8638 ipv6 = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit)); 8639 8640 /* Calculate LPM table traverse step count */ 8641 if (ipv6) { 8642 if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) { 8643 step_count = 2; 8644 } else { 8645 step_count = 1; 8646 } 8647 } else { 8648 step_count = 2; 8649 } 8650 8651 /* Insert LPM entry into HASH table and init LPM trackers */ 8652 if (BCM_FAILURE(soc_alpm_warmboot_lpm_reinit(unit, ipv6, 8653 idx, lpm_entry))) { 8654 goto free_lpm_table; 8655 } 8656 8657 bkt_occupied = 0; 8658 8659 /* 8660 * This loop is used for two purposes 8661 * 1. IPv4, DEFIP entry has two IPv4 entries. 8662 * 2. IPv6 double wide mode, walk next bucket. 8663 */ 8664 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 8665 if (tmp_idx) { /* If index == 1*/ 8666 if (!ipv6) { 8667 /* Copy upper half of lpm entry to lower half */ 8668 soc_alpm_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE); 8669 8670 /* Invalidate upper half */ 8671 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 0); 8672 } 8673 } 8674 8675 /* Make sure entry is valid. */ 8676 if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) { 8677 continue; 8678 } 8679 8680 if (ipv6 && tmp_idx) { 8681 /* 8682 * IPv6 double wide mode, Walk bucket entries at next bucket. 8683 */ 8684 bkt_ptr++; 8685 } else { 8686 /* Extract bucket pointer from LPM entry */ 8687 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 8688 ALG_BKT_PTR0f); 8689 bkt_ptr_tmp = bkt_ptr; 8690 8691 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 8692 if (soc_feature(unit, soc_feature_ipmc_defip)) { 8693 /* Skip reserved ipmc entry */ 8694 int ipmc_index = 0; 8695 ipmc_route = 0; 8696 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 8697 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 8698 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 8699 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 8700 ipmc_route = 1; 8701 } else { 8702 ipmc_route = 0; 8703 } 8704 } 8705 8706 if (soc_feature(unit, soc_feature_generic_dest)) { 8707 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 8708 uint32 dest_value = 0; 8709 dest_value = soc_mem_field32_dest_get(unit, 8710 L3_DEFIPm, lpm_entry, 8711 DESTINATION0f, &dest_type); 8712 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 8713 ipmc_index = dest_value; 8714 } else { 8715 ipmc_index = 0; 8716 } 8717 } else { 8718 ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm, 8719 lpm_entry, L3MC_INDEX0f); 8720 } 8721 8722 if (ipmc_route && ipmc_index == 0) { 8723 continue; 8724 } 8725 } 8726 #endif 8727 /* Extract VRF from LPM entry*/ 8728 if (BCM_FAILURE(soc_alpm_lpm_vrf_get 8729 (unit, lpm_entry, &vrf_id, &vrf))) { 8730 goto free_lpm_table; 8731 } 8732 8733 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 8734 * resides in TCAM */ 8735 if (bkt_ptr == 0) { 8736 VRF_TRIE_ROUTES_INC(unit, vrf_id, vrf, ipv6); 8737 8738 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 8739 _bcm_td2_alpm_lpm_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 8740 lpm_entry); 8741 _bcm_td2_alpm_lpm_key_parse(unit, &lpm_cfg, lpm_entry); 8742 lpm_cfg.defip_index = idx; 8743 8744 if (ipv6 == (lpm_cfg.defip_flags & BCM_L3_IP6)) { 8745 if (trv_data->op_cb) { 8746 (void) (*trv_data->op_cb)(unit, (void *)trv_data, 8747 (void *)&lpm_cfg, 8748 (void *)&nh_ecmp_idx, 8749 &cmp_result); 8750 } 8751 } 8752 if (ipv6) { 8753 tmp_idx++; 8754 } 8755 continue; 8756 } 8757 8758 pivot_idx = (idx << 1) + tmp_idx; 8759 8760 /* TCAM pivot recovery */ 8761 if(BCM_FAILURE(soc_alpm_warmboot_pivot_add(unit, ipv6, lpm_entry, pivot_idx, 8762 bkt_ptr))) { 8763 goto free_lpm_table; 8764 } 8765 8766 /* Set bucket bitmap */ 8767 if(BCM_FAILURE(soc_alpm_warmboot_bucket_bitmap_set(unit, ipv6, bkt_ptr))) { 8768 goto free_lpm_table; 8769 } 8770 } 8771 8772 flex = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f); 8773 if (ipv6) { 8774 if (flex) { 8775 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m; 8776 bkt_count = ALPM_IPV6_64_BKT_COUNT_FLEX; 8777 entry_count = 3; 8778 alpm_entry = &alpm_entry_v6_64; 8779 } else { 8780 alpm_mem = L3_DEFIP_ALPM_IPV6_64m; 8781 bkt_count = ALPM_IPV6_64_BKT_COUNT; 8782 entry_count = 4; 8783 alpm_entry = &alpm_entry_v6_64; 8784 } 8785 } else { 8786 if (flex) { 8787 alpm_mem = L3_DEFIP_ALPM_IPV4_1m; 8788 bkt_count = ALPM_IPV4_BKT_COUNT_FLEX; 8789 entry_count = 4; 8790 alpm_entry = &alpm_entry_v4; 8791 } else { 8792 alpm_mem = L3_DEFIP_ALPM_IPV4m; 8793 bkt_count = ALPM_IPV4_BKT_COUNT; 8794 entry_count = 6; 8795 alpm_entry = &alpm_entry_v4; 8796 } 8797 } 8798 8799 entry_num = 0; 8800 bank_num = 0; 8801 8802 /* Get the bucket pointer from lpm entry */ 8803 for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) { 8804 /* Calculate bucket memory address */ 8805 /* Increment so next bucket address can be calculated */ 8806 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 8807 (bank_num & 0x3); 8808 entry_num++; 8809 if (entry_num == entry_count) { 8810 entry_num = 0; 8811 bank_num++; 8812 if (bank_num == bank_count) { 8813 bank_num = 0; 8814 } 8815 } 8816 8817 /* Read entry from bucket memory */ 8818 if (BCM_FAILURE(soc_mem_read(unit, alpm_mem, MEM_BLOCK_ANY, 8819 bkt_addr, alpm_entry))) { 8820 goto free_lpm_table; 8821 } 8822 8823 /* Check if ALPM entry is valid */ 8824 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 8825 continue; 8826 } 8827 8828 bkt_occupied = 1; 8829 8830 /* Zero destination buffer first. */ 8831 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 8832 8833 /* Parse the entry. */ 8834 _bcm_td2_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 8835 alpm_mem, alpm_entry); 8836 8837 /* Execute operation routine if any. */ 8838 if (trv_data->op_cb) { 8839 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 8840 (void *)&lpm_cfg, 8841 (void *)&nh_ecmp_idx, &cmp_result); 8842 #ifdef BCM_CB_ABORT_ON_ERR 8843 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 8844 continue; 8845 } 8846 #endif 8847 } 8848 8849 if(BCM_FAILURE(soc_alpm_warmboot_prefix_insert(unit, ipv6, flex, lpm_entry, 8850 alpm_entry, pivot_idx, bkt_ptr, bkt_addr))) { 8851 continue; 8852 } 8853 8854 } /* End of bucket walk loop*/ 8855 if (bkt_occupied) { 8856 /* If ipv6 double wide, two alpm bkt views should be set */ 8857 if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) { 8858 _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 8859 _soc_trident2_alpm_bkt_view_set(unit, (bkt_ptr_tmp + 1) << 2, alpm_mem); 8860 } else { 8861 _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 8862 } 8863 } 8864 } /* End of lpm entry upper/lower half traversal */ 8865 } /* End of lpm table traversal */ 8866 8867 if(BCM_FAILURE(soc_alpm_warmboot_lpm_reinit_done(unit))) { 8868 goto free_lpm_table; 8869 } 8870 8871 #ifdef ALPM_WARM_BOOT_DEBUG 8872 soc_alpm_lpm_sw_dump(unit); 8873 #endif /* ALPM_WARM_BOOT_DEBUG */ 8874 8875 rv = BCM_E_NONE; 8876 free_lpm_table: 8877 soc_cm_sfree(unit, lpm_tbl_ptr); 8878 8879 return (rv); 8880 } 8881 8882 /* 8883 * Function: 8884 * _bcm_td2_alpm_128_warmboot_walk 8885 * Purpose: 8886 * Recover IPv6-128Bit LPM and ALPM entries 8887 * Parameters: 8888 * unit - (IN)SOC unit number. 8889 * trv_data - (IN)pattern + compare,act,notify routines. 8890 * Returns: 8891 * BCM_E_XXX 8892 */ 8893 int 8894 _bcm_td2_alpm_128_warmboot_walk(int unit, _bcm_l3_trvrs_data_t *trv_data) 8895 { 8896 int ipv6 = 2; /* IPv6 flag. */ 8897 int idx; /* Iteration index. */ 8898 int tmp_idx; /* IPv4 entries iterator. */ 8899 int vrf, vrf_id; /* */ 8900 int idx_end; /* */ 8901 int bkt_addr; /* */ 8902 int bkt_count; /* */ 8903 int bkt_idx = 0; /* */ 8904 int bkt_ptr = 0; /* Bucket pointer */ 8905 int bank_num = 0; /* Number of active SRAM banks */ 8906 int entry_num = 0; /* ALPM entry number in bucket */ 8907 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 8908 int entry_count; /* ALPM entry count in bucket */ 8909 int bank_count; /* SRAM bank count */ 8910 int step_count; /* */ 8911 int cmp_result; /* Test routine result. */ 8912 int rv = BCM_E_FAIL; /* Operation return status. */ 8913 int defip_table_size = 0; /* Defip table size. */ 8914 char *lpm_tbl_ptr = NULL; /* DMA table pointer. */ 8915 void *alpm_entry = NULL; /* */ 8916 uint32 rval; /* */ 8917 soc_mem_t alpm_mem; /* */ 8918 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 8919 defip_pair_128_entry_t *lpm_entry; /* Hw entry buffer. */ 8920 defip_alpm_ipv6_128_entry_t alpm_entry_v6_128; /* ALPM 128 */ 8921 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 8922 int ipmc_route = 0; /* Route is ip multicast type */ 8923 #endif 8924 int bkt_ptr_tmp = 0; 8925 uint8 bkt_occupied = 0; 8926 8927 /* DMA LPM table to software copy */ 8928 BCM_IF_ERROR_RETURN 8929 (bcm_xgs3_l3_tbl_dma(unit, L3_DEFIP_PAIR_128m, 8930 WORDS2BYTES(soc_mem_entry_words(unit, L3_DEFIP_PAIR_128m)), 8931 "lpm_128_warmboot_tbl", 8932 &lpm_tbl_ptr, &defip_table_size)); 8933 8934 if(BCM_FAILURE(READ_L3_DEFIP_RPF_CONTROLr(unit, &rval))) { 8935 goto free_lpm_table; 8936 } 8937 8938 if (SOC_URPF_STATUS_GET(unit)) { 8939 defip_table_size >>= 1; 8940 } 8941 8942 idx_end = defip_table_size; 8943 alpm_mem = L3_DEFIP_ALPM_IPV6_128m; 8944 alpm_entry = &alpm_entry_v6_128; 8945 bkt_count = ALPM_IPV6_128_BKT_COUNT; 8946 entry_count = 2; 8947 bank_count = 4; 8948 8949 if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) { 8950 step_count = 2; 8951 } else { 8952 step_count = 1; 8953 } 8954 8955 /* Walk all lpm entries */ 8956 for (idx = 0; idx < idx_end; idx++) { 8957 /* Calculate entry ofset */ 8958 lpm_entry = 8959 soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 8960 defip_pair_128_entry_t *, lpm_tbl_ptr, idx); 8961 8962 /* Verify if read LPM entry is IPv6-128 entry */ 8963 if (0x03 != soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 8964 MODE1_UPR_f(unit))) { 8965 continue; 8966 }; 8967 8968 /* Verify if LPM entry is valid */ 8969 if (!soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 8970 VALID1_LWRf) || 8971 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 8972 VALID0_LWRf) || 8973 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 8974 VALID1_UPRf) || 8975 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 8976 VALID0_UPRf)) { 8977 continue; 8978 }; 8979 8980 /* Insert LPM entry into HASH table and init LPM trackers */ 8981 if (BCM_FAILURE(soc_alpm_128_warmboot_lpm_reinit(unit, ipv6, 8982 idx, lpm_entry))) { 8983 goto free_lpm_table; 8984 } 8985 8986 bkt_occupied = 0; 8987 8988 /* If IPv6 double wide mode, walk next bucket.*/ 8989 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 8990 8991 if (tmp_idx) { 8992 /* IPv6 double wide mode, Walk bucket entries at next bucket.*/ 8993 bkt_ptr++; 8994 } else { 8995 /* Extract bucket pointer from LPM entry */ 8996 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 8997 ALG_BKT_PTRf); 8998 bkt_ptr_tmp = bkt_ptr; 8999 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 9000 if (soc_feature(unit, soc_feature_ipmc_defip)) { 9001 /* Skip reserved ipmc entry */ 9002 int ipmc_index = 0; 9003 ipmc_route = 0; 9004 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 9005 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 9006 lpm_entry, MULTICAST_ROUTEf); 9007 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 9008 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 9009 lpm_entry, DATA_TYPEf) == 2) { 9010 ipmc_route = 1; 9011 } else { 9012 ipmc_route = 0; 9013 } 9014 } 9015 9016 if (soc_feature(unit, soc_feature_generic_dest)) { 9017 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 9018 uint32 dest_value = 0; 9019 dest_value = soc_mem_field32_dest_get(unit, 9020 L3_DEFIP_PAIR_128m, lpm_entry, 9021 DESTINATIONf, &dest_type); 9022 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 9023 ipmc_index = dest_value; 9024 } else { 9025 ipmc_index = 0; 9026 } 9027 } else { 9028 ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 9029 lpm_entry, L3MC_INDEXf); 9030 } 9031 9032 if ((ipmc_route) && (ipmc_index == 0)) { 9033 continue; 9034 } 9035 } 9036 #endif 9037 9038 /* Extract VRF from LPM entry*/ 9039 if (BCM_FAILURE(soc_alpm_128_lpm_vrf_get 9040 (unit, lpm_entry, &vrf_id, &vrf))) { 9041 goto free_lpm_table; 9042 } 9043 9044 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix resides in TCAM */ 9045 if (bkt_ptr == 0) { 9046 VRF_TRIE_ROUTES_INC(unit, vrf_id, vrf, ipv6); 9047 9048 /* TCAM Routes Processing */ 9049 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9050 (void) _bcm_td2_alpm_lpm128_key_parse(unit, (uint32 *) lpm_entry, 9051 &lpm_cfg); 9052 (void) soc_alpm_128_lpm_vrf_get(unit, lpm_entry, 9053 &lpm_cfg.defip_vrf, 9054 &nh_ecmp_idx); 9055 (void) _bcm_td2_alpm_lpm128_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry); 9056 9057 lpm_cfg.defip_index = idx; 9058 if (trv_data->op_cb) { 9059 (void) (*trv_data->op_cb)(unit, (void *)trv_data, 9060 (void *)&lpm_cfg, 9061 (void *)&nh_ecmp_idx, 9062 &cmp_result); 9063 } 9064 tmp_idx++; 9065 continue; 9066 } 9067 9068 /* TCAM pivot recovery */ 9069 if(BCM_FAILURE(soc_alpm_128_warmboot_pivot_add(unit, ipv6, 9070 lpm_entry, idx, bkt_ptr))) { 9071 goto free_lpm_table; 9072 } 9073 9074 /* Set bucket bitmap */ 9075 if(BCM_FAILURE(soc_alpm_128_warmboot_bucket_bitmap_set(unit, ipv6, 9076 bkt_ptr))) { 9077 goto free_lpm_table; 9078 } 9079 } 9080 9081 /* Get the bucket pointer from lpm entry */ 9082 for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) { 9083 /* Calculate bucket memory address */ 9084 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 9085 (bank_num & 0x3); 9086 entry_num++; 9087 9088 if (entry_num == entry_count) { 9089 entry_num = 0; 9090 bank_num++; 9091 if (bank_num == bank_count) { 9092 bank_num = 0; 9093 } 9094 } 9095 9096 /* Read entry from bucket memory */ 9097 if (BCM_FAILURE(soc_mem_read(unit, alpm_mem, MEM_BLOCK_ANY, 9098 bkt_addr, alpm_entry))) { 9099 goto free_lpm_table; 9100 } 9101 9102 /* Check if ALPM entry is valid */ 9103 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 9104 continue; 9105 } 9106 9107 bkt_occupied = 1; 9108 9109 /* Zero destination buffer first. */ 9110 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9111 9112 /* Fill entry IP address and subnet mask. */ 9113 _bcm_td2_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, &lpm_cfg); 9114 soc_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, &vrf); 9115 /* Parse the entry. */ 9116 _bcm_td2_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, 9117 &lpm_cfg, &nh_ecmp_idx); 9118 9119 /* Execute operation routine if any. */ 9120 if (trv_data->op_cb) { 9121 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9122 (void *)&lpm_cfg, 9123 (void *)&nh_ecmp_idx, &cmp_result); 9124 #ifdef BCM_CB_ABORT_ON_ERR 9125 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9126 continue; 9127 } 9128 #endif 9129 } 9130 9131 if(BCM_FAILURE(soc_alpm_128_warmboot_prefix_insert(unit, ipv6, lpm_entry, 9132 alpm_entry, idx, bkt_ptr, bkt_addr))) { 9133 continue; 9134 } 9135 9136 } /* End of bucket walk loop*/ 9137 if (bkt_occupied) { 9138 /* If IPV6 double wide, two alpm bkt views should be set */ 9139 if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) { 9140 _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 9141 _soc_trident2_alpm_bkt_view_set(unit, (bkt_ptr_tmp + 1) << 2, alpm_mem); 9142 } else { 9143 _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 9144 } 9145 } 9146 } /* End of lpm entry upper/lower half traversal */ 9147 } /* End of lpm table traversal */ 9148 9149 if(BCM_FAILURE(soc_alpm_128_warmboot_lpm_reinit_done(unit))) { 9150 goto free_lpm_table; 9151 } 9152 9153 #ifdef ALPM_WARM_BOOT_DEBUG 9154 soc_alpm_lpm_sw_dump(unit); 9155 #endif /* ALPM_WARM_BOOT_DEBUG */ 9156 9157 rv = BCM_E_NONE; 9158 free_lpm_table: 9159 soc_cm_sfree(unit, lpm_tbl_ptr); 9160 9161 return (rv); 9162 } 9163 9164 STATIC int 9165 _bcm_td2_alpm_128_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 9166 { 9167 uint32 ipv6; /* Iterate over ipv6 only flag. */ 9168 int idx; /* Iteration index. */ 9169 int phy_idx; /* Iteration index. */ 9170 int tmp_idx; /* ipv4 entries iterator. */ 9171 char *lpm_tbl_ptr = NULL; /* Dma table pointer. */ 9172 char *alpm_tbl_ptr = NULL; /* Dma table pointer. */ 9173 char *alpm_hit_tbl_ptr = NULL; /* Dma hit only table pointer. */ 9174 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 9175 int cmp_result; /* Test routine result. */ 9176 defip_pair_128_entry_t *lpm_entry = NULL; /* Hw entry buffer. */ 9177 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 9178 int defip_table_size; /* Defip table size. */ 9179 int rv = BCM_E_NONE; /* Operation return status. */ 9180 int idx_start = 0; 9181 int idx_end = 0, bkt_idx, bkt_count, bkt_ptr = 0, bkt_addr; 9182 int entry_num, bank_num, entry_count, bank_count; 9183 defip_alpm_ipv6_128_entry_t alpm_entry_v6_128; 9184 void *alpm_entry; 9185 void *raw_entry ; 9186 soc_mem_t alpm_mem, pivot_mem = L3_DEFIP_PAIR_128m; 9187 void *hit_entry; 9188 soc_mem_t alpm_hit_mem; 9189 int step_count; 9190 int def_arr_idx = 0; 9191 int def_rte_arr_sz; 9192 typedef struct _alpm_def_route_info_s { 9193 int idx; 9194 int bkt_addr; 9195 } _alpm_def_route_info_t; 9196 _alpm_def_route_info_t *def_rte_arr = NULL; 9197 9198 ipv6 = (trv_data->flags & BCM_L3_IP6); 9199 if (!ipv6) { 9200 return SOC_E_NONE; 9201 } 9202 9203 /* Table DMA the LPM table to software copy */ 9204 alpm_mem = L3_DEFIP_ALPM_RAWm; 9205 9206 rv = bcm_xgs3_l3_tbl_dma(unit, alpm_mem, 9207 WORDS2BYTES(soc_mem_entry_words(unit, alpm_mem)), 9208 "alpm_tbl", &alpm_tbl_ptr, NULL); 9209 alpm_mem = L3_DEFIP_ALPM_IPV6_128m; 9210 if (BCM_FAILURE(rv)) { 9211 goto error; 9212 } 9213 9214 rv = bcm_xgs3_l3_tbl_dma(unit, L3_DEFIP_PAIR_128m, 9215 WORDS2BYTES(soc_mem_entry_words(unit, L3_DEFIP_PAIR_128m)), 9216 "lpm_128_tbl", &lpm_tbl_ptr, &defip_table_size); 9217 if (BCM_FAILURE(rv)) { 9218 goto error; 9219 } 9220 9221 if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) { 9222 alpm_hit_mem = L3_DEFIP_ALPM_HIT_ONLYm; 9223 rv = bcm_xgs3_l3_tbl_dma(unit, alpm_hit_mem, 9224 WORDS2BYTES(soc_mem_entry_words(unit, alpm_hit_mem)), 9225 "alpm_hit_tbl", &alpm_hit_tbl_ptr, NULL); 9226 if (BCM_FAILURE(rv)) { 9227 goto error; 9228 } 9229 } 9230 9231 /* Allocate memory to store default route meta data*/ 9232 def_rte_arr_sz = SOC_VRF_MAX(unit) * sizeof(_alpm_def_route_info_t); 9233 def_rte_arr = sal_alloc(def_rte_arr_sz, "alpm_def_rte_arry"); 9234 if (NULL == def_rte_arr) { 9235 rv = BCM_E_MEMORY; 9236 goto error; 9237 } 9238 sal_memset(def_rte_arr, 0, def_rte_arr_sz); 9239 9240 if (SOC_URPF_STATUS_GET(unit)) { 9241 defip_table_size >>= 1; 9242 } 9243 9244 idx_end = defip_table_size; 9245 alpm_mem = L3_DEFIP_ALPM_IPV6_128m; 9246 bkt_count = ALPM_IPV6_128_BKT_COUNT; 9247 idx_start = 0; 9248 bank_num = 0; 9249 entry_num = 0; 9250 bank_count = 4; 9251 entry_count = 2; 9252 alpm_entry = &alpm_entry_v6_128; 9253 9254 if (SOC_ALPM_V6_SCALE_CHECK(unit, 1)) { 9255 step_count = 2; 9256 } else { 9257 step_count = 1; 9258 } 9259 9260 9261 /* Walk all lpm entries */ 9262 for (idx = (idx_end - 1); idx >= idx_start; idx--) { 9263 9264 /* Calculate entry ofset. */ 9265 lpm_entry = 9266 soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 9267 defip_pair_128_entry_t *, lpm_tbl_ptr, idx); 9268 9269 /* Make sure entry is valid. */ 9270 if (!soc_mem_field32_get(unit, pivot_mem, lpm_entry, VALID0_LWRf)) { 9271 continue; 9272 } 9273 9274 /* Skip reserved ipmc entry */ 9275 if (soc_feature(unit, soc_feature_ipmc_defip)) { 9276 int ipmc_route = 0; 9277 int ipmc_index = 0; 9278 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 9279 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 9280 lpm_entry, MULTICAST_ROUTEf); 9281 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 9282 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 9283 lpm_entry, DATA_TYPEf) == 2) { 9284 ipmc_route = 1; 9285 } else { 9286 ipmc_route = 0; 9287 } 9288 } 9289 9290 if (soc_feature(unit, soc_feature_generic_dest)) { 9291 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 9292 uint32 dest_value = 0; 9293 dest_value = soc_mem_field32_dest_get(unit, 9294 L3_DEFIP_PAIR_128m, lpm_entry, 9295 DESTINATIONf, &dest_type); 9296 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 9297 ipmc_index = dest_value; 9298 } else { 9299 ipmc_index = 0; 9300 } 9301 } else { 9302 ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 9303 lpm_entry, L3MC_INDEXf); 9304 } 9305 9306 if (ipmc_route && (ipmc_index == 0)) { 9307 continue; 9308 } 9309 } 9310 9311 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 9312 if (tmp_idx) { 9313 bkt_ptr++; 9314 } else { 9315 bkt_ptr = soc_mem_field32_get(unit, pivot_mem, lpm_entry, 9316 ALG_BKT_PTRf); 9317 } 9318 9319 if (bkt_ptr == 0) { 9320 9321 /* OVERRIDE VRF Processing */ 9322 9323 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9324 _bcm_td2_alpm_lpm128_key_parse(unit, (uint32 *) lpm_entry, &lpm_cfg); 9325 (void) soc_alpm_128_lpm_vrf_get(unit, lpm_entry, 9326 &lpm_cfg.defip_vrf, 9327 &nh_ecmp_idx); 9328 _bcm_td2_alpm_lpm128_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry); 9329 9330 lpm_cfg.defip_index = idx; 9331 9332 if (trv_data->op_cb) { 9333 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9334 (void *)&lpm_cfg, 9335 (void *)&nh_ecmp_idx, &cmp_result); 9336 #ifdef BCM_CB_ABORT_ON_ERR 9337 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9338 break; 9339 } 9340 #endif 9341 } 9342 9343 /* Skip second iteration for VRF OVERRIDE routes */ 9344 tmp_idx++; 9345 9346 continue; 9347 } 9348 9349 /* get the bucket pointer from lpm mem entry */ 9350 for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) { 9351 /* calculate bucket memory address */ 9352 /* also increment so next bucket address can be calculated */ 9353 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 9354 (bank_num & 0x3); 9355 /* read entry from bucket memory */ 9356 raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm, 9357 defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF); 9358 _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, entry_num, alpm_entry); 9359 9360 entry_num++; 9361 if (entry_num == entry_count) { 9362 entry_num = 0; 9363 bank_num++; 9364 if (bank_num == bank_count) { 9365 bank_num = 0; 9366 } 9367 } 9368 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 9369 continue; 9370 } 9371 /* Zero destination buffer first. */ 9372 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9373 9374 /* Parse the entry. */ 9375 /* Fill entry ip address & subnet mask. */ 9376 _bcm_td2_alpm_ent128_key_parse(unit, alpm_mem, 9377 (uint32 *) alpm_entry, &lpm_cfg); 9378 9379 soc_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 9380 &cmp_result); 9381 9382 /* get associated data */ 9383 _bcm_td2_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, 9384 &lpm_cfg, &nh_ecmp_idx); 9385 9386 if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) { 9387 int hit_offset; 9388 soc_field_t hit_field[4] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f}; 9389 hit_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_HIT_ONLYm, 9390 defip_alpm_hit_only_entry_t *, alpm_hit_tbl_ptr, (bkt_addr / 4)); 9391 hit_offset = bkt_addr % 4; 9392 if (!ALPM_CTRL(unit).hit_bits_skip && 9393 soc_mem_field32_get(unit, alpm_hit_mem, hit_entry, hit_field[hit_offset])) { 9394 lpm_cfg.defip_flags |= BCM_L3_HIT; 9395 } 9396 } 9397 9398 /* If protocol doesn't match skip the entry. */ 9399 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 9400 continue; 9401 } 9402 9403 phy_idx = soc_alpm_physical_idx(unit, L3_DEFIP_PAIR_128m, idx, 1); 9404 phy_idx = SOC_ALPM_128_ADDR_LWR(unit, phy_idx ) << 1; 9405 lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx; 9406 lpm_cfg.defip_index = bkt_addr; 9407 9408 /* Check if this is default route */ 9409 /* Subnet length zero will indicate default route */ 9410 if (0 == lpm_cfg.defip_sub_len) { 9411 if (def_arr_idx < SOC_VRF_MAX(unit)) { 9412 def_rte_arr[def_arr_idx].bkt_addr = bkt_addr; 9413 def_rte_arr[def_arr_idx].idx = idx; 9414 def_arr_idx ++; 9415 } 9416 } else { 9417 /* Execute operation routine if any. */ 9418 if (trv_data->op_cb) { 9419 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9420 (void *)&lpm_cfg, 9421 (void *)&nh_ecmp_idx, &cmp_result); 9422 #ifdef BCM_CB_ABORT_ON_ERR 9423 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9424 break; 9425 } 9426 #endif 9427 } 9428 } 9429 } 9430 } 9431 } 9432 9433 /* Process Default routes */ 9434 for (idx = 0; idx < def_arr_idx; idx++) { 9435 9436 /* Calculate entry ofset. */ 9437 lpm_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 9438 defip_pair_128_entry_t *, lpm_tbl_ptr, 9439 def_rte_arr[idx].idx); 9440 9441 /* Make sure entry is valid. */ 9442 if (!soc_mem_field32_get(unit, pivot_mem, lpm_entry, VALID0_LWRf)) { 9443 continue; 9444 } 9445 9446 bkt_addr = def_rte_arr[idx].bkt_addr; 9447 9448 /* read entry from bucket memory */ 9449 raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm, 9450 defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF); 9451 _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, bkt_addr >> 16, alpm_entry); 9452 9453 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 9454 continue; 9455 } 9456 9457 /* Zero destination buffer first. */ 9458 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9459 9460 phy_idx = soc_alpm_physical_idx(unit, L3_DEFIP_PAIR_128m, 9461 def_rte_arr[idx].idx, 1); 9462 phy_idx = SOC_ALPM_128_ADDR_LWR(unit, phy_idx) << 1; 9463 lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx; 9464 lpm_cfg.defip_index = bkt_addr; 9465 9466 /* Parse the entry. */ 9467 soc_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 9468 &cmp_result); 9469 /* Fill entry ip address & subnet mask. */ 9470 _bcm_td2_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, &lpm_cfg); 9471 9472 _bcm_td2_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, &lpm_cfg, 9473 &nh_ecmp_idx); 9474 9475 /* If protocol doesn't match skip the entry. */ 9476 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 9477 continue; 9478 } 9479 9480 /* Execute operation routine if any. */ 9481 if (trv_data->op_cb) { 9482 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9483 (void *)&lpm_cfg, 9484 (void *)&nh_ecmp_idx, &cmp_result); 9485 #ifdef BCM_CB_ABORT_ON_ERR 9486 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9487 break; 9488 } 9489 #endif 9490 } 9491 } 9492 9493 error: 9494 if (def_rte_arr != NULL) { 9495 sal_free(def_rte_arr); 9496 } 9497 if (lpm_tbl_ptr != NULL) { 9498 soc_cm_sfree(unit, lpm_tbl_ptr); 9499 } 9500 if (alpm_tbl_ptr != NULL) { 9501 soc_cm_sfree(unit, alpm_tbl_ptr); 9502 } 9503 if (alpm_hit_tbl_ptr != NULL) { 9504 soc_cm_sfree(unit, alpm_hit_tbl_ptr); 9505 } 9506 return (rv); 9507 } 9508 9509 /* 9510 * Function: 9511 * _bcm_td2_alpm_update_match 9512 * Purpose: 9513 * Update/Delete all entries in defip table matching a certain rule. 9514 * Parameters: 9515 * unit - (IN)SOC unit number. 9516 * trv_data - (IN)Delete pattern + compare,act,notify routines. 9517 * Returns: 9518 * BCM_E_XXX 9519 */ 9520 int 9521 _bcm_td2_alpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 9522 { 9523 uint32 ipv6 = 0; /* Iterate over ipv6 only flag. */ 9524 int idx; /* Iteration index. */ 9525 int phy_idx; /* Iteration index. */ 9526 int tmp_idx; /* Iteration index. */ 9527 int tmp_start; /* Iteration start. */ 9528 int tmp_end; /* Iteration end. */ 9529 int tmp_delta; /* Iteration delta. */ 9530 char *lpm_tbl_ptr = NULL; /* Dma table pointer. */ 9531 char *alpm_tbl_ptr = NULL; /* Dma table pointer. */ 9532 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 9533 int cmp_result; /* Test routine result. */ 9534 defip_entry_t *lpm_entry; /* Hw entry buffer. */ 9535 defip_entry_t lpm_entry_data; /* Hw entry buffer. */ 9536 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 9537 int defip_table_size; /* Defip table size. */ 9538 int rv = BCM_E_NONE; /* Operation return status. */ 9539 char *alpm_hit_tbl_ptr = NULL; /* Dma hit only table pointer. */ 9540 int idx_start = 0; 9541 int idx_end = 0, bkt_idx, bkt_count, bkt_ptr = 0, bkt_addr; 9542 int entry_num, bank_num, entry_count, bank_count; 9543 defip_alpm_ipv4_1_entry_t alpm_entry_v4; 9544 defip_alpm_ipv6_64_1_entry_t alpm_entry_v6_64; 9545 void *alpm_entry; 9546 void *raw_entry ; 9547 soc_mem_t alpm_mem; 9548 void *hit_entry; 9549 soc_mem_t alpm_hit_mem; 9550 int step_count; 9551 int def_arr_idx = 0; 9552 int def_rte_arr_sz; 9553 int flex; 9554 typedef struct _alpm_def_route_info_s { 9555 int idx; 9556 int tmp_idx; 9557 int bkt_addr; 9558 defip_entry_t lpm_entry; 9559 } _alpm_def_route_info_t; 9560 9561 _alpm_def_route_info_t *def_rte_arr = NULL; 9562 9563 #ifdef BCM_WARM_BOOT_SUPPORT 9564 if (SOC_WARM_BOOT(unit)) { 9565 if (soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)) != 0) { 9566 rv =_bcm_td2_alpm_warmboot_walk(unit, trv_data); 9567 if (rv < 0) { 9568 LOG_CLI((BSL_META_U(unit, 9569 "ERROR! ALPM Warmboot recovery failed"))); 9570 return (rv); 9571 } 9572 } 9573 if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) != 0) { 9574 /* v6-128 entries */ 9575 rv = _bcm_td2_alpm_128_warmboot_walk(unit, trv_data); 9576 if (rv < 0) { 9577 LOG_CLI((BSL_META_U(unit, 9578 "ERROR! ALPM Warmboot V6-128 recovery failed"))); 9579 } 9580 } 9581 return (rv); 9582 } 9583 #endif 9584 9585 ipv6 = trv_data->flags & BCM_L3_IP6; 9586 9587 if (ipv6 && soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) != 0) { 9588 /* first get v6-128 entries */ 9589 rv = _bcm_td2_alpm_128_update_match(unit, trv_data); 9590 #ifdef BCM_CB_ABORT_ON_ERR 9591 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9592 return rv; 9593 } 9594 #endif 9595 } 9596 9597 if (soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)) == 0) { 9598 return BCM_E_NONE; 9599 } 9600 9601 9602 /* Table DMA the LPM table to software copy */ 9603 9604 alpm_mem = L3_DEFIP_ALPM_RAWm; 9605 rv = bcm_xgs3_l3_tbl_dma(unit, alpm_mem, 9606 WORDS2BYTES(soc_mem_entry_words(unit, alpm_mem)), 9607 "alpm_tbl", &alpm_tbl_ptr, NULL); 9608 if (BCM_FAILURE(rv)) { 9609 goto error; 9610 } 9611 9612 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 9613 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 9614 &lpm_tbl_ptr, &defip_table_size); 9615 if (BCM_FAILURE(rv)) { 9616 goto error; 9617 } 9618 9619 if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) { 9620 alpm_hit_mem = L3_DEFIP_ALPM_HIT_ONLYm; 9621 rv = bcm_xgs3_l3_tbl_dma(unit, alpm_hit_mem, 9622 WORDS2BYTES(soc_mem_entry_words(unit, alpm_hit_mem)), 9623 "alpm_hit_tbl", &alpm_hit_tbl_ptr, NULL); 9624 if (BCM_FAILURE(rv)) { 9625 goto error; 9626 } 9627 } 9628 9629 /* Allocate memory to store default route meta data*/ 9630 def_rte_arr_sz = SOC_VRF_MAX(unit) * sizeof(_alpm_def_route_info_t); 9631 def_rte_arr = sal_alloc(def_rte_arr_sz, "alpm_def_rte_arry"); 9632 if (NULL == def_rte_arr) { 9633 rv = BCM_E_MEMORY; 9634 goto error; 9635 } 9636 sal_memset(def_rte_arr, 0, def_rte_arr_sz); 9637 9638 if (SOC_URPF_STATUS_GET(unit)) { 9639 defip_table_size >>= 1; 9640 } 9641 9642 idx_end = defip_table_size; 9643 bank_num = 0; 9644 entry_num = 0; 9645 bank_count = 4; 9646 9647 if (ipv6) { 9648 if (SOC_ALPM_V6_SCALE_CHECK(unit, 1)) { 9649 step_count = 2; 9650 } else { 9651 step_count = 1; 9652 } 9653 } else { 9654 step_count = 2; 9655 } 9656 9657 /* Walk all lpm entries */ 9658 for (idx = (idx_end - 1); idx >= idx_start; idx--) { 9659 /* Calculate entry ofset. */ 9660 lpm_entry = 9661 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 9662 defip_entry_t *, lpm_tbl_ptr, idx); 9663 sal_memcpy (&lpm_entry_data, lpm_entry, sizeof (lpm_entry_data)); 9664 9665 if (ipv6 && (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit)) == 0)) { 9666 /* 9667 * Function called for IPv6 LPM/ALPM walk and LPM entry is IPv4; Continue; 9668 */ 9669 continue; 9670 } 9671 9672 /* Each LPM index has two IPv4 entries*/ 9673 if (ipv6) { 9674 tmp_start = 0; 9675 tmp_end = step_count; 9676 tmp_delta = 1; 9677 } else { 9678 tmp_start = step_count - 1; 9679 tmp_end = -1; 9680 tmp_delta = -1; 9681 } 9682 9683 for (tmp_idx = tmp_start; tmp_idx != tmp_end; tmp_idx += tmp_delta) { 9684 if (!ipv6) { 9685 if (tmp_idx) { 9686 soc_alpm_lpm_ip4entry1_to_0(unit, &lpm_entry_data, lpm_entry, TRUE); 9687 } else { 9688 soc_alpm_lpm_ip4entry0_to_0(unit, &lpm_entry_data, lpm_entry, TRUE); 9689 } 9690 } 9691 9692 /* Make sure entry is valid. */ 9693 if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) { 9694 continue; 9695 } 9696 9697 /* Skip reserved ipmc entry */ 9698 if (soc_feature(unit, soc_feature_ipmc_defip)) { 9699 /* Skip reserved ipmc entry */ 9700 int ipmc_index = 0; 9701 int ipmc_route = 0; 9702 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 9703 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 9704 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 9705 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 9706 ipmc_route = 1; 9707 } else { 9708 ipmc_route = 0; 9709 } 9710 } 9711 9712 if (soc_feature(unit, soc_feature_generic_dest)) { 9713 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 9714 uint32 dest_value = 0; 9715 dest_value = soc_mem_field32_dest_get(unit, 9716 L3_DEFIPm, lpm_entry, 9717 DESTINATION0f, &dest_type); 9718 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 9719 ipmc_index = dest_value; 9720 } else { 9721 ipmc_index = 0; 9722 } 9723 } else { 9724 ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm, 9725 lpm_entry, L3MC_INDEX0f); 9726 } 9727 9728 if (ipmc_route && (ipmc_index == 0)) { 9729 continue; 9730 } 9731 } 9732 9733 cmp_result = ipv6 ? 1 : 0; 9734 if (cmp_result != (soc_mem_field32_get(unit, L3_DEFIPm, 9735 lpm_entry, MODE0_f(unit)))) { 9736 continue; 9737 } 9738 9739 soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, NULL); 9740 9741 9742 if (ipv6 && tmp_idx) { 9743 bkt_ptr++; 9744 } else { 9745 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 9746 ALG_BKT_PTR0f); 9747 if (bkt_ptr == 0) { 9748 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9749 _bcm_td2_alpm_lpm_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry); 9750 _bcm_td2_alpm_lpm_key_parse(unit, &lpm_cfg, lpm_entry); 9751 9752 lpm_cfg.defip_index = idx; 9753 9754 if (ipv6 == (lpm_cfg.defip_flags & BCM_L3_IP6)) { 9755 if (trv_data->op_cb) { 9756 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9757 (void *)&lpm_cfg, 9758 (void *)&nh_ecmp_idx, &cmp_result); 9759 #ifdef BCM_CB_ABORT_ON_ERR 9760 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9761 break; 9762 } 9763 #endif 9764 } 9765 } 9766 if (ipv6) { 9767 /* Skip IPv6 second iteration for TCAM routes */ 9768 tmp_idx = tmp_end - tmp_delta; 9769 } 9770 continue; 9771 } 9772 9773 } 9774 9775 flex = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f); 9776 if (ipv6) { 9777 if (flex) { 9778 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m; 9779 bkt_count = ALPM_IPV6_64_BKT_COUNT_FLEX; 9780 entry_count = 3; 9781 alpm_entry = &alpm_entry_v6_64; 9782 } else { 9783 alpm_mem = L3_DEFIP_ALPM_IPV6_64m; 9784 bkt_count = ALPM_IPV6_64_BKT_COUNT; 9785 entry_count = 4; 9786 alpm_entry = &alpm_entry_v6_64; 9787 } 9788 9789 } else { 9790 if (flex) { 9791 alpm_mem = L3_DEFIP_ALPM_IPV4_1m; 9792 bkt_count = ALPM_IPV4_BKT_COUNT_FLEX; 9793 entry_count = 4; 9794 alpm_entry = &alpm_entry_v4; 9795 } else { 9796 alpm_mem = L3_DEFIP_ALPM_IPV4m; 9797 bkt_count = ALPM_IPV4_BKT_COUNT; 9798 entry_count = 6; 9799 alpm_entry = &alpm_entry_v4; 9800 } 9801 } 9802 9803 /* Get the bucket pointer from lpm mem entry */ 9804 for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) { 9805 /* Calculate bucket memory address */ 9806 /* Increment so next bucket address can be calculated */ 9807 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 9808 (bank_num & 0x3); 9809 9810 raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm, 9811 defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF); 9812 _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, entry_num, alpm_entry); 9813 9814 entry_num++; 9815 if (entry_num == entry_count) { 9816 entry_num = 0; 9817 bank_num++; 9818 if (bank_num == bank_count) { 9819 bank_num = 0; 9820 } 9821 } 9822 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 9823 continue; 9824 } 9825 9826 /* Zero destination buffer first. */ 9827 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9828 9829 /* Parse the entry. */ 9830 _bcm_td2_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 9831 alpm_mem, alpm_entry); 9832 9833 if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) { 9834 int hit_offset; 9835 soc_field_t hit_field[4] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f}; 9836 hit_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_HIT_ONLYm, 9837 defip_alpm_hit_only_entry_t *, alpm_hit_tbl_ptr, (bkt_addr / 4)); 9838 hit_offset = bkt_addr % 4; 9839 if (!ALPM_CTRL(unit).hit_bits_skip && 9840 soc_mem_field32_get(unit, alpm_hit_mem, hit_entry, hit_field[hit_offset])) { 9841 lpm_cfg.defip_flags |= BCM_L3_HIT; 9842 } 9843 } 9844 9845 /* If protocol doesn't match skip the entry. */ 9846 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 9847 continue; 9848 } 9849 9850 /* Fill entry IP address and subnet mask. */ 9851 _bcm_td2_alpm_ent_key_parse(unit, &lpm_cfg, lpm_entry, 9852 alpm_mem, alpm_entry); 9853 9854 phy_idx = ipv6 ? idx: ((idx << 1) + tmp_idx); 9855 phy_idx = soc_alpm_physical_idx(unit, L3_DEFIPm, phy_idx, ipv6); 9856 phy_idx = phy_idx << (ipv6 ? 1 : 0); 9857 lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx; 9858 lpm_cfg.defip_index = bkt_addr; 9859 9860 /* Check if this is default route */ 9861 /* Subnet length zero will indicate default route */ 9862 if (0 == lpm_cfg.defip_sub_len) { 9863 if (def_arr_idx < SOC_VRF_MAX(unit)) { 9864 def_rte_arr[def_arr_idx].bkt_addr = bkt_addr; 9865 def_rte_arr[def_arr_idx].idx = idx; 9866 def_rte_arr[def_arr_idx].tmp_idx = tmp_idx; 9867 sal_memcpy(&def_rte_arr[def_arr_idx].lpm_entry, 9868 lpm_entry, sizeof(*lpm_entry)); 9869 def_arr_idx ++; 9870 } 9871 } else { 9872 /* Execute operation routine if any. */ 9873 if (trv_data->op_cb) { 9874 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9875 (void *)&lpm_cfg, 9876 (void *)&nh_ecmp_idx, &cmp_result); 9877 #ifdef BCM_CB_ABORT_ON_ERR 9878 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9879 break; 9880 } 9881 #endif 9882 } 9883 } 9884 } 9885 } 9886 } 9887 9888 /* Process Default routes */ 9889 for (idx = 0; idx < def_arr_idx; idx++) { 9890 9891 /* Calculate entry ofset. */ 9892 lpm_entry = &def_rte_arr[idx].lpm_entry; 9893 9894 cmp_result = ipv6 ? 1 : 0; 9895 if (cmp_result != (soc_mem_field32_get(unit, L3_DEFIPm, 9896 lpm_entry, MODE0_f(unit)))) { 9897 /* 9898 * Function called for IPv6 LPM/ALPM walk and LPM entry is IPv4; 9899 * Continue; 9900 */ 9901 continue; 9902 } 9903 flex = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f); 9904 if (ipv6) { 9905 if (flex) { 9906 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m; 9907 alpm_entry = &alpm_entry_v6_64; 9908 } else { 9909 alpm_mem = L3_DEFIP_ALPM_IPV6_64m; 9910 alpm_entry = &alpm_entry_v6_64; 9911 } 9912 9913 } else { 9914 if (flex) { 9915 alpm_mem = L3_DEFIP_ALPM_IPV4_1m; 9916 alpm_entry = &alpm_entry_v4; 9917 } else { 9918 alpm_mem = L3_DEFIP_ALPM_IPV4m; 9919 alpm_entry = &alpm_entry_v4; 9920 } 9921 } 9922 9923 bkt_addr = def_rte_arr[idx].bkt_addr; 9924 9925 /* read entry from bucket memory */ 9926 raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm, 9927 defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF); 9928 _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, bkt_addr >> 16, alpm_entry); 9929 9930 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 9931 continue; 9932 } 9933 9934 /* Zero destination buffer first. */ 9935 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 9936 9937 phy_idx = ipv6 ? def_rte_arr[idx].idx: 9938 ((def_rte_arr[idx].idx << 1) + def_rte_arr[idx].tmp_idx); 9939 phy_idx = soc_alpm_physical_idx(unit, L3_DEFIPm, phy_idx, ipv6); 9940 phy_idx = phy_idx << (ipv6 ? 1 : 0); 9941 lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx; 9942 lpm_cfg.defip_index = bkt_addr; 9943 9944 soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, NULL); 9945 /* Parse the entry. */ 9946 _bcm_td2_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 9947 alpm_mem, alpm_entry); 9948 9949 /* If protocol doesn't match skip the entry. */ 9950 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 9951 continue; 9952 } 9953 9954 /* Fill entry ip address & subnet mask. */ 9955 _bcm_td2_alpm_ent_key_parse(unit, &lpm_cfg, lpm_entry, 9956 alpm_mem, alpm_entry); 9957 9958 /* Execute operation routine if any. */ 9959 if (trv_data->op_cb) { 9960 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 9961 (void *)&lpm_cfg, 9962 (void *)&nh_ecmp_idx, &cmp_result); 9963 #ifdef BCM_CB_ABORT_ON_ERR 9964 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 9965 break; 9966 } 9967 #endif 9968 } 9969 } 9970 9971 #ifdef ALPM_WARM_BOOT_DEBUG 9972 soc_alpm_lpm_sw_dump(unit); 9973 #endif /* ALPM_WARM_BOOT_DEBUG */ 9974 9975 error: 9976 if (def_rte_arr != NULL) { 9977 sal_free(def_rte_arr); 9978 } 9979 if (lpm_tbl_ptr != NULL) { 9980 soc_cm_sfree(unit, lpm_tbl_ptr); 9981 } 9982 if (alpm_tbl_ptr != NULL) { 9983 soc_cm_sfree(unit, alpm_tbl_ptr); 9984 } 9985 if (alpm_hit_tbl_ptr != NULL) { 9986 soc_cm_sfree(unit, alpm_hit_tbl_ptr); 9987 } 9988 return (rv); 9989 } 9990 9991 /* 9992 * Function: 9993 * _bcm_td2_alpm_find 9994 * Purpose: 9995 * Get an entry from DEFIP table. 9996 * Parameters: 9997 * unit - (IN)SOC unit number. 9998 * lpm_cfg - (IN)Buffer to fill defip information. 9999 * nh_ecmp_idx - (IN)Next hop or ecmp group index 10000 * Returns: 10001 * BCM_E_XXX 10002 */ 10003 int 10004 _bcm_td2_alpm_find(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 10005 { 10006 defip_entry_t lpm_key; /* Route lookup key. */ 10007 defip_entry_t lpm_entry; /* Search result buffer. */ 10008 defip_pair_128_entry_t lpm_128_key; 10009 defip_pair_128_entry_t lpm_128_entry; 10010 int do_urpf = 0; /* Find uRPF region */ 10011 int rv; /* Operation return status. */ 10012 uint32 flags = 0; 10013 soc_mem_t mem; 10014 int lpm_mode, tmp; 10015 uint32 rval; 10016 10017 /* Input parameters check */ 10018 if (NULL == lpm_cfg) { 10019 return (BCM_E_PARAM); 10020 } 10021 10022 SOC_IF_ERROR_RETURN(READ_L3_DEFIP_RPF_CONTROLr(unit, &rval)); 10023 lpm_mode = soc_reg_field_get(unit, L3_DEFIP_RPF_CONTROLr, rval, LPM_MODEf); 10024 /* Not supported in Legacy LPM mode */ 10025 if (lpm_mode == 0) { 10026 return (BCM_E_UNAVAIL); 10027 } 10028 10029 /* Zero buffers. */ 10030 sal_memset(&lpm_entry, 0, sizeof(defip_entry_t)); 10031 sal_memset(&lpm_key, 0, sizeof(defip_entry_t)); 10032 sal_memset(&lpm_128_entry, 0, sizeof(defip_pair_128_entry_t)); 10033 sal_memset(&lpm_128_key, 0, sizeof(defip_pair_128_entry_t)); 10034 10035 /* Default value */ 10036 mem = L3_DEFIPm; 10037 if ((lpm_cfg->defip_flags & BCM_L3_IP6)) { 10038 if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) > 0) { 10039 mem = L3_DEFIP_PAIR_128m; 10040 } 10041 } 10042 10043 switch (mem) { 10044 case L3_DEFIP_PAIR_128m: 10045 /* Initialize lkup key. */ 10046 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg, 10047 &lpm_128_key, 0, &flags)); 10048 /* Perform hw lookup. */ 10049 rv = soc_alpm_128_find_best_match(unit, &lpm_128_key, &lpm_128_entry, 10050 &lpm_cfg->defip_index, do_urpf); 10051 BCM_IF_ERROR_RETURN(rv); 10052 10053 /* Parse hw buffer to defip entry. */ 10054 /* OVERRIDE VRF Processing */ 10055 _bcm_td2_alpm_lpm128_key_parse(unit, (uint32 *)&lpm_128_entry, lpm_cfg); 10056 soc_alpm_128_lpm_vrf_get(unit, &lpm_128_entry, &lpm_cfg->defip_vrf, &tmp); 10057 _bcm_td2_alpm_lpm128_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_128_entry); 10058 10059 break; 10060 default: 10061 /* Initialize lkup key. */ 10062 BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_key, 0, 10063 &flags)); 10064 /* Perform hw lookup. */ 10065 rv = soc_alpm_find_best_match(unit, &lpm_key, &lpm_entry, 10066 &lpm_cfg->defip_index, do_urpf); 10067 BCM_IF_ERROR_RETURN(rv); 10068 10069 /* Parse hw buffer to defip entry. */ 10070 _bcm_td2_alpm_lpm_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_entry); 10071 _bcm_td2_alpm_lpm_key_parse(unit, lpm_cfg, &lpm_entry); 10072 10073 break; 10074 } 10075 10076 return (BCM_E_NONE); 10077 } 10078 10079 #if defined(BCM_TOMAHAWK3_SUPPORT) 10080 /* 10081 * Function: 10082 * _bcm_th3_alpm_clear_hit 10083 * Purpose: 10084 * Clear prefix entry hit bit. 10085 * Parameters: 10086 * u - (IN)SOC unit number. 10087 * lpm_cfg - (IN)Found LPM Defip config info 10088 * Returns: 10089 * BCM_E_XXX 10090 */ 10091 STATIC int _bcm_th3_alpm_clear_hit(int u, 10092 _bcm_defip_cfg_t * lpm_cfg) 10093 { 10094 return bcm_esw_alpm_clear_hit(u, lpm_cfg); 10095 } 10096 10097 /* 10098 * Function: 10099 * _bcm_th3_alpm_get 10100 * Purpose: 10101 * Get an entry from DEFIP table. 10102 * Parameters: 10103 * unit - (IN)SOC unit number. 10104 * lpm_cfg - (IN)Buffer to fill defip information. 10105 * nh_ecmp_idx - (IN)Next hop or ecmp group index 10106 * Returns: 10107 * BCM_E_XXX 10108 */ 10109 int bcm_th3_alpm_get( 10110 int unit, 10111 _bcm_defip_cfg_t * lpm_cfg, 10112 int *nh_ecmp_idx) 10113 { 10114 int clear_hit; /* Clear hit indicator. */ 10115 int alpm_global_routes = 0; 10116 10117 /* 10118 * Input parameters check 10119 */ 10120 if (lpm_cfg == NULL) 10121 { 10122 return (BCM_E_PARAM); 10123 } 10124 10125 #if 0 10126 BCM_IF_ERROR_RETURN( 10127 _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 10128 lpm_cfg->defip_sub_len, NULL)); 10129 #else 10130 if ((lpm_cfg->defip_sub_len > 64 && 10131 (soc_mem_index_count(unit, L3_DEFIP_PAIR_LEVEL1m) <= 0)) || 10132 (!(lpm_cfg->defip_flags & BCM_L3_IP6) && 10133 (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0)) 10134 ) { 10135 return BCM_E_PARAM; 10136 } 10137 #endif 10138 /* 10139 * Check if clear hit bit required. 10140 */ 10141 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 10142 10143 /* 10144 * Perform hw lookup. 10145 */ 10146 BCM_IF_ERROR_RETURN(bcm_esw_alpm_lookup(unit, lpm_cfg)); 10147 10148 if (nh_ecmp_idx) 10149 { 10150 *nh_ecmp_idx = lpm_cfg->defip_ecmp_index; 10151 } 10152 10153 if (!ALPM_HIT_SKIP(unit) && 10154 !(lpm_cfg->defip_flags & BCM_L3_IPMC) && 10155 _soc_alpm_mode[unit] != 0 && 10156 (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE || 10157 (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL && 10158 _soc_alpm_mode[unit] == 3))) { 10159 alpm_global_routes = 1; 10160 } 10161 10162 if (!ALPM_HIT_SKIP(unit) && 10163 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 10164 alpm_global_routes = 1; 10165 } 10166 10167 /* 10168 * Clear the HIT bit 10169 */ 10170 if (clear_hit && !alpm_global_routes) 10171 { 10172 BCM_IF_ERROR_RETURN(_bcm_th3_alpm_clear_hit(unit, lpm_cfg)); 10173 } 10174 10175 return (BCM_E_NONE); 10176 } 10177 10178 /* 10179 * Function: 10180 * _bcm_th3_alpm_add 10181 * Purpose: 10182 * Add an entry to DEFIP table. 10183 * Parameters: 10184 * unit - (IN)SOC unit number. 10185 * lpm_cfg - (IN)Buffer to fill defip information. 10186 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 10187 * Returns: 10188 * BCM_E_XXX 10189 */ 10190 int bcm_th3_alpm_add( 10191 int unit, 10192 _bcm_defip_cfg_t * lpm_cfg, 10193 int nh_ecmp_idx) 10194 { 10195 int rv = 0; /* Operation return status. */ 10196 /* 10197 * Input parameters check 10198 */ 10199 if (lpm_cfg == NULL) 10200 { 10201 return (BCM_E_PARAM); 10202 } 10203 #if 0 10204 BCM_IF_ERROR_RETURN( 10205 _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 10206 lpm_cfg->defip_sub_len, NULL)); 10207 #else 10208 if ((lpm_cfg->defip_sub_len > 64 && 10209 (soc_mem_index_count(unit, L3_DEFIP_PAIR_LEVEL1m) <= 0)) || 10210 (!(lpm_cfg->defip_flags & BCM_L3_IP6) && 10211 (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0)) 10212 ) { 10213 return BCM_E_PARAM; 10214 } 10215 #endif 10216 /* 10217 * Write buffer to hw. 10218 */ 10219 lpm_cfg->defip_ecmp_index = nh_ecmp_idx; 10220 rv = bcm_esw_alpm_insert(unit, lpm_cfg); 10221 10222 alpm_trace_log(unit, ALPM_TRACE_OP_ADD, lpm_cfg, nh_ecmp_idx, rv); 10223 /* 10224 * If new route added increment total number of routes. 10225 */ 10226 /* 10227 * Lack of index indicates a new route. 10228 */ 10229 if ((rv >= 0) && !(lpm_cfg->defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT)) 10230 { 10231 BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 10232 } 10233 10234 return rv; 10235 } 10236 10237 /* 10238 * Function: 10239 * _bcm_th3_alpm_del 10240 * Purpose: 10241 * Delete an entry from DEFIP table. 10242 * Parameters: 10243 * unit - (IN)SOC unit number. 10244 * lpm_cfg - (IN)Buffer to fill defip information. 10245 * Returns: 10246 * BCM_E_XXX 10247 */ 10248 int bcm_th3_alpm_del( 10249 int unit, 10250 _bcm_defip_cfg_t * lpm_cfg) 10251 { 10252 int rv = 0; /* Operation return status. */ 10253 /* 10254 * Input parameters check 10255 */ 10256 if (lpm_cfg == NULL) 10257 { 10258 return (BCM_E_PARAM); 10259 } 10260 10261 /* For fast delete_all, we skip delete route and only do delete ecmp_nh_idx */ 10262 if (lpm_cfg->fast_delete_all) { 10263 return rv; 10264 } 10265 #if 0 10266 BCM_IF_ERROR_RETURN( 10267 _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 10268 lpm_cfg->defip_sub_len, NULL)); 10269 #else 10270 if ((lpm_cfg->defip_sub_len > 64 && 10271 (soc_mem_index_count(unit, L3_DEFIP_PAIR_LEVEL1m) <= 0)) || 10272 (!(lpm_cfg->defip_flags & BCM_L3_IP6) && 10273 (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0)) 10274 ) { 10275 return BCM_E_PARAM; 10276 } 10277 #endif 10278 /* 10279 * Write buffer to hw. 10280 */ 10281 rv = bcm_esw_alpm_delete(unit, lpm_cfg); 10282 10283 alpm_trace_log(unit, ALPM_TRACE_OP_DELETE, lpm_cfg, -1, rv); 10284 /* 10285 * If route deleted, decrement total number of routes. 10286 */ 10287 if (rv >= 0) 10288 { 10289 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6); 10290 } 10291 return rv; 10292 } 10293 10294 /* 10295 * Function: 10296 * _bcm_th3_alpm_update_match 10297 * Purpose: 10298 * Update/Delete all entries in defip table matching a certain rule. 10299 * Parameters: 10300 * unit - (IN)SOC unit number. 10301 * trv_data - (IN)Delete pattern + compare,act,notify routines. 10302 * Returns: 10303 * BCM_E_XXX 10304 */ 10305 int bcm_th3_alpm_update_match( 10306 int unit, 10307 _bcm_l3_trvrs_data_t * trv_data) 10308 { 10309 int rv = BCM_E_NONE; 10310 10311 rv = bcm_esw_alpm_update_match(unit, trv_data); 10312 return (rv); 10313 } 10314 #endif /* BCM_TOMAHAWK3_SUPPORT */ 10315 10316 #if defined(BCM_TOMAHAWK_SUPPORT) 10317 /* 10318 * Function: 10319 * _bcm_th_alpm_clear_hit 10320 * Purpose: 10321 * Clear prefix entry hit bit. 10322 * Parameters: 10323 * u - (IN)SOC unit number. 10324 * lpm_cfg - (IN)Found LPM Defip config info 10325 * Returns: 10326 * BCM_E_XXX 10327 */ 10328 STATIC int 10329 _bcm_th_alpm_clear_hit(int u, _bcm_defip_cfg_t * lpm_cfg) 10330 { 10331 return bcm_esw_alpm_clear_hit(u, lpm_cfg); 10332 } 10333 10334 /* 10335 * Function: 10336 * bcm_th_alpm_get 10337 * Purpose: 10338 * Get an entry from DEFIP table. 10339 * Parameters: 10340 * unit - (IN)SOC unit number. 10341 * lpm_cfg - (IN)Buffer to fill defip information. 10342 * nh_ecmp_idx - (IN)Next hop or ecmp group index 10343 * Returns: 10344 * BCM_E_XXX 10345 */ 10346 int 10347 bcm_th_alpm_get(int unit, _bcm_defip_cfg_t * lpm_cfg, int *nh_ecmp_idx) 10348 { 10349 int clear_hit; /* Clear hit indicator. */ 10350 soc_mem_t mem; 10351 int alpm_global_routes = 0; 10352 /* 10353 * Input parameters check 10354 */ 10355 if (lpm_cfg == NULL) { 10356 return (BCM_E_PARAM); 10357 } 10358 10359 BCM_IF_ERROR_RETURN( 10360 _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 10361 lpm_cfg->defip_sub_len, &mem)); 10362 10363 /* 10364 * Check if clear hit bit required. 10365 */ 10366 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 10367 10368 /* 10369 * Perform hw lookup. 10370 */ 10371 BCM_IF_ERROR_RETURN(bcm_esw_alpm_lookup(unit, lpm_cfg)); 10372 10373 if (nh_ecmp_idx) { 10374 *nh_ecmp_idx = lpm_cfg->defip_ecmp_index; 10375 } 10376 10377 if (!ALPM_HIT_SKIP(unit) && 10378 !(lpm_cfg->defip_flags & BCM_L3_IPMC) && 10379 _soc_alpm_mode[unit] != 0 && 10380 (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE || 10381 (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL && 10382 _soc_alpm_mode[unit] == 3))) { 10383 alpm_global_routes = 1; 10384 } 10385 10386 if (!ALPM_HIT_SKIP(unit) && 10387 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 10388 alpm_global_routes = 1; 10389 } 10390 10391 /* 10392 * Clear the HIT bit 10393 */ 10394 if (clear_hit && !alpm_global_routes) { 10395 BCM_IF_ERROR_RETURN(_bcm_th_alpm_clear_hit(unit, lpm_cfg)); 10396 } 10397 10398 return (BCM_E_NONE); 10399 } 10400 10401 /* 10402 * Function: 10403 * bcm_th_alpm_add 10404 * Purpose: 10405 * Add an entry to DEFIP table. 10406 * Parameters: 10407 * unit - (IN)SOC unit number. 10408 * lpm_cfg - (IN)Buffer to fill defip information. 10409 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 10410 * Returns: 10411 * BCM_E_XXX 10412 */ 10413 int 10414 bcm_th_alpm_add(int unit, _bcm_defip_cfg_t * lpm_cfg, int nh_ecmp_idx) 10415 { 10416 int rv = 0; /* Operation return status. */ 10417 soc_mem_t mem; 10418 10419 /* 10420 * Input parameters check 10421 */ 10422 if (lpm_cfg == NULL) { 10423 return (BCM_E_PARAM); 10424 } 10425 10426 BCM_IF_ERROR_RETURN( 10427 _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 10428 lpm_cfg->defip_sub_len, &mem)); 10429 10430 /* 10431 * Write buffer to hw. 10432 */ 10433 lpm_cfg->defip_ecmp_index = nh_ecmp_idx; 10434 rv = bcm_esw_alpm_insert(unit, lpm_cfg); 10435 10436 alpm_trace_log(unit, ALPM_TRACE_OP_ADD, lpm_cfg, nh_ecmp_idx, rv); 10437 10438 /* 10439 * If new route added increment total number of routes. 10440 */ 10441 /* 10442 * Lack of index indicates a new route. 10443 */ 10444 if ((rv >= 0) && !(lpm_cfg->defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT || 10445 lpm_cfg->defip_alpm_cookie & SOC_ALPM_LPM_LOOKUP_HIT)) { 10446 BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 10447 } 10448 10449 return rv; 10450 } 10451 10452 /* 10453 * Function: 10454 * bcm_th_alpm_del 10455 * Purpose: 10456 * Delete an entry from DEFIP table. 10457 * Parameters: 10458 * unit - (IN)SOC unit number. 10459 * lpm_cfg - (IN)Buffer to fill defip information. 10460 * Returns: 10461 * BCM_E_XXX 10462 */ 10463 int 10464 bcm_th_alpm_del(int unit, _bcm_defip_cfg_t * lpm_cfg) 10465 { 10466 int rv = 0; /* Operation return status. */ 10467 soc_mem_t mem; 10468 10469 /* 10470 * Input parameters check 10471 */ 10472 if (lpm_cfg == NULL) { 10473 return (BCM_E_PARAM); 10474 } 10475 10476 BCM_IF_ERROR_RETURN( 10477 _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 10478 lpm_cfg->defip_sub_len, &mem)); 10479 10480 /* 10481 * Write buffer to hw. 10482 */ 10483 rv = bcm_esw_alpm_delete(unit, lpm_cfg); 10484 10485 alpm_trace_log(unit, ALPM_TRACE_OP_DELETE, lpm_cfg, -1, rv); 10486 10487 /* 10488 * If route deleted, decrement total number of routes. 10489 */ 10490 if (rv >= 0) { 10491 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6); 10492 } 10493 return rv; 10494 } 10495 10496 /* 10497 * Function: 10498 * bcm_th_alpm_update_match 10499 * Purpose: 10500 * Update/Delete all entries in defip table matching a certain rule. 10501 * Parameters: 10502 * unit - (IN)SOC unit number. 10503 * trv_data - (IN)Delete pattern + compare,act,notify routines. 10504 * Returns: 10505 * BCM_E_XXX 10506 */ 10507 int 10508 bcm_th_alpm_update_match(int unit, _bcm_l3_trvrs_data_t * trv_data) 10509 { 10510 int rv = BCM_E_NONE; 10511 10512 rv = bcm_esw_alpm_update_match(unit, trv_data); 10513 return (rv); 10514 } 10515 #endif /* BCM_TOMAHAWK_SUPPORT */ 10516 10517 #endif /* ALPM_ENABLE */ 10518 10519 /* 10520 * Function: 10521 * bcm_td2_ecmp_rh_deinit 10522 * Purpose: 10523 * Deallocate ECMP resilient hashing internal data structures 10524 * Parameters: 10525 * unit - (IN) SOC unit number. 10526 * Returns: 10527 * BCM_E_xxx 10528 */ 10529 void 10530 bcm_td2_ecmp_rh_deinit(int unit) 10531 { 10532 if (_td2_ecmp_rh_info[unit]) { 10533 if (_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap) { 10534 sal_free(_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap); 10535 _td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap = NULL; 10536 } 10537 sal_free(_td2_ecmp_rh_info[unit]); 10538 _td2_ecmp_rh_info[unit] = NULL; 10539 } 10540 } 10541 10542 /* 10543 * Function: 10544 * bcm_td2_ecmp_rh_init 10545 * Purpose: 10546 * Initialize ECMP resilient hashing internal data structures 10547 * Parameters: 10548 * unit - (IN) SOC unit number. 10549 * Returns: 10550 * BCM_E_xxx 10551 */ 10552 int 10553 bcm_td2_ecmp_rh_init(int unit) 10554 { 10555 int num_ecmp_rh_flowset_entries; 10556 10557 bcm_td2_ecmp_rh_deinit(unit); 10558 10559 _td2_ecmp_rh_info[unit] = sal_alloc(sizeof(_td2_ecmp_rh_info_t), 10560 "_td2_ecmp_rh_info"); 10561 if (_td2_ecmp_rh_info[unit] == NULL) { 10562 return BCM_E_MEMORY; 10563 } 10564 sal_memset(_td2_ecmp_rh_info[unit], 0, sizeof(_td2_ecmp_rh_info_t)); 10565 10566 /* The LAG and ECMP resilient hash features share the same flow set table. 10567 * The table can be configured in one of 3 modes: 10568 * - dedicated to LAG resilient hashing, 10569 * - dedicated to ECMP resilient hashing, 10570 * - split evenly between LAG and ECMP resilient hashing. 10571 * The mode was configured during Trident2 initialization. 10572 */ 10573 num_ecmp_rh_flowset_entries = soc_mem_index_count(unit, RH_ECMP_FLOWSETm); 10574 10575 #ifdef BCM_MONTEREY_SUPPORT 10576 if (SOC_IS_MONTEREY(unit)) { 10577 _td2_ecmp_rh_info[unit]->ecmp_block_size = 3; 10578 _td2_ecmp_rh_info[unit]->ecmp_rand_seed_shift = 22; 10579 } else 10580 #endif 10581 { 10582 _td2_ecmp_rh_info[unit]->ecmp_block_size = 6; 10583 _td2_ecmp_rh_info[unit]->ecmp_rand_seed_shift = 16; 10584 } 10585 10586 /* Each bit in ecmp_rh_flowset_block_bitmap corresponds to a block of 64 10587 * resilient hashing flow set table entries. 10588 */ 10589 _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks = 10590 num_ecmp_rh_flowset_entries >> _td2_ecmp_rh_info[unit]->ecmp_block_size; 10591 if (_td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks > 0) { 10592 _td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap = 10593 sal_alloc(SHR_BITALLOCSIZE(_td2_ecmp_rh_info[unit]-> 10594 num_ecmp_rh_flowset_blocks), 10595 "ecmp_rh_flowset_block_bitmap"); 10596 if (_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap == NULL) { 10597 bcm_td2_ecmp_rh_deinit(unit); 10598 return BCM_E_MEMORY; 10599 } 10600 sal_memset(_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap, 0, 10601 SHR_BITALLOCSIZE(_td2_ecmp_rh_info[unit]-> 10602 num_ecmp_rh_flowset_blocks)); 10603 } 10604 10605 /* Set the seed for the pseudo-random number generator */ 10606 _td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed = sal_time_usecs(); 10607 10608 /* Clear flow set table entries */ 10609 SOC_IF_ERROR_RETURN 10610 (soc_mem_clear(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, TRUE)); 10611 10612 return BCM_E_NONE; 10613 } 10614 10615 /* 10616 * Function: 10617 * _bcm_td2_ecmp_rh_dynamic_size_encode 10618 * Purpose: 10619 * Encode ECMP resilient hashing flow set size. 10620 * Parameters: 10621 * dynamic_size - (IN) Number of flow sets. 10622 * encoded_value - (OUT) Encoded value. 10623 * Returns: 10624 * BCM_E_xxx 10625 */ 10626 STATIC int 10627 _bcm_td2_ecmp_rh_dynamic_size_encode(int unit, int dynamic_size, int *encoded_value) 10628 { 10629 #ifdef BCM_MONTEREY_SUPPORT 10630 if (SOC_IS_MONTEREY(unit)) { 10631 return _bcm_monterey_ecmp_rh_dynamic_size_encode(dynamic_size, 10632 encoded_value); 10633 } 10634 #endif 10635 switch (dynamic_size) { 10636 case 64: 10637 *encoded_value = 1; 10638 break; 10639 case 128: 10640 *encoded_value = 2; 10641 break; 10642 case 256: 10643 *encoded_value = 3; 10644 break; 10645 case 512: 10646 *encoded_value = 4; 10647 break; 10648 case 1024: 10649 *encoded_value = 5; 10650 break; 10651 case 2048: 10652 *encoded_value = 6; 10653 break; 10654 case 4096: 10655 *encoded_value = 7; 10656 break; 10657 case 8192: 10658 *encoded_value = 8; 10659 break; 10660 case 16384: 10661 *encoded_value = 9; 10662 break; 10663 case 32768: 10664 *encoded_value = 10; 10665 break; 10666 case 65536: 10667 *encoded_value = 11; 10668 break; 10669 default: 10670 return BCM_E_PARAM; 10671 } 10672 10673 return BCM_E_NONE; 10674 } 10675 10676 /* 10677 * Function: 10678 * _bcm_td2_ecmp_rh_dynamic_size_decode 10679 * Purpose: 10680 * Decode ECMP resilient hashing flow set size. 10681 * Parameters: 10682 * encoded_value - (IN) Encoded value. 10683 * dynamic_size - (OUT) Number of flow sets. 10684 * Returns: 10685 * BCM_E_xxx 10686 */ 10687 STATIC int 10688 _bcm_td2_ecmp_rh_dynamic_size_decode(int unit, int encoded_value, int *dynamic_size) 10689 { 10690 #ifdef BCM_MONTEREY_SUPPORT 10691 if (SOC_IS_MONTEREY(unit)) { 10692 return _bcm_monterey_ecmp_rh_dynamic_size_decode(encoded_value, 10693 dynamic_size); 10694 } 10695 #endif 10696 #ifdef BCM_HELIX5_SUPPORT 10697 if (SOC_IS_HELIX5(unit)) { 10698 return _bcm_hx5_ecmp_rh_dynamic_size_decode(encoded_value, 10699 dynamic_size); 10700 } 10701 #endif /* BCM_HELIX5_SUPPORT */ 10702 switch (encoded_value) { 10703 case 1: 10704 *dynamic_size = 64; 10705 break; 10706 case 2: 10707 *dynamic_size = 128; 10708 break; 10709 case 3: 10710 *dynamic_size = 256; 10711 break; 10712 case 4: 10713 *dynamic_size = 512; 10714 break; 10715 case 5: 10716 *dynamic_size = 1024; 10717 break; 10718 case 6: 10719 *dynamic_size = 2048; 10720 break; 10721 case 7: 10722 *dynamic_size = 4096; 10723 break; 10724 case 8: 10725 *dynamic_size = 8192; 10726 break; 10727 case 9: 10728 *dynamic_size = 16384; 10729 break; 10730 case 10: 10731 *dynamic_size = 32768; 10732 break; 10733 case 11: 10734 *dynamic_size = 65536; 10735 break; 10736 default: 10737 return BCM_E_INTERNAL; 10738 } 10739 10740 return BCM_E_NONE; 10741 } 10742 10743 /* 10744 * Function: 10745 * _bcm_td2_ecmp_rh_free_resource 10746 * Purpose: 10747 * Free resources for an ECMP resilient hashing group. 10748 * Parameters: 10749 * unit - (IN) SOC unit number. 10750 * ecmp_group - (IN) ECMP group ID. 10751 * Returns: 10752 * BCM_E_xxx 10753 */ 10754 STATIC int 10755 _bcm_td2_ecmp_rh_free_resource(int unit, int ecmp_group) 10756 { 10757 int rv = BCM_E_NONE; 10758 ecmp_count_entry_t ecmp_count_entry; 10759 int flow_set_size; 10760 int entry_base_ptr; 10761 int num_entries; 10762 int block_base_ptr; 10763 int num_blocks; 10764 int alloc_size; 10765 uint32 *buf_ptr = NULL; 10766 int index_min, index_max, enhanced_hashing = 1; 10767 soc_field_t enhanced_hashing_fld; 10768 uint32 rval; 10769 10770 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) { 10771 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 10772 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 10773 RH_DLB_SELECTIONf)) { 10774 /* ECMP resilient hashing is not enabled chip-wide. */ 10775 return BCM_E_NONE; 10776 } 10777 } 10778 10779 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, 10780 ecmp_group, &ecmp_count_entry)); 10781 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){ 10782 enhanced_hashing_fld = LB_MODEf; 10783 enhanced_hashing = 4; 10784 } else { 10785 enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf; 10786 } 10787 if (soc_L3_ECMP_COUNTm_field32_get(unit, 10788 &ecmp_count_entry, enhanced_hashing_fld)!= enhanced_hashing) { 10789 /* Either (1) resilient hashing is not enabled on this ECMP 10790 * group, or (2) resilient hashing is enabled with no members. 10791 * For case (2), L3_ECMP_COUNT.FLOW_SET_SIZE needs to be cleared. 10792 */ 10793 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 10794 RH_FLOW_SET_SIZEf, 0); 10795 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, 10796 ecmp_group, &ecmp_count_entry)); 10797 return BCM_E_NONE; 10798 } 10799 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, 10800 &ecmp_count_entry, RH_FLOW_SET_SIZEf); 10801 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, 10802 &ecmp_count_entry, RH_FLOW_SET_BASEf); 10803 10804 /* Clear resilient hashing fields */ 10805 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 10806 enhanced_hashing_fld, 0); 10807 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 10808 RH_FLOW_SET_BASEf, 0); 10809 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 10810 RH_FLOW_SET_SIZEf, 0); 10811 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, 10812 ecmp_group, &ecmp_count_entry)); 10813 10814 /* Clear flow set table entries */ 10815 BCM_IF_ERROR_RETURN 10816 (_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries)); 10817 alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t); 10818 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries"); 10819 if (NULL == buf_ptr) { 10820 return BCM_E_MEMORY; 10821 } 10822 sal_memset(buf_ptr, 0, alloc_size); 10823 index_min = entry_base_ptr; 10824 index_max = index_min + num_entries - 1; 10825 rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, 10826 index_min, index_max, buf_ptr); 10827 if (SOC_FAILURE(rv)) { 10828 soc_cm_sfree(unit, buf_ptr); 10829 return rv; 10830 } 10831 soc_cm_sfree(unit, buf_ptr); 10832 10833 /* Free flow set table resources */ 10834 block_base_ptr = entry_base_ptr >> \ 10835 _td2_ecmp_rh_info[unit]->ecmp_block_size ; 10836 num_blocks = num_entries >> \ 10837 _td2_ecmp_rh_info[unit]->ecmp_block_size; 10838 _BCM_ECMP_RH_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks); 10839 10840 10841 #ifdef BCM_TRIDENT3_SUPPORT 10842 if (soc_feature(unit, soc_feature_td3_dlb)) { 10843 ecmp_grp_enhanced_hashing[unit][ecmp_group] = 0; 10844 } 10845 #endif 10846 return BCM_E_NONE; 10847 } 10848 10849 /* 10850 * Function: 10851 * _bcm_td2_ecmp_rh_dynamic_size_set 10852 * Purpose: 10853 * Set the dynamic size for an ECMP resilient hashing group with 10854 * no members. 10855 * Parameters: 10856 * unit - (IN) SOC unit number. 10857 * ecmp_group - (IN) ECMP group ID. 10858 * dynamic_size - (IN) Number of flow sets. 10859 * Returns: 10860 * BCM_E_xxx 10861 */ 10862 STATIC int 10863 _bcm_td2_ecmp_rh_dynamic_size_set(int unit, int ecmp_group, int dynamic_size) 10864 { 10865 ecmp_count_entry_t ecmp_count_entry; 10866 int flow_set_size, enhanced_hashing = 1; 10867 soc_field_t enhanced_hashing_fld; 10868 10869 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group, 10870 &ecmp_count_entry)); 10871 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){ 10872 enhanced_hashing_fld = LB_MODEf; 10873 enhanced_hashing = 4; 10874 } else { 10875 enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf; 10876 } 10877 if (soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 10878 enhanced_hashing_fld) == enhanced_hashing) { 10879 /* Not expecting resilient hashing to be enabled */ 10880 return BCM_E_INTERNAL; 10881 } 10882 10883 BCM_IF_ERROR_RETURN 10884 (_bcm_td2_ecmp_rh_dynamic_size_encode(unit, dynamic_size, &flow_set_size)); 10885 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, RH_FLOW_SET_SIZEf, 10886 flow_set_size); 10887 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_group, 10888 &ecmp_count_entry)); 10889 10890 return BCM_E_NONE; 10891 } 10892 10893 /* 10894 * Function: 10895 * _bcm_td2_ecmp_rh_rand_get 10896 * Purpose: 10897 * Get a random number between 0 and the given max value. 10898 * Parameters: 10899 * unit - (IN) SOC unit number. 10900 * rand_max - (IN) Maximum random number. 10901 * rand_num - (OUT) Random number. 10902 * Returns: 10903 * BCM_E_xxx 10904 * Notes: 10905 * This procedure uses the pseudo-random number generator algorithm 10906 * suggested by the C standard. 10907 */ 10908 STATIC int 10909 _bcm_td2_ecmp_rh_rand_get(int unit, int rand_max, int *rand_num) 10910 { 10911 int modulus; 10912 int rand_seed_shift; 10913 10914 if (rand_max < 0) { 10915 return BCM_E_PARAM; 10916 } 10917 10918 if (NULL == rand_num) { 10919 return BCM_E_PARAM; 10920 } 10921 10922 /* Make sure the modulus does not exceed limit. For instance, 10923 * if the 32-bit rand_seed is shifted to the right by 16 bits before 10924 * the modulo operation, the modulus should not exceed 1 << 16. 10925 */ 10926 modulus = rand_max + 1; 10927 rand_seed_shift = _td2_ecmp_rh_info[unit]->ecmp_rand_seed_shift; 10928 if (modulus > (1 << (32 - rand_seed_shift))) { 10929 return BCM_E_PARAM; 10930 } 10931 10932 _td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed = 10933 _td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed * 1103515245 + 12345; 10934 10935 *rand_num = (_td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed >> rand_seed_shift) % 10936 modulus; 10937 10938 return BCM_E_NONE; 10939 } 10940 10941 /* 10942 * Function: 10943 * _bcm_td2_ecmp_rh_member_choose 10944 * Purpose: 10945 * Choose a member of the ECMP group. 10946 * Parameters: 10947 * unit - (IN) SOC unit number. 10948 * num_members - (IN) Number of members to choose from. 10949 * entry_count_arr - (IN/OUT) An array keeping track of how many 10950 * flow set entries have been assigned 10951 * to each member. 10952 * max_entry_count - (IN/OUT) The maximum number of flow set entries 10953 * that can be assigned to a member. 10954 * chosen_index - (OUT) The index of the chosen member. 10955 * Returns: 10956 * BCM_E_xxx 10957 */ 10958 STATIC int 10959 _bcm_td2_ecmp_rh_member_choose(int unit, int num_members, int *entry_count_arr, 10960 int *max_entry_count, int *chosen_index) 10961 { 10962 int member_index; 10963 int next_index; 10964 10965 *chosen_index = 0; 10966 10967 /* Choose a random member index */ 10968 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_rand_get(unit, num_members - 1, 10969 &member_index)); 10970 10971 if (entry_count_arr[member_index] < *max_entry_count) { 10972 entry_count_arr[member_index]++; 10973 *chosen_index = member_index; 10974 } else { 10975 /* The randomly chosen member has reached the maximum 10976 * flow set entry count. Choose the next member that 10977 * has not reached the maximum entry count. 10978 */ 10979 next_index = (member_index + 1) % num_members; 10980 while (next_index != member_index) { 10981 if (entry_count_arr[next_index] < *max_entry_count) { 10982 entry_count_arr[next_index]++; 10983 *chosen_index = next_index; 10984 break; 10985 } else { 10986 next_index = (next_index + 1) % num_members; 10987 } 10988 } 10989 if (next_index == member_index) { 10990 /* All members have reached the maximum flow set entry 10991 * count. This scenario occurs when dividing the number of 10992 * flow set entries by the number of members results 10993 * in a non-zero remainder. The remainder flow set entries 10994 * will be distributed among members, at most 1 remainder 10995 * entry per member. 10996 */ 10997 (*max_entry_count)++; 10998 if (entry_count_arr[member_index] < *max_entry_count) { 10999 entry_count_arr[member_index]++; 11000 *chosen_index = member_index; 11001 } else { 11002 /* It's possible that the member's entry count equals 11003 * to the incremented value of max_entry_count, when 11004 * this procedure is invoked by 11005 * _bcm_td2_ecmp_rh_populate_empty_entries. 11006 */ 11007 next_index = (member_index + 1) % num_members; 11008 while (next_index != member_index) { 11009 if (entry_count_arr[next_index] < *max_entry_count) { 11010 entry_count_arr[next_index]++; 11011 *chosen_index = next_index; 11012 break; 11013 } else { 11014 next_index = (next_index + 1) % num_members; 11015 } 11016 } 11017 if (next_index == member_index) { 11018 return BCM_E_INTERNAL; 11019 } 11020 } 11021 } 11022 } 11023 11024 return BCM_E_NONE; 11025 } 11026 11027 /* 11028 * Function: 11029 * _bcm_td2_ecmp_rh_set 11030 * Purpose: 11031 * Configure an ECMP resilient hashing group. 11032 * Parameters: 11033 * unit - (IN) SOC unit number. 11034 * ecmp - (IN) ECMP group info. 11035 * intf_count - (IN) Number of elements in intf_array. 11036 * intf_array - (IN) Array of Egress forwarding objects. 11037 * Returns: 11038 * BCM_E_xxx 11039 */ 11040 STATIC int 11041 _bcm_td2_ecmp_rh_set(int unit, 11042 bcm_l3_egress_ecmp_t *ecmp, 11043 int intf_count, 11044 bcm_if_t *intf_array) 11045 { 11046 int rv = BCM_E_NONE; 11047 int ecmp_group; 11048 int num_blocks; 11049 int total_blocks; 11050 int max_block_base_ptr; 11051 int block_base_ptr = 0; 11052 int entry_base_ptr; 11053 SHR_BITDCL occupied; 11054 int alloc_size; 11055 uint32 *buf_ptr = NULL; 11056 int *entry_count_arr = NULL; 11057 int max_entry_count; 11058 int chosen_index; 11059 int i; 11060 rh_ecmp_flowset_entry_t *flowset_entry; 11061 int offset; 11062 int next_hop_index; 11063 int index_min, index_max; 11064 ecmp_count_entry_t ecmp_count_entry; 11065 int flow_set_size, enhanced_hashing = 1; 11066 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 11067 _bcm_l3_bookkeeping_t *l3_bk_info = &_bcm_l3_bk_info[unit]; 11068 #endif 11069 soc_field_t enhanced_hashing_fld; 11070 11071 if (ecmp == NULL || 11072 ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 11073 return BCM_E_PARAM; 11074 } 11075 11076 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 11077 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 11078 } else { 11079 return BCM_E_PARAM; 11080 } 11081 11082 if (intf_count > 0 && intf_array == NULL) { 11083 return BCM_E_PARAM; 11084 } 11085 11086 if (intf_count == 0) { 11087 /* Store the dynamic_size in hardware */ 11088 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_set(unit, 11089 ecmp_group, ecmp->dynamic_size)); 11090 return BCM_E_NONE; 11091 } 11092 11093 /* Find a contiguous region of flow set table that's large 11094 * enough to hold the requested number of flow sets. 11095 * The flow set table is allocated in 64-entry blocks. 11096 */ 11097 num_blocks = ecmp->dynamic_size >> _td2_ecmp_rh_info[unit]->ecmp_block_size; 11098 total_blocks = _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks; 11099 LOG_DEBUG(BSL_LS_SOC_L3, (BSL_META_U(unit, 11100 "Total_blocks = %d , num_blocks = %d\n "), total_blocks, num_blocks)); 11101 11102 if (num_blocks > total_blocks) { 11103 return BCM_E_RESOURCE; 11104 } 11105 max_block_base_ptr = total_blocks - num_blocks; 11106 11107 /* 11108 * In case of Riot or Multi-Layer ECMP, RH_ECMP_FLOWSET table is divided into two halves. 11109 * One half goes to overlay and other goes to underlay range. 11110 * When ECMP is created then user tells the software that which range 11111 * should be used. SDK will test the blocks only in that range. 11112 */ 11113 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 11114 if ( 11115 #if defined(BCM_RIOT_SUPPORT) 11116 (l3_bk_info->riot_enable) || 11117 #endif 11118 BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 11119 if (ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) { 11120 block_base_ptr = 0; 11121 max_block_base_ptr = (l3_bk_info->l3_ecmp_rh_overlay_entries >> \ 11122 _td2_ecmp_rh_info[unit]->ecmp_block_size) 11123 - num_blocks; 11124 LOG_DEBUG(BSL_LS_SOC_L3, (BSL_META_U(unit, 11125 "Total_blocks = %d , num_blocks = %d\n "), 11126 total_blocks, num_blocks)); 11127 11128 } else { 11129 block_base_ptr = (l3_bk_info->l3_ecmp_rh_overlay_entries >> \ 11130 _td2_ecmp_rh_info[unit]->ecmp_block_size); 11131 max_block_base_ptr = total_blocks; 11132 } 11133 } 11134 #endif 11135 for (; block_base_ptr <= max_block_base_ptr; block_base_ptr++) { 11136 /* Check if the contiguous region of flow set table from 11137 * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 11138 */ 11139 _BCM_ECMP_RH_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks, 11140 occupied); 11141 if (!occupied) { 11142 break; 11143 } 11144 } 11145 if (block_base_ptr > max_block_base_ptr) { 11146 /* A contiguous region of the desired size could not be found in 11147 * flow set table. 11148 */ 11149 return BCM_E_RESOURCE; 11150 } 11151 #ifdef BCM_TRIDENT3_SUPPORT 11152 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){ 11153 if (soc_mem_index_count(unit, RH_ECMP_FLOWSETm)) { 11154 SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, ENHANCED_HASHING_CONTROLr, 11155 REG_PORT_ANY, RH_DLB_SELECTIONf, 1)); 11156 11157 } 11158 } 11159 #endif 11160 11161 /* Configure flow set table */ 11162 alloc_size = ecmp->dynamic_size * sizeof(rh_ecmp_flowset_entry_t); 11163 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries"); 11164 if (NULL == buf_ptr) { 11165 return BCM_E_MEMORY; 11166 } 11167 sal_memset(buf_ptr, 0, alloc_size); 11168 11169 entry_count_arr = sal_alloc(sizeof(int) * intf_count, 11170 "ECMP RH entry count array"); 11171 if (NULL == entry_count_arr) { 11172 soc_cm_sfree(unit, buf_ptr); 11173 return BCM_E_MEMORY; 11174 } 11175 sal_memset(entry_count_arr, 0, sizeof(int) * intf_count); 11176 max_entry_count = ecmp->dynamic_size / intf_count; 11177 11178 for (i = 0; i < ecmp->dynamic_size; i++) { 11179 /* Choose a member of the ECMP */ 11180 rv = _bcm_td2_ecmp_rh_member_choose(unit, intf_count, 11181 entry_count_arr, &max_entry_count, &chosen_index); 11182 if (BCM_FAILURE(rv)) { 11183 soc_cm_sfree(unit, buf_ptr); 11184 sal_free(entry_count_arr); 11185 return rv; 11186 } 11187 11188 /* Set flow set entry */ 11189 flowset_entry = soc_mem_table_idx_to_pointer(unit, 11190 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, buf_ptr, i); 11191 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, VALIDf, 1); 11192 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, 11193 intf_array[chosen_index])) { 11194 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 11195 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, 11196 intf_array[chosen_index])) { 11197 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 11198 } else { 11199 soc_cm_sfree(unit, buf_ptr); 11200 sal_free(entry_count_arr); 11201 return BCM_E_PARAM; 11202 } 11203 next_hop_index = intf_array[chosen_index] - offset; 11204 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 11205 NEXT_HOP_INDEXf, next_hop_index); 11206 } 11207 11208 entry_base_ptr = block_base_ptr << _td2_ecmp_rh_info[unit]->ecmp_block_size; 11209 index_min = entry_base_ptr; 11210 index_max = index_min + ecmp->dynamic_size - 1; 11211 rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, 11212 index_min, index_max, buf_ptr); 11213 if (SOC_FAILURE(rv)) { 11214 soc_cm_sfree(unit, buf_ptr); 11215 sal_free(entry_count_arr); 11216 return rv; 11217 } 11218 soc_cm_sfree(unit, buf_ptr); 11219 sal_free(entry_count_arr); 11220 11221 _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 11222 11223 /* Update ECMP group table */ 11224 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group, 11225 &ecmp_count_entry)); 11226 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){ 11227 enhanced_hashing_fld = LB_MODEf; 11228 enhanced_hashing = 4; 11229 } else { 11230 enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf; 11231 } 11232 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 11233 enhanced_hashing_fld, enhanced_hashing); 11234 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 11235 RH_FLOW_SET_BASEf, entry_base_ptr); 11236 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_encode( 11237 unit, ecmp->dynamic_size, &flow_set_size)); 11238 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, 11239 RH_FLOW_SET_SIZEf, flow_set_size); 11240 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_group, 11241 &ecmp_count_entry)); 11242 11243 #ifdef BCM_TRIDENT3_SUPPORT 11244 if (soc_feature(unit, soc_feature_td3_dlb)) { 11245 ecmp_grp_enhanced_hashing[unit][ecmp_group] = 1; 11246 } 11247 #endif 11248 return BCM_E_NONE; 11249 } 11250 11251 /* 11252 * Function: 11253 * _bcm_td2_ecmp_rh_member_replica_find 11254 * Purpose: 11255 * For each member in the member_array, find others members 11256 * who share the same next hop index. 11257 * Parameters: 11258 * unit - (IN) SOC unit number. 11259 * num_members - (IN) Number of members. 11260 * member_array - (IN/OUT) Array of members. 11261 * Returns: 11262 * BCM_E_XXX 11263 */ 11264 STATIC int 11265 _bcm_td2_ecmp_rh_member_replica_find(int unit, int num_members, 11266 _td2_ecmp_rh_member_t *member_array) 11267 { 11268 int i, k; 11269 11270 if (num_members < 1) { 11271 return BCM_E_PARAM; 11272 } 11273 if (NULL == member_array) { 11274 return BCM_E_PARAM; 11275 } 11276 11277 for (i = 0; i < num_members - 1; i++) { 11278 if (member_array[i].replica_id == 0) { 11279 /* replica_id == 0 indicates first replica. 11280 * Search for other replicas in subsequent members. 11281 */ 11282 for (k = i + 1; k < num_members; k++) { 11283 if (member_array[k].nh_index == member_array[i].nh_index) { 11284 /* Replica found. Assign replica id. */ 11285 member_array[k].replica_id = member_array[i].num_replica; 11286 11287 /* For non-first replicas, set non-applicable fields to -1. */ 11288 member_array[k].num_replica = -1; 11289 member_array[k].next_replica_id = -1; 11290 11291 /* Increment the num_replica field of the first replica */ 11292 member_array[i].num_replica++; 11293 } 11294 } 11295 } 11296 } 11297 11298 return BCM_E_NONE; 11299 } 11300 11301 /* 11302 * Function: 11303 * _bcm_td2_ecmp_rh_member_id_buf_assign 11304 * Purpose: 11305 * For each entry in the flow set entry buffer, match its next hop 11306 * index against the next hop index of a member, then assign the 11307 * matching member's member ID to the entry. 11308 * Parameters: 11309 * unit - (IN) SOC unit number. 11310 * num_members - (IN) Number of members. 11311 * member_array - (IN/OUT) Array of members. 11312 * num_entries - (IN) Number of flow set entries in buffer. 11313 * flowset_buf - (IN) Flow set entry buffer. 11314 * member_id_buf - (OUT) Member ID buffer. 11315 * Returns: 11316 * BCM_E_XXX 11317 */ 11318 STATIC int 11319 _bcm_td2_ecmp_rh_member_id_buf_assign(int unit, int num_members, 11320 _td2_ecmp_rh_member_t *member_array, int num_entries, 11321 uint32 *flowset_buf, int *member_id_buf) 11322 { 11323 int i, k, m; 11324 rh_ecmp_flowset_entry_t *flowset_entry; 11325 int next_hop_index; 11326 11327 for (i = 0; i < num_entries; i++) { 11328 flowset_entry = soc_mem_table_idx_to_pointer(unit, 11329 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i); 11330 if (!soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry, 11331 VALIDf)) { 11332 return BCM_E_INTERNAL; 11333 } 11334 next_hop_index = soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, 11335 flowset_entry, NEXT_HOP_INDEXf); 11336 11337 /* Search the member_array for matching next hop index */ 11338 for (k = 0; k < num_members; k++) { 11339 if (member_array[k].nh_index == next_hop_index) { 11340 if (member_array[k].num_replica == 1) { 11341 /* The next hop index is not shared by other members. */ 11342 member_id_buf[i] = member_array[k].member_id; 11343 break; 11344 } 11345 11346 /* Else there are more than one members sharing the next 11347 * hop index. Assign the member ID of the replica 11348 * indicated by next_replica_id. 11349 */ 11350 for (m = k; m < num_members; m++) { 11351 if ((member_array[m].nh_index == next_hop_index) && 11352 (member_array[m].replica_id == member_array[k].next_replica_id)) { 11353 member_id_buf[i] = member_array[m].member_id; 11354 break; 11355 } 11356 } 11357 if (m == num_members) { 11358 /* Cannot find a matching replica */ 11359 return BCM_E_INTERNAL; 11360 } 11361 11362 /* Increment the next_replica_id field of the first replica */ 11363 member_array[k].next_replica_id = (member_array[k].next_replica_id + 1) % 11364 member_array[k].num_replica; 11365 11366 break; 11367 } 11368 } 11369 if (k == num_members) { 11370 /* Cannot find a member with matching next hop index */ 11371 return BCM_E_INTERNAL; 11372 } 11373 } 11374 11375 return BCM_E_NONE; 11376 } 11377 11378 /* 11379 * Function: 11380 * _bcm_td2_ecmp_rh_add_rebalance 11381 * Purpose: 11382 * Re-balance flow set entries from existing members to the new member. 11383 * For example, if the number of flow set entries is 64, and the number of 11384 * existing members is 6, then each existing member has between 10 and 11 11385 * entries. The entries should be re-assigned from the 6 existing members 11386 * to the new member such that each member will end up with between 9 and 11387 * 10 entries. 11388 * Parameters: 11389 * unit - (IN) SOC unit number. 11390 * num_entries - (IN) Number of flow set entries in buffer. 11391 * flowset_buf - (IN/OUT) Flow set entry buffer. 11392 * member_id_buf - (IN/OUT) Member ID buffer. 11393 * num_members - (IN) Number of members in member_array. 11394 * member_array - (IN) Array of existing members. 11395 * entry_count_array - (IN/OUT) Array of entry counts of existing members. 11396 * new_member - (IN) The member to be added. 11397 * entry_count - (OUT) Entry count of the new member. 11398 * Returns: 11399 * BCM_E_XXX 11400 */ 11401 STATIC int 11402 _bcm_td2_ecmp_rh_add_rebalance(int unit, 11403 int num_entries, uint32 *flowset_buf, int *member_id_buf, 11404 int num_members, _td2_ecmp_rh_member_t *member_array, 11405 int *entry_count_array, 11406 _td2_ecmp_rh_member_t *new_member, int *entry_count) 11407 { 11408 int lower_bound, upper_bound; 11409 int threshold; 11410 int entry_index, next_entry_index; 11411 rh_ecmp_flowset_entry_t *flowset_entry; 11412 int member_id; 11413 int is_new_member; 11414 int member_index = 0; 11415 11416 if (num_entries < 1) { 11417 return BCM_E_PARAM; 11418 } 11419 if (NULL == flowset_buf || NULL == member_id_buf) { 11420 return BCM_E_PARAM; 11421 } 11422 if (num_members < 1) { 11423 return BCM_E_PARAM; 11424 } 11425 if (NULL == member_array) { 11426 return BCM_E_PARAM; 11427 } 11428 if (NULL == entry_count_array) { 11429 return BCM_E_PARAM; 11430 } 11431 if (NULL == new_member) { 11432 return BCM_E_PARAM; 11433 } 11434 if (NULL == entry_count) { 11435 return BCM_E_PARAM; 11436 } 11437 11438 lower_bound = num_entries / (num_members + 1); 11439 upper_bound = (num_entries % (num_members + 1)) ? 11440 (lower_bound + 1) : lower_bound; 11441 threshold = upper_bound; 11442 *entry_count = 0; 11443 while (*entry_count < lower_bound) { 11444 /* Pick a random entry in the flow set entry buffer */ 11445 BCM_IF_ERROR_RETURN 11446 (_bcm_td2_ecmp_rh_rand_get(unit, num_entries - 1, &entry_index)); 11447 flowset_entry = soc_mem_table_idx_to_pointer(unit, RH_ECMP_FLOWSETm, 11448 rh_ecmp_flowset_entry_t *, flowset_buf, entry_index); 11449 member_id = member_id_buf[entry_index]; 11450 11451 /* Determine if the randomly picked entry contains the new member. 11452 * If not, determine the existing member index. 11453 */ 11454 if (member_id == new_member->member_id) { 11455 is_new_member = TRUE; 11456 } else { 11457 is_new_member = FALSE; 11458 11459 /* In the member_array, it's assumed that each array element's 11460 * member_id matches the element's array index. 11461 */ 11462 member_index = member_id; 11463 } 11464 11465 if (!is_new_member && (entry_count_array[member_index] > threshold)) { 11466 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 11467 NEXT_HOP_INDEXf, new_member->nh_index); 11468 member_id_buf[entry_index] = new_member->member_id; 11469 entry_count_array[member_index]--; 11470 (*entry_count)++; 11471 } else { 11472 /* Either the member of the randomly chosen entry is 11473 * the same as the new member, or the member is an existing 11474 * member and its entry count has decreased to threshold. 11475 * In both cases, find the next entry that contains a 11476 * member that's not the new member and whose entry count 11477 * has not decreased to threshold. 11478 */ 11479 next_entry_index = (entry_index + 1) % num_entries; 11480 while (next_entry_index != entry_index) { 11481 flowset_entry = soc_mem_table_idx_to_pointer(unit, 11482 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, 11483 flowset_buf, next_entry_index); 11484 member_id = member_id_buf[next_entry_index]; 11485 11486 /* Determine if the entry contains the new member. 11487 * If not, determine the existing member index. 11488 */ 11489 if (member_id == new_member->member_id) { 11490 is_new_member = TRUE; 11491 } else { 11492 is_new_member = FALSE; 11493 11494 /* In the member_array, it's assumed that each array element's 11495 * member_id matches the array index of the element. 11496 */ 11497 member_index = member_id; 11498 } 11499 11500 if (!is_new_member && 11501 (entry_count_array[member_index] > threshold)) { 11502 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 11503 NEXT_HOP_INDEXf, new_member->nh_index); 11504 member_id_buf[next_entry_index] = new_member->member_id; 11505 entry_count_array[member_index]--; 11506 (*entry_count)++; 11507 break; 11508 } else { 11509 next_entry_index = (next_entry_index + 1) % num_entries; 11510 } 11511 } 11512 if (next_entry_index == entry_index) { 11513 /* The entry count of all existing members has decreased 11514 * to threshold. The entry count of the new member has 11515 * not yet increased to lower_bound. Lower the threshold. 11516 */ 11517 threshold--; 11518 } 11519 } 11520 } 11521 11522 return BCM_E_NONE; 11523 } 11524 11525 /* 11526 * Function: 11527 * _bcm_td2_ecmp_rh_clear_by_member_id_th 11528 * Purpose: 11529 * In the given flow set entry buffer, clear entries whose 11530 * member ID is greater than or equal to the given member ID threshold. 11531 * Also, keep track of entry count for each member ID smaller 11532 * than the given member ID threshold. 11533 * Parameters: 11534 * unit - (IN) SOC unit number. 11535 * num_entries - (IN) Number of flow set entries in buffer. 11536 * flowset_buf - (IN/OUT) Flow set entry buffer. 11537 * member_id_buf - (IN/OUT) Member ID buffer. 11538 * member_id_th - (IN) Member ID threshold. 11539 * array_size - (IN) Number of elements in entry_count_array. 11540 * entry_count_array - (OUT) Array of entry counts for member IDs not cleared. 11541 * Returns: 11542 * BCM_E_XXX 11543 */ 11544 STATIC int 11545 _bcm_td2_ecmp_rh_clear_by_member_id_th(int unit, 11546 int num_entries, uint32 *flowset_buf, int *member_id_buf, 11547 int member_id_th, int array_size, int *entry_count_array) 11548 { 11549 int i; 11550 rh_ecmp_flowset_entry_t *flowset_entry; 11551 int member_id; 11552 11553 if (num_entries < 1) { 11554 return BCM_E_PARAM; 11555 } 11556 if (NULL == flowset_buf || NULL == member_id_buf) { 11557 return BCM_E_PARAM; 11558 } 11559 if (member_id_th != array_size) { 11560 return BCM_E_PARAM; 11561 } 11562 if (NULL == entry_count_array) { 11563 return BCM_E_PARAM; 11564 } 11565 11566 for (i = 0; i < num_entries; i++) { 11567 flowset_entry = soc_mem_table_idx_to_pointer(unit, 11568 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i); 11569 if (!soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry, 11570 VALIDf)) { 11571 return BCM_E_INTERNAL; 11572 } 11573 member_id = member_id_buf[i]; 11574 11575 if (member_id >= member_id_th) { 11576 /* Clear the valid bit */ 11577 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 11578 VALIDf, 0); 11579 11580 /* Do not clear the next hop index, which is needed later by 11581 * _bcm_td2_ecmp_rh_populate_empty_entries. 11582 */ 11583 11584 /* Clear member ID */ 11585 member_id_buf[i] = -1; 11586 } else { 11587 entry_count_array[member_id]++; 11588 } 11589 } 11590 11591 return BCM_E_NONE; 11592 } 11593 11594 /* 11595 * Function: 11596 * _bcm_td2_ecmp_rh_populate_empty_entries 11597 * Purpose: 11598 * In the given flow set entry buffer, populate entries not 11599 * containing a member, such that maximal balance is achieve 11600 * among members in member_array. 11601 * Parameters: 11602 * unit - (IN) SOC unit number. 11603 * num_entries - (IN) Number of flow set entries in buffer. 11604 * flowset_buf - (IN/OUT) Flow set entry buffer. 11605 * member_id_buf - (IN/OUT) Member ID buffer. 11606 * num_members - (IN) Number of elements in member_array and 11607 * entry_count_array. 11608 * member_array - (IN) Array of members. 11609 * entry_count_array - (IN/OUT) Array of entry counts. 11610 * num_shared_members - (IN) Number of members in member_array that 11611 * are shared by the old and the new ECMP 11612 * groups. 11613 * Returns: 11614 * BCM_E_XXX 11615 */ 11616 STATIC int 11617 _bcm_td2_ecmp_rh_populate_empty_entries(int unit, 11618 int num_entries, uint32 *flowset_buf, int *member_id_buf, 11619 int num_members, _td2_ecmp_rh_member_t *member_array, 11620 int *entry_count_array, int num_shared_members) 11621 { 11622 int max_entry_count; 11623 int i, k; 11624 rh_ecmp_flowset_entry_t *flowset_entry; 11625 int next_hop_index; 11626 int chosen_index = 0; 11627 11628 if (num_entries < 1) { 11629 return BCM_E_PARAM; 11630 } 11631 if (NULL == flowset_buf || NULL == member_id_buf) { 11632 return BCM_E_PARAM; 11633 } 11634 if (0 == num_members) { 11635 return BCM_E_PARAM; 11636 } 11637 if (NULL == member_array) { 11638 return BCM_E_PARAM; 11639 } 11640 if (NULL == entry_count_array) { 11641 return BCM_E_PARAM; 11642 } 11643 if (num_shared_members > num_members) { 11644 return BCM_E_PARAM; 11645 } 11646 11647 max_entry_count = num_entries / num_members; 11648 for (i = 0; i < num_entries; i++) { 11649 flowset_entry = soc_mem_table_idx_to_pointer(unit, 11650 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i); 11651 if (soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry, 11652 VALIDf)) { 11653 /* Skip valid entries */ 11654 continue; 11655 } 11656 11657 /* First, try to find a shared member whose next hop index 11658 * matches the current entry and whose entry count has not reached 11659 * max_entry_count. Doing so minimizes flow-to-member reassignments. 11660 */ 11661 next_hop_index = soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, 11662 flowset_entry, NEXT_HOP_INDEXf); 11663 for (k = 0; k < num_shared_members; k++) { 11664 if (member_array[k].nh_index == next_hop_index) { 11665 if (entry_count_array[k] < max_entry_count) { 11666 entry_count_array[k]++; 11667 chosen_index = k; 11668 break; 11669 } 11670 } 11671 } 11672 if (k == num_shared_members) { 11673 /* Cannot find a shared member with matching next hop index and 11674 * with entry count < max_entry_count. Randomly choose a member. 11675 */ 11676 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_member_choose(unit, num_members, 11677 entry_count_array, &max_entry_count, &chosen_index)); 11678 } 11679 11680 /* Set flow set entry */ 11681 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, VALIDf, 1); 11682 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 11683 NEXT_HOP_INDEXf, member_array[chosen_index].nh_index); 11684 member_id_buf[i] = member_array[chosen_index].member_id; 11685 } 11686 11687 return BCM_E_NONE; 11688 } 11689 11690 /* 11691 * Function: 11692 * _bcm_td2_ecmp_rh_balance_with_min_shared_mod 11693 * Purpose: 11694 * Modify the given flow set entry buffer to achieve balance among 11695 * the shared members and members exclusive to the new ECMP group, 11696 * while keeping modification of entries containing the 11697 * shared members to a minimum. 11698 * Parameters: 11699 * unit - (IN) SOC unit number. 11700 * num_entries - (IN) Number of flow set entries in buffer. 11701 * flowset_buf - (IN/OUT) Flow set entry buffer. Initially, this buffer 11702 * contains the old ECMP group's flow set entries. 11703 * shared_intf_count - (IN) Number of members shared by old and new ECMP 11704 * groups. 11705 * shared_intf_array - (IN) Array of members shared by old and new ECMP 11706 * groups. 11707 * ex_old_intf_count - (IN) Number of members exclusive to old ECMP group. 11708 * ex_old_intf_array - (IN) Array of members exclusive to old ECMP group. 11709 * ex_new_intf_count - (IN) Number of members exclusive to new ECMP group. 11710 * ex_new_intf_array - (IN) Array of members exclusive to new ECMP group. 11711 * Returns: 11712 * BCM_E_XXX 11713 */ 11714 STATIC int 11715 _bcm_td2_ecmp_rh_balance_with_min_shared_mod(int unit, 11716 int num_entries, uint32 *flowset_buf, 11717 int shared_intf_count, bcm_if_t *shared_intf_array, 11718 int ex_old_intf_count, bcm_if_t *ex_old_intf_array, 11719 int ex_new_intf_count, bcm_if_t *ex_new_intf_array) 11720 { 11721 int rv = BCM_E_NONE; 11722 int old_intf_count; 11723 int new_intf_count; 11724 int num_members; 11725 int alloc_size; 11726 _td2_ecmp_rh_member_t *member_array = NULL; 11727 int *entry_count_array = NULL; 11728 int i; 11729 int ex_old_index, ex_new_index; 11730 int *member_id_buf = NULL; 11731 int intf_count; 11732 11733 if (num_entries < 1) { 11734 return BCM_E_PARAM; 11735 } 11736 if (NULL == flowset_buf) { 11737 return BCM_E_PARAM; 11738 } 11739 if (0 == shared_intf_count) { 11740 return BCM_E_PARAM; 11741 } 11742 if (NULL == shared_intf_array) { 11743 return BCM_E_PARAM; 11744 } 11745 if ((ex_old_intf_count > 0) && (NULL == ex_old_intf_array)) { 11746 return BCM_E_PARAM; 11747 } 11748 if ((ex_new_intf_count > 0) && (NULL == ex_new_intf_array)) { 11749 return BCM_E_PARAM; 11750 } 11751 11752 /* Allocate an array of members and an array of entry counts */ 11753 old_intf_count = shared_intf_count + ex_old_intf_count; 11754 new_intf_count = shared_intf_count + ex_new_intf_count; 11755 num_members = (old_intf_count > new_intf_count) ? old_intf_count : new_intf_count; 11756 alloc_size = num_members * sizeof(_td2_ecmp_rh_member_t); 11757 member_array = sal_alloc(alloc_size, "ECMP RH member array"); 11758 if (NULL == member_array) { 11759 rv = BCM_E_MEMORY; 11760 goto cleanup; 11761 } 11762 sal_memset(member_array, 0, alloc_size); 11763 11764 alloc_size = num_members * sizeof(int); 11765 entry_count_array = sal_alloc(alloc_size, "ECMP RH entry count array"); 11766 if (NULL == entry_count_array) { 11767 rv = BCM_E_MEMORY; 11768 goto cleanup; 11769 } 11770 sal_memset(entry_count_array, 0, alloc_size); 11771 11772 /* Initialize the member_array with shared members, followed by members 11773 * exclusive to the old ECMP group. 11774 */ 11775 for (i = 0; i < shared_intf_count; i++) { 11776 member_array[i].nh_index = shared_intf_array[i]; 11777 member_array[i].member_id = i; 11778 member_array[i].num_replica = 1; 11779 member_array[i].replica_id = 0; 11780 member_array[i].next_replica_id = 0; 11781 } 11782 for (i = shared_intf_count; i < old_intf_count; i++) { 11783 ex_old_index = i - shared_intf_count; 11784 member_array[i].nh_index = ex_old_intf_array[ex_old_index]; 11785 member_array[i].member_id = i; 11786 member_array[i].num_replica = 1; 11787 member_array[i].replica_id = 0; 11788 member_array[i].next_replica_id = 0; 11789 } 11790 11791 /* Find members that share the same next hop index, and 11792 * update the replica information in member_array. 11793 */ 11794 rv = _bcm_td2_ecmp_rh_member_replica_find(unit, old_intf_count, 11795 member_array); 11796 if (BCM_FAILURE(rv)) { 11797 goto cleanup; 11798 } 11799 11800 /* Derive a buffer of member IDs by assigning a member ID to each 11801 * entry of the flow set entry buffer. 11802 */ 11803 alloc_size = num_entries * sizeof(int); 11804 member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer"); 11805 if (NULL == member_id_buf) { 11806 rv = BCM_E_MEMORY; 11807 goto cleanup; 11808 } 11809 sal_memset(member_id_buf, 0, alloc_size); 11810 rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, old_intf_count, 11811 member_array, num_entries, flowset_buf, member_id_buf); 11812 if (BCM_FAILURE(rv)) { 11813 goto cleanup; 11814 } 11815 11816 /* Traverse the flow set entry buffer to clear entries with member 11817 * IDs greater than the member IDs of the shared members. Also keep 11818 * track of each shared member's entry count. 11819 */ 11820 rv = _bcm_td2_ecmp_rh_clear_by_member_id_th(unit, num_entries, flowset_buf, 11821 member_id_buf, shared_intf_count, shared_intf_count, 11822 entry_count_array); 11823 if (BCM_FAILURE(rv)) { 11824 goto cleanup; 11825 } 11826 11827 /* Clear from the member_array members exclusive to the old ECMP group. 11828 * Also need to reset share members' replica info. 11829 */ 11830 for (i = shared_intf_count; i < old_intf_count; i++) { 11831 sal_memset(&member_array[i], 0, sizeof(_td2_ecmp_rh_member_t)); 11832 } 11833 for (i = 0; i < shared_intf_count; i++) { 11834 member_array[i].num_replica = 1; 11835 member_array[i].replica_id = 0; 11836 member_array[i].next_replica_id = 0; 11837 } 11838 11839 /* Add to member_array members exclusive to the new ECMP group */ 11840 for (i = shared_intf_count; i < new_intf_count; i++) { 11841 ex_new_index = i - shared_intf_count; 11842 member_array[i].nh_index = ex_new_intf_array[ex_new_index]; 11843 member_array[i].member_id = i; 11844 member_array[i].num_replica = 1; 11845 member_array[i].replica_id = 0; 11846 member_array[i].next_replica_id = 0; 11847 } 11848 11849 /* Find members that share the same next hop index, and 11850 * update the replica information in member_array. 11851 */ 11852 rv = _bcm_td2_ecmp_rh_member_replica_find(unit, new_intf_count, 11853 member_array); 11854 if (BCM_FAILURE(rv)) { 11855 goto cleanup; 11856 } 11857 11858 /* Populate the cleared entries in the flow set entry buffer. 11859 * There're 2 cases: 11860 * 11861 * Case 1: 11862 * If the number of members in the old ECMP group is greater than or 11863 * equal to the number in the new ECMP group, populate the cleared 11864 * entries with shared members and members exclusive to the new ECMP 11865 * group, such that maximal balance is achieved among them. 11866 * 11867 * Case 2: 11868 * If the old ECMP group has fewer members than the new ECMP group, 11869 * populate the cleared entries with N members that are exclusive 11870 * to the new ECMP group, such that N + number of shared members equals 11871 * to the number of members in old ECMP group. 11872 * 11873 * In both cases, the flow set entries containing the shared members 11874 * are unmodified. 11875 */ 11876 if (old_intf_count >= new_intf_count) { 11877 intf_count = new_intf_count; 11878 } else { 11879 intf_count = old_intf_count; 11880 } 11881 rv = _bcm_td2_ecmp_rh_populate_empty_entries(unit, num_entries, flowset_buf, 11882 member_id_buf, intf_count, member_array, entry_count_array, 11883 shared_intf_count); 11884 if (BCM_FAILURE(rv)) { 11885 goto cleanup; 11886 } 11887 11888 /* For any remaining unused members in member_array, move some 11889 * flow set entries from existing members to these remaining 11890 * members, such that maximal balance is achieved. 11891 */ 11892 if (new_intf_count > intf_count) { 11893 for (i = intf_count; i < new_intf_count; i++) { 11894 rv = _bcm_td2_ecmp_rh_add_rebalance(unit, num_entries, flowset_buf, 11895 member_id_buf, i, member_array, entry_count_array, 11896 &member_array[i], &entry_count_array[i]); 11897 if (BCM_FAILURE(rv)) { 11898 goto cleanup; 11899 } 11900 } 11901 } 11902 11903 cleanup: 11904 if (member_array) { 11905 sal_free(member_array); 11906 } 11907 if (entry_count_array) { 11908 sal_free(entry_count_array); 11909 } 11910 if (member_id_buf) { 11911 sal_free(member_id_buf); 11912 } 11913 11914 return rv; 11915 } 11916 11917 /* 11918 * Function: 11919 * _bcm_td2_ecmp_rh_arrange_with_no_shared_entries 11920 * Purpose: 11921 * Arrange the given flow set entry buffer to achieve Maximization of the shared members, 11922 * while entries containing none of shared members. 11923 * Parameters: 11924 * unit - (IN) SOC unit number. 11925 * num_entries - (IN) Number of flow set entries in buffer. 11926 * flowset_buf - (IN/OUT) Flow set entry buffer. Initially, this buffer 11927 * contains the old ECMP group's flow set entries. 11928 * old_intf_count - (IN) Number of members exclusive to old ECMP group. 11929 * old_intf_array - (IN) Array of members exclusive to old ECMP group. 11930 * new_intf_count - (IN) Number of members exclusive to new ECMP group. 11931 * new_intf_array - (IN) Array of members exclusive to new ECMP group. 11932 * shared_intf_count - (OUT) Number of members shared by old and new ECMP 11933 * groups. 11934 * shared_intf_array - (OUT) Array of members shared by old and new ECMP 11935 * groups. 11936 * ex_old_intf_count - (OUT) Number of members exclusive to old ECMP group. 11937 * ex_old_intf_array - (OUT) Array of members exclusive to old ECMP group. 11938 * ex_new_intf_count - (OUT) Number of members exclusive to new ECMP group. 11939 * ex_new_intf_array - (OUT) Array of members exclusive to new ECMP group. 11940 * Returns: 11941 * BCM_E_XXX 11942 */ 11943 STATIC int 11944 _bcm_td2_ecmp_rh_arrange_with_no_shared_entries(int unit, 11945 int num_entries, uint32 *flowset_buf, 11946 int old_intf_count, bcm_if_t *old_intf_array, 11947 int new_intf_count, bcm_if_t *new_intf_array, 11948 int *shared_intf_count, bcm_if_t *shared_intf_array, 11949 int *ex_old_intf_count, bcm_if_t *ex_old_intf_array, 11950 int *ex_new_intf_count, bcm_if_t *ex_new_intf_array) 11951 { 11952 int rv = BCM_E_NONE; 11953 int num_members; 11954 int alloc_size; 11955 _td2_ecmp_rh_member_t *member_array = NULL; 11956 int i; 11957 int *member_id_buf = NULL; 11958 rh_ecmp_flowset_entry_t *flowset_entry; 11959 int member_id; 11960 int max_shared; 11961 11962 if (num_entries < 1) { 11963 return BCM_E_PARAM; 11964 } 11965 if (NULL == flowset_buf) { 11966 return BCM_E_PARAM; 11967 } 11968 if (old_intf_count > 0 && old_intf_array == NULL) { 11969 return BCM_E_PARAM; 11970 } 11971 if (new_intf_count > 0 && new_intf_array == NULL) { 11972 return BCM_E_PARAM; 11973 } 11974 if (NULL == shared_intf_array) { 11975 return BCM_E_PARAM; 11976 } 11977 if (NULL == ex_old_intf_array) { 11978 return BCM_E_PARAM; 11979 } 11980 if (NULL == ex_new_intf_array) { 11981 return BCM_E_PARAM; 11982 } 11983 11984 /* Allocate an array of members and an array of entry counts */ 11985 num_members = old_intf_count; 11986 alloc_size = num_members * sizeof(_td2_ecmp_rh_member_t); 11987 member_array = sal_alloc(alloc_size, "ECMP RH member array"); 11988 if (NULL == member_array) { 11989 rv = BCM_E_MEMORY; 11990 goto cleanup; 11991 } 11992 sal_memset(member_array, 0, alloc_size); 11993 11994 /* Initialize the member_array with shared members, followed by members 11995 * exclusive to the old ECMP group. 11996 */ 11997 for (i = 0; i < num_members; i++) { 11998 member_array[i].nh_index = old_intf_array[i]; 11999 member_array[i].member_id = i; 12000 member_array[i].num_replica = 1; 12001 member_array[i].replica_id = 0; 12002 member_array[i].next_replica_id = 0; 12003 } 12004 12005 /* Find members that share the same next hop index, and 12006 * update the replica information in member_array. 12007 */ 12008 rv = _bcm_td2_ecmp_rh_member_replica_find(unit, old_intf_count, 12009 member_array); 12010 if (BCM_FAILURE(rv)) { 12011 goto cleanup; 12012 } 12013 12014 /* Derive a buffer of member IDs by assigning a member ID to each 12015 * entry of the flow set entry buffer. 12016 */ 12017 alloc_size = num_entries * sizeof(int); 12018 member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer"); 12019 if (NULL == member_id_buf) { 12020 rv = BCM_E_MEMORY; 12021 goto cleanup; 12022 } 12023 sal_memset(member_id_buf, 0, alloc_size); 12024 rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, num_members, 12025 member_array, num_entries, flowset_buf, member_id_buf); 12026 if (BCM_FAILURE(rv)) { 12027 goto cleanup; 12028 } 12029 12030 /* Determine members shared by old and new ECMP groups, and 12031 * members exclusive to the old and the new ECMP groups. 12032 */ 12033 max_shared = (old_intf_count > new_intf_count) ? new_intf_count : 12034 old_intf_count; 12035 12036 for (i = 0; i < num_entries; i++) { 12037 member_id = member_id_buf[i]; 12038 if (member_id >= max_shared) { 12039 continue; 12040 } 12041 flowset_entry = soc_mem_table_idx_to_pointer(unit, 12042 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i); 12043 if (!soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry, 12044 VALIDf)) { 12045 rv = BCM_E_INTERNAL; 12046 goto cleanup; 12047 } 12048 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 12049 NEXT_HOP_INDEXf, new_intf_array[member_id]); 12050 } 12051 12052 *shared_intf_count = max_shared; 12053 sal_memcpy(shared_intf_array, new_intf_array, 12054 *shared_intf_count * sizeof(bcm_if_t)); 12055 12056 if (old_intf_count > new_intf_count) { 12057 *ex_new_intf_count = 0; 12058 *ex_old_intf_count = old_intf_count - *shared_intf_count; 12059 sal_memcpy(ex_old_intf_array, &old_intf_array[*shared_intf_count], 12060 *ex_old_intf_count * sizeof(bcm_if_t)); 12061 } else { 12062 *ex_old_intf_count = 0; 12063 *ex_new_intf_count = new_intf_count - *shared_intf_count; 12064 sal_memcpy(ex_new_intf_array, &new_intf_array[*shared_intf_count], 12065 *ex_new_intf_count * sizeof(bcm_if_t)); 12066 } 12067 12068 cleanup: 12069 if (member_array) { 12070 sal_free(member_array); 12071 } 12072 if (member_id_buf) { 12073 sal_free(member_id_buf); 12074 } 12075 12076 return rv; 12077 } 12078 12079 /* 12080 * Function: 12081 * _bcm_td2_ecmp_rh_add 12082 * Purpose: 12083 * Add a member to an ECMP resilient hashing group. 12084 * Parameters: 12085 * unit - (IN) SOC unit number. 12086 * ecmp - (IN) ECMP group info. 12087 * intf_count - (IN) Number of elements in intf_array. 12088 * intf_array - (IN) Array of resilient hashing eligible members, 12089 * including the member to be added. 12090 * new_intf - (IN) New member to be added. 12091 * Returns: 12092 * BCM_E_xxx 12093 */ 12094 STATIC int 12095 _bcm_td2_ecmp_rh_add(int unit, 12096 bcm_l3_egress_ecmp_t *ecmp, 12097 int intf_count, 12098 bcm_if_t *intf_array, 12099 bcm_if_t new_intf) 12100 { 12101 int rv = BCM_E_NONE; 12102 int ecmp_group; 12103 int offset; 12104 int new_next_hop_index; 12105 int num_existing_members; 12106 ecmp_count_entry_t ecmp_count_entry; 12107 int entry_base_ptr; 12108 int flow_set_size; 12109 int num_entries; 12110 int alloc_size; 12111 uint32 *flowset_buf = NULL; 12112 int index_min, index_max; 12113 _td2_ecmp_rh_member_t *existing_member_arr = NULL; 12114 int i; 12115 int *member_id_buf = NULL; 12116 int *entry_count_arr = NULL; 12117 int member_id; 12118 int lower_bound, upper_bound; 12119 _td2_ecmp_rh_member_t new_member; 12120 int new_member_entry_count; 12121 12122 if (ecmp == NULL || 12123 ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 12124 return BCM_E_PARAM; 12125 } 12126 12127 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 12128 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12129 } else { 12130 return BCM_E_PARAM; 12131 } 12132 12133 if (intf_count == 0 || intf_array == NULL) { 12134 return BCM_E_PARAM; 12135 } 12136 12137 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, new_intf)) { 12138 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 12139 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, new_intf)) { 12140 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 12141 } else { 12142 return BCM_E_PARAM; 12143 } 12144 new_next_hop_index = new_intf - offset; 12145 12146 /* Check that the new member is the last element of the array of 12147 * resilient hashing eligible members. 12148 */ 12149 if (new_intf != intf_array[intf_count - 1]) { 12150 return BCM_E_PARAM; 12151 } 12152 num_existing_members = intf_count - 1; 12153 12154 if (intf_count == 1) { 12155 /* Adding the first member is the same as setting one member */ 12156 return _bcm_td2_ecmp_rh_set(unit, ecmp, intf_count, intf_array); 12157 } 12158 12159 /* Read all the flow set entries of this ECMP resilient hash group */ 12160 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group, 12161 &ecmp_count_entry)); 12162 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 12163 RH_FLOW_SET_BASEf); 12164 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 12165 RH_FLOW_SET_SIZEf); 12166 BCM_IF_ERROR_RETURN 12167 (_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries)); 12168 12169 alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t); 12170 flowset_buf = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries"); 12171 if (NULL == flowset_buf) { 12172 rv = BCM_E_MEMORY; 12173 goto cleanup; 12174 } 12175 sal_memset(flowset_buf, 0, alloc_size); 12176 index_min = entry_base_ptr; 12177 index_max = index_min + num_entries - 1; 12178 rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY, 12179 index_min, index_max, flowset_buf); 12180 if (SOC_FAILURE(rv)) { 12181 goto cleanup; 12182 } 12183 12184 /* Construct an array of existing members */ 12185 alloc_size = num_existing_members * sizeof(_td2_ecmp_rh_member_t); 12186 existing_member_arr = sal_alloc(alloc_size, "ECMP RH member array"); 12187 if (NULL == existing_member_arr) { 12188 rv = BCM_E_MEMORY; 12189 goto cleanup; 12190 } 12191 sal_memset(existing_member_arr, 0, alloc_size); 12192 for (i = 0; i < num_existing_members; i++) { 12193 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) { 12194 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 12195 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) { 12196 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 12197 } else { 12198 rv = BCM_E_PARAM; 12199 goto cleanup; 12200 } 12201 existing_member_arr[i].nh_index = intf_array[i] - offset; 12202 existing_member_arr[i].member_id = i; 12203 existing_member_arr[i].num_replica = 1; 12204 existing_member_arr[i].replica_id = 0; 12205 existing_member_arr[i].next_replica_id = 0; 12206 } 12207 12208 /* Find members that share the same next hop index, and 12209 * update the replica information in existing_member_arr. 12210 */ 12211 rv = _bcm_td2_ecmp_rh_member_replica_find(unit, num_existing_members, 12212 existing_member_arr); 12213 if (BCM_FAILURE(rv)) { 12214 goto cleanup; 12215 } 12216 12217 /* Derive a buffer of member IDs by assigning a member ID to each 12218 * entry of the flow set entry buffer. 12219 */ 12220 alloc_size = num_entries * sizeof(int); 12221 member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer"); 12222 if (NULL == member_id_buf) { 12223 rv = BCM_E_MEMORY; 12224 goto cleanup; 12225 } 12226 sal_memset(member_id_buf, 0, alloc_size); 12227 rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, num_existing_members, 12228 existing_member_arr, num_entries, flowset_buf, member_id_buf); 12229 if (BCM_FAILURE(rv)) { 12230 goto cleanup; 12231 } 12232 12233 /* Compute the number of entries currently assigned to each 12234 * existing member. 12235 */ 12236 alloc_size = num_existing_members * sizeof(int); 12237 entry_count_arr = sal_alloc(alloc_size, "ECMP RH entry count array"); 12238 if (NULL == entry_count_arr) { 12239 rv = BCM_E_MEMORY; 12240 goto cleanup; 12241 } 12242 sal_memset(entry_count_arr, 0, alloc_size); 12243 for (i = 0; i < num_entries; i++) { 12244 member_id = member_id_buf[i]; 12245 12246 /* In this procedure, the member_id happens to be the same as 12247 * the index into the existing_member_arr. 12248 */ 12249 entry_count_arr[member_id]++; 12250 } 12251 12252 /* Check that the distribution of flow set entries among existing members 12253 * is balanced. For instance, if the number of flow set entries is 64, and 12254 * the number of existing members is 6, then every member should have 12255 * between 10 and 11 entries. 12256 */ 12257 lower_bound = num_entries / num_existing_members; 12258 upper_bound = (num_entries % num_existing_members) ? 12259 (lower_bound + 1) : lower_bound; 12260 for (i = 0; i < num_existing_members; i++) { 12261 if (entry_count_arr[i] < lower_bound || 12262 entry_count_arr[i] > upper_bound) { 12263 rv = BCM_E_INTERNAL; 12264 goto cleanup; 12265 } 12266 } 12267 12268 /* Re-balance flow set entries from existing members to the new member */ 12269 sal_memset(&new_member, 0, sizeof(_td2_ecmp_rh_member_t)); 12270 new_member.nh_index = new_next_hop_index; 12271 new_member.member_id = num_existing_members; 12272 rv = _bcm_td2_ecmp_rh_add_rebalance(unit, num_entries, flowset_buf, 12273 member_id_buf, num_existing_members, existing_member_arr, 12274 entry_count_arr, &new_member, &new_member_entry_count); 12275 if (BCM_FAILURE(rv)) { 12276 goto cleanup; 12277 } 12278 12279 /* Write re-balanced flow set entries to hardware */ 12280 rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, 12281 index_min, index_max, flowset_buf); 12282 if (SOC_FAILURE(rv)) { 12283 goto cleanup; 12284 } 12285 12286 cleanup: 12287 if (flowset_buf) { 12288 soc_cm_sfree(unit, flowset_buf); 12289 } 12290 if (member_id_buf) { 12291 sal_free(member_id_buf); 12292 } 12293 if (existing_member_arr) { 12294 sal_free(existing_member_arr); 12295 } 12296 if (entry_count_arr) { 12297 sal_free(entry_count_arr); 12298 } 12299 12300 return rv; 12301 } 12302 12303 /* 12304 * Function: 12305 * _bcm_td2_ecmp_rh_delete 12306 * Purpose: 12307 * Delete a member from an ECMP resilient hashing group. 12308 * Parameters: 12309 * unit - (IN) SOC unit number. 12310 * ecmp - (IN) ECMP group info. 12311 * intf_count - (IN) Number of elements in intf_array. 12312 * intf_array - (IN) Array of resilient hashing eligible members, 12313 * except the member to be deleted. 12314 * leaving_intf - (IN) Member to delete. 12315 * Returns: 12316 * BCM_E_xxx 12317 */ 12318 STATIC int 12319 _bcm_td2_ecmp_rh_delete(int unit, 12320 bcm_l3_egress_ecmp_t *ecmp, 12321 int intf_count, 12322 bcm_if_t *intf_array, 12323 bcm_if_t leaving_intf) 12324 { 12325 int rv = BCM_E_NONE; 12326 int ecmp_group; 12327 int offset; 12328 int leaving_next_hop_index; 12329 ecmp_count_entry_t ecmp_count_entry; 12330 int entry_base_ptr; 12331 int flow_set_size; 12332 int num_entries; 12333 int alloc_size; 12334 uint32 *flowset_buf = NULL; 12335 int index_min, index_max; 12336 int num_existing_members; 12337 _td2_ecmp_rh_member_t *existing_member_arr = NULL; 12338 int i; 12339 int *member_id_buf = NULL; 12340 int *entry_count_arr = NULL; 12341 int lower_bound, upper_bound; 12342 int num_remaining_members; 12343 int threshold; 12344 int leaving_member_id; 12345 rh_ecmp_flowset_entry_t *flowset_entry; 12346 int member_id; 12347 int chosen_index; 12348 12349 if (ecmp == NULL || 12350 ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 12351 return BCM_E_PARAM; 12352 } 12353 12354 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 12355 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12356 } else { 12357 return BCM_E_PARAM; 12358 } 12359 12360 if (intf_count > 0 && intf_array == NULL) { 12361 return BCM_E_PARAM; 12362 } 12363 12364 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, leaving_intf)) { 12365 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 12366 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, leaving_intf)) { 12367 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 12368 } else { 12369 return BCM_E_PARAM; 12370 } 12371 leaving_next_hop_index = leaving_intf - offset; 12372 12373 if (intf_count == 0) { 12374 /* Deleting the last member is the same as freeing all resources */ 12375 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group)); 12376 12377 /* Store the dynamic_size in hardware */ 12378 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_set(unit, ecmp_group, 12379 ecmp->dynamic_size)); 12380 12381 return BCM_E_NONE; 12382 } 12383 12384 /* Read all the flow set entries of this ECMP resilient hash group */ 12385 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group, 12386 &ecmp_count_entry)); 12387 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 12388 RH_FLOW_SET_BASEf); 12389 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 12390 RH_FLOW_SET_SIZEf); 12391 BCM_IF_ERROR_RETURN 12392 (_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries)); 12393 12394 alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t); 12395 flowset_buf = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries"); 12396 if (NULL == flowset_buf) { 12397 return BCM_E_MEMORY; 12398 } 12399 sal_memset(flowset_buf, 0, alloc_size); 12400 index_min = entry_base_ptr; 12401 index_max = index_min + num_entries - 1; 12402 rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY, 12403 index_min, index_max, flowset_buf); 12404 if (SOC_FAILURE(rv)) { 12405 goto cleanup; 12406 } 12407 12408 /* Construct an array of existing members */ 12409 num_existing_members = intf_count + 1; 12410 alloc_size = num_existing_members * sizeof(_td2_ecmp_rh_member_t); 12411 existing_member_arr = sal_alloc(alloc_size, "ECMP RH member array"); 12412 if (NULL == existing_member_arr) { 12413 rv = BCM_E_MEMORY; 12414 goto cleanup; 12415 } 12416 sal_memset(existing_member_arr, 0, alloc_size); 12417 for (i = 0; i < intf_count; i++) { 12418 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) { 12419 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 12420 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) { 12421 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 12422 } else { 12423 rv = BCM_E_PARAM; 12424 goto cleanup; 12425 } 12426 existing_member_arr[i].nh_index = intf_array[i] - offset; 12427 existing_member_arr[i].member_id = i; 12428 existing_member_arr[i].num_replica = 1; 12429 existing_member_arr[i].replica_id = 0; 12430 existing_member_arr[i].next_replica_id = 0; 12431 } 12432 existing_member_arr[intf_count].nh_index = leaving_next_hop_index; 12433 existing_member_arr[intf_count].member_id = intf_count; 12434 existing_member_arr[intf_count].num_replica = 1; 12435 existing_member_arr[intf_count].replica_id = 0; 12436 existing_member_arr[intf_count].next_replica_id = 0; 12437 12438 /* Find members that share the same next hop index, and 12439 * update the replica information in existing_member_arr. 12440 */ 12441 rv = _bcm_td2_ecmp_rh_member_replica_find(unit, num_existing_members, 12442 existing_member_arr); 12443 if (BCM_FAILURE(rv)) { 12444 goto cleanup; 12445 } 12446 12447 /* Derive a buffer of member IDs by assigning a member ID to each 12448 * entry of the flow set entry buffer. 12449 */ 12450 alloc_size = num_entries * sizeof(int); 12451 member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer"); 12452 if (NULL == member_id_buf) { 12453 rv = BCM_E_MEMORY; 12454 goto cleanup; 12455 } 12456 sal_memset(member_id_buf, 0, alloc_size); 12457 rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, num_existing_members, 12458 existing_member_arr, num_entries, flowset_buf, member_id_buf); 12459 if (BCM_FAILURE(rv)) { 12460 goto cleanup; 12461 } 12462 12463 /* Compute the number of entries currently assigned to each 12464 * existing member. 12465 */ 12466 alloc_size = num_existing_members * sizeof(int); 12467 entry_count_arr = sal_alloc(alloc_size, "ECMP RH entry count array"); 12468 if (NULL == entry_count_arr) { 12469 rv = BCM_E_MEMORY; 12470 goto cleanup; 12471 } 12472 sal_memset(entry_count_arr, 0, alloc_size); 12473 for (i = 0; i < num_entries; i++) { 12474 member_id = member_id_buf[i]; 12475 12476 /* In the existing_member_arr, each element's member_id is the 12477 * same as its array index. 12478 */ 12479 entry_count_arr[member_id]++; 12480 } 12481 12482 /* Check that the distribution of flow set entries among all members 12483 * is balanced. For instance, if the number of flow set entries is 64, and 12484 * the number of members is 6, then every member should have 12485 * between 10 and 11 entries. 12486 */ 12487 lower_bound = num_entries / num_existing_members; 12488 upper_bound = (num_entries % num_existing_members) ? 12489 (lower_bound + 1) : lower_bound; 12490 for (i = 0; i < num_existing_members; i++) { 12491 if (entry_count_arr[i] < lower_bound || 12492 entry_count_arr[i] > upper_bound) { 12493 rv = BCM_E_INTERNAL; 12494 goto cleanup; 12495 } 12496 } 12497 12498 /* Re-balance flow set entries from the leaving member to the remaining 12499 * members. For example, if the number of flow set entries is 64, and 12500 * the number of members is 6, then each member has between 10 and 11 12501 * entries. The entries should be re-assigned from the leaving member to 12502 * the remaining 5 members such that each remaining member will end up 12503 * with between 12 and 13 entries. 12504 */ 12505 num_remaining_members = num_existing_members - 1; 12506 lower_bound = num_entries / num_remaining_members; 12507 upper_bound = (num_entries % num_remaining_members) ? 12508 (lower_bound + 1) : lower_bound; 12509 threshold = lower_bound; 12510 leaving_member_id = existing_member_arr[intf_count].member_id; 12511 for (i = 0; i < num_entries; i++) { 12512 flowset_entry = soc_mem_table_idx_to_pointer(unit, 12513 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i); 12514 member_id = member_id_buf[i]; 12515 if (member_id != leaving_member_id) { 12516 continue; 12517 } 12518 12519 /* Randomly choose a member among the remaining members */ 12520 rv = _bcm_td2_ecmp_rh_member_choose(unit, num_remaining_members, 12521 entry_count_arr, &threshold, &chosen_index); 12522 if (BCM_FAILURE(rv)) { 12523 goto cleanup; 12524 } 12525 soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, 12526 NEXT_HOP_INDEXf, existing_member_arr[chosen_index].nh_index); 12527 member_id_buf[i] = existing_member_arr[chosen_index].member_id; 12528 } 12529 12530 /* Write re-balanced flow set entries to hardware */ 12531 rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, 12532 index_min, index_max, flowset_buf); 12533 if (SOC_FAILURE(rv)) { 12534 goto cleanup; 12535 } 12536 12537 cleanup: 12538 if (flowset_buf) { 12539 soc_cm_sfree(unit, flowset_buf); 12540 } 12541 if (member_id_buf) { 12542 sal_free(member_id_buf); 12543 } 12544 if (existing_member_arr) { 12545 sal_free(existing_member_arr); 12546 } 12547 if (entry_count_arr) { 12548 sal_free(entry_count_arr); 12549 } 12550 12551 return rv; 12552 } 12553 12554 /* 12555 * Function: 12556 * _bcm_td2_ecmp_rh_replace 12557 * Purpose: 12558 * Replace ECMP resilient hashing group members without flowset table shuffle. 12559 * Parameters: 12560 * unit - (IN) SOC unit number. 12561 * ecmp - (IN) ECMP group info. 12562 * intf_count - (IN) Number of elements in intf_array. 12563 * intf_array - (IN) Array of Egress forwarding objects. 12564 * old_intf_count - (IN) Number of elements in old_intf_array. 12565 * old_intf_array - (IN) Array of Egress forwarding objects before replacing. 12566 * Returns: 12567 * BCM_E_xxx 12568 */ 12569 STATIC int 12570 _bcm_td2_ecmp_rh_replace(int unit, 12571 bcm_l3_egress_ecmp_t *ecmp, 12572 int intf_count, 12573 bcm_if_t *intf_array, 12574 int old_intf_count, 12575 bcm_if_t *old_intf_array) 12576 { 12577 int rv = BCM_E_NONE; 12578 int ecmp_group; 12579 int offset; 12580 ecmp_count_entry_t ecmp_count_entry; 12581 int entry_base_ptr; 12582 int flow_set_size; 12583 int num_entries; 12584 int alloc_size; 12585 uint32 *flowset_buf = NULL; 12586 int index_min, index_max; 12587 int max_shared; 12588 int i, j; 12589 int shared_intf_count; 12590 int ex_old_intf_count; 12591 int ex_new_intf_count; 12592 bcm_if_t *shared_intf_array = NULL; 12593 bcm_if_t *ex_old_intf_array = NULL; 12594 bcm_if_t *ex_new_intf_array = NULL; 12595 bcm_if_t *temp_old_intf_array = NULL; 12596 bcm_if_t *temp_new_intf_array = NULL; 12597 12598 if (ecmp == NULL || 12599 ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 12600 return BCM_E_PARAM; 12601 } 12602 12603 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 12604 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12605 } else { 12606 return BCM_E_PARAM; 12607 } 12608 12609 if (intf_count > 0 && intf_array == NULL) { 12610 return BCM_E_PARAM; 12611 } 12612 12613 if (intf_count == 0) { 12614 /* Replacing the last member is the same as freeing all resources */ 12615 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group)); 12616 12617 /* Store the dynamic_size in hardware */ 12618 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_set(unit, ecmp_group, 12619 ecmp->dynamic_size)); 12620 12621 return BCM_E_NONE; 12622 } 12623 12624 if (old_intf_count == 0) { 12625 /* Replacing the first member is the same as setting one member */ 12626 return _bcm_td2_ecmp_rh_set(unit, ecmp, intf_count, intf_array); 12627 } 12628 12629 /* Determine members shared by old and new ECMP groups, and 12630 * members exclusive to the old and the new ECMP groups. 12631 */ 12632 max_shared = (old_intf_count > intf_count) ? intf_count : 12633 old_intf_count; 12634 12635 alloc_size = max_shared * sizeof(bcm_if_t); 12636 shared_intf_array = sal_alloc(alloc_size, "shared ecmp member array"); 12637 if (NULL == shared_intf_array) { 12638 rv = BCM_E_MEMORY; 12639 goto cleanup; 12640 } 12641 sal_memset(shared_intf_array, 0, alloc_size); 12642 12643 alloc_size = old_intf_count * sizeof(bcm_if_t); 12644 ex_old_intf_array = sal_alloc(alloc_size, 12645 "array of members exclusive to old ecmp group"); 12646 if (NULL == ex_old_intf_array) { 12647 rv = BCM_E_MEMORY; 12648 goto cleanup; 12649 } 12650 sal_memset(ex_old_intf_array, 0, alloc_size); 12651 12652 alloc_size = intf_count * sizeof(bcm_if_t); 12653 ex_new_intf_array = sal_alloc(alloc_size, 12654 "array of members exclusive to new ecmp group"); 12655 if (NULL == ex_new_intf_array) { 12656 rv = BCM_E_MEMORY; 12657 goto cleanup; 12658 } 12659 sal_memset(ex_new_intf_array, 0, alloc_size); 12660 12661 alloc_size = old_intf_count * sizeof(bcm_if_t); 12662 temp_old_intf_array = sal_alloc(alloc_size, "copy of old_intf_array"); 12663 if (NULL == temp_old_intf_array) { 12664 rv = BCM_E_MEMORY; 12665 goto cleanup; 12666 } 12667 sal_memcpy(temp_old_intf_array, old_intf_array, alloc_size); 12668 for (i = 0; i < old_intf_count; i++) { 12669 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, temp_old_intf_array[i])) { 12670 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 12671 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, temp_old_intf_array[i])) { 12672 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 12673 } else { 12674 rv = BCM_E_PARAM; 12675 goto cleanup; 12676 } 12677 temp_old_intf_array[i] -= offset; 12678 } 12679 12680 alloc_size = intf_count * sizeof(bcm_if_t); 12681 temp_new_intf_array = sal_alloc(alloc_size, "copy of intf_array"); 12682 if (NULL == temp_new_intf_array) { 12683 rv = BCM_E_MEMORY; 12684 goto cleanup; 12685 } 12686 sal_memcpy(temp_new_intf_array, intf_array, alloc_size); 12687 for (i = 0; i < intf_count; i++) { 12688 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, temp_new_intf_array[i])) { 12689 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 12690 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, temp_new_intf_array[i])) { 12691 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 12692 } else { 12693 rv = BCM_E_PARAM; 12694 goto cleanup; 12695 } 12696 temp_new_intf_array[i] -= offset; 12697 } 12698 12699 /* Replace arrangement */ 12700 shared_intf_count = 0; 12701 ex_new_intf_count = 0; 12702 for (i = 0; i < intf_count; i++) { 12703 for (j = 0; j < old_intf_count; j++) { 12704 if (temp_new_intf_array[i] == temp_old_intf_array[j]) { 12705 shared_intf_array[shared_intf_count++] = temp_new_intf_array[i]; 12706 /* Mark the matched element invalid */ 12707 temp_old_intf_array[j] = BCM_XGS3_L3_INVALID_INDEX; 12708 break; 12709 } 12710 } 12711 if (j == old_intf_count) { 12712 ex_new_intf_array[ex_new_intf_count++] = temp_new_intf_array[i]; 12713 } 12714 } 12715 12716 ex_old_intf_count = 0; 12717 for (i = 0; i < old_intf_count; i++) { 12718 if (temp_old_intf_array[i] != BCM_XGS3_L3_INVALID_INDEX) { 12719 ex_old_intf_array[ex_old_intf_count++] = temp_old_intf_array[i]; 12720 } 12721 } 12722 12723 /* Read all the flow set entries of this ECMP resilient hash group */ 12724 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group, 12725 &ecmp_count_entry); 12726 if (BCM_FAILURE(rv)) { 12727 goto cleanup; 12728 } 12729 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 12730 RH_FLOW_SET_BASEf); 12731 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 12732 RH_FLOW_SET_SIZEf); 12733 12734 rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries); 12735 if (BCM_FAILURE(rv)) { 12736 goto cleanup; 12737 } 12738 12739 alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t); 12740 flowset_buf = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries"); 12741 if (NULL == flowset_buf) { 12742 rv = BCM_E_MEMORY; 12743 goto cleanup; 12744 } 12745 sal_memset(flowset_buf, 0, alloc_size); 12746 index_min = entry_base_ptr; 12747 index_max = index_min + num_entries - 1; 12748 rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY, 12749 index_min, index_max, flowset_buf); 12750 if (BCM_FAILURE(rv)) { 12751 goto cleanup; 12752 } 12753 12754 if (shared_intf_count == 0) { 12755 /* The old and the new ECMP groups don't share any members. 12756 * Replacing flow set entries with max_shared members so as to 12757 * set shared_intf_count = max_shared. 12758 */ 12759 rv = _bcm_td2_ecmp_rh_arrange_with_no_shared_entries(unit, 12760 num_entries, flowset_buf, 12761 old_intf_count, temp_old_intf_array, 12762 intf_count, temp_new_intf_array, 12763 &shared_intf_count, shared_intf_array, 12764 &ex_old_intf_count, ex_old_intf_array, 12765 &ex_new_intf_count, ex_new_intf_array); 12766 if (BCM_FAILURE(rv)) { 12767 goto cleanup; 12768 } 12769 } 12770 12771 /* Modify the flow set entry buffer to achieve balance among 12772 * shared members and members exclusive to the new ECMP group, 12773 * while keeping modifications of entries containing the 12774 * shared members to a minimum. 12775 */ 12776 rv = _bcm_td2_ecmp_rh_balance_with_min_shared_mod(unit, 12777 num_entries, flowset_buf, 12778 shared_intf_count, shared_intf_array, 12779 ex_old_intf_count, ex_old_intf_array, 12780 ex_new_intf_count, ex_new_intf_array); 12781 if (BCM_FAILURE(rv)) { 12782 goto cleanup; 12783 } 12784 12785 rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, 12786 index_min, index_max, flowset_buf); 12787 if (BCM_FAILURE(rv)) { 12788 goto cleanup; 12789 } 12790 12791 cleanup: 12792 if (flowset_buf) { 12793 soc_cm_sfree(unit, flowset_buf); 12794 } 12795 if (shared_intf_array) { 12796 sal_free(shared_intf_array); 12797 } 12798 if (ex_old_intf_array) { 12799 sal_free(ex_old_intf_array); 12800 } 12801 if (ex_new_intf_array) { 12802 sal_free(ex_new_intf_array); 12803 } 12804 if (temp_old_intf_array) { 12805 sal_free(temp_old_intf_array); 12806 } 12807 if (temp_new_intf_array) { 12808 sal_free(temp_new_intf_array); 12809 } 12810 12811 return rv; 12812 } 12813 12814 12815 /* 12816 * Function: 12817 * bcm_td2_l3_egress_ecmp_rh_create 12818 * Purpose: 12819 * Create or modify an ECMP resilient hashing group. 12820 * Parameters: 12821 * unit - (IN) bcm device. 12822 * ecmp - (IN) ECMP group info. 12823 * intf_count - (IN) Number of elements in intf_array. 12824 * intf_array - (IN) Array of Egress forwarding objects. 12825 * op - (IN) Member operation: SET, ADD, DELETE, or REPLACE. 12826 * count - (IN) Number of elements in intf. 12827 * intf - (IN) Egress forwarding objects to add, delete, or replace. 12828 12829 * Returns: 12830 * BCM_E_XXX 12831 */ 12832 int 12833 bcm_td2_l3_egress_ecmp_rh_create(int unit, bcm_l3_egress_ecmp_t *ecmp, 12834 int intf_count, bcm_if_t *intf_array, int op, int count, bcm_if_t *intf) 12835 { 12836 int dynamic_size_encode; 12837 int rh_enable; 12838 int ecmp_group; 12839 initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry; 12840 12841 12842 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 12843 /* Verify ecmp->dynamic_size */ 12844 BCM_IF_ERROR_RETURN 12845 (_bcm_td2_ecmp_rh_dynamic_size_encode(unit, ecmp->dynamic_size, 12846 &dynamic_size_encode)); 12847 rh_enable = 1; 12848 } else { 12849 rh_enable = 0; 12850 } 12851 12852 if (op == BCM_L3_ECMP_MEMBER_OP_SET) { 12853 /* Free resilient hashing resources associated with this ecmp group */ 12854 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12855 BCM_IF_ERROR_RETURN 12856 (_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group)); 12857 12858 if (rh_enable) { 12859 /* Set resilient hashing members for this ecmp group */ 12860 BCM_IF_ERROR_RETURN 12861 (_bcm_td2_ecmp_rh_set(unit, ecmp, intf_count, intf_array)); 12862 12863 if (SOC_IS_TRIDENT3X(unit)) { 12864 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12865 12866 BCM_IF_ERROR_RETURN 12867 (soc_mem_read(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ANY, 12868 ecmp_group,&initial_l3_ecmp_group_entry)); 12869 12870 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 12871 &initial_l3_ecmp_group_entry, LB_MODEf, 1); 12872 BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL, 12873 ecmp_group, &initial_l3_ecmp_group_entry)); 12874 } 12875 } 12876 } else if (op == BCM_L3_ECMP_MEMBER_OP_ADD) { 12877 if (rh_enable) { 12878 /* Add new resilient hashing member to ecmp group */ 12879 BCM_IF_ERROR_RETURN 12880 (_bcm_td2_ecmp_rh_add(unit, ecmp, intf_count, intf_array, *intf)); 12881 } 12882 } else if (op == BCM_L3_ECMP_MEMBER_OP_DELETE) { 12883 if (rh_enable) { 12884 /* Delete resilient hashing member from ecmp group */ 12885 BCM_IF_ERROR_RETURN 12886 (_bcm_td2_ecmp_rh_delete(unit, ecmp, intf_count, intf_array, *intf)); 12887 } 12888 } else if (op == BCM_L3_ECMP_MEMBER_OP_REPLACE) { 12889 if (rh_enable) { 12890 /* Replace resilient hashing member for ecmp group */ 12891 BCM_IF_ERROR_RETURN 12892 (_bcm_td2_ecmp_rh_replace(unit, ecmp, intf_count, intf_array, count, intf)); 12893 } 12894 } else { 12895 return BCM_E_PARAM; 12896 } 12897 12898 return BCM_E_NONE; 12899 } 12900 12901 /* 12902 * Function: 12903 * bcm_td2_l3_egress_ecmp_rh_destroy 12904 * Purpose: 12905 * Destroy an ECMP resilient hashing group. 12906 * Parameters: 12907 * unit - (IN) bcm device. 12908 * mpintf - (IN) L3 interface id pointing to Egress multipath object. 12909 * Returns: 12910 * BCM_E_XXX 12911 */ 12912 int 12913 bcm_td2_l3_egress_ecmp_rh_destroy(int unit, bcm_if_t mpintf) 12914 { 12915 int ecmp_group; 12916 12917 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) { 12918 ecmp_group = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12919 } else { 12920 return BCM_E_PARAM; 12921 } 12922 12923 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group)); 12924 12925 return BCM_E_NONE; 12926 } 12927 12928 /* 12929 * Function: 12930 * bcm_td2_l3_egress_ecmp_rh_get 12931 * Purpose: 12932 * Get info about an ECMP resilient hashing group. 12933 * Parameters: 12934 * unit - (IN) bcm device. 12935 * ecmp - (INOUT) ECMP group info. 12936 * Returns: 12937 * BCM_E_XXX 12938 */ 12939 int 12940 bcm_td2_l3_egress_ecmp_rh_get(int unit, bcm_l3_egress_ecmp_t *ecmp) 12941 { 12942 int ecmp_group; 12943 ecmp_count_entry_t ecmp_count_entry; 12944 int flow_set_size; 12945 int num_entries; 12946 12947 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 12948 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 12949 } else { 12950 return BCM_E_PARAM; 12951 } 12952 12953 /* An ECMP group can be in one of 3 resilient hashing states: 12954 * (1) RH not enabled: L3_ECMP_COUNT.RH_FLOW_SET_SIZE = 0. 12955 * (2) RH enabled but without any members: 12956 * L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero, 12957 * L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 0. 12958 * (3) RH enabled with members: 12959 * L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero, 12960 * L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 1. 12961 */ 12962 12963 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, 12964 ecmp_group, &ecmp_count_entry)); 12965 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, 12966 &ecmp_count_entry, RH_FLOW_SET_SIZEf); 12967 12968 if (0 == flow_set_size) { 12969 /* Resilient hashing is not enabled on this ECMP group. */ 12970 return BCM_E_NONE; 12971 } 12972 12973 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT; 12974 BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, 12975 &num_entries)); 12976 ecmp->dynamic_size = num_entries; 12977 12978 return BCM_E_NONE; 12979 } 12980 12981 /* 12982 * Function: 12983 * bcm_td2_l3_egress_ecmp_rh_ethertype_set 12984 * Purpose: 12985 * Set the Ethertypes that are eligible or ineligible for 12986 * ECMP resilient hashing. 12987 * Parameters: 12988 * unit - (IN) Unit number. 12989 * flags - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags. 12990 * ethertype_count - (IN) Number of elements in ethertype_array. 12991 * ethertype_array - (IN) Array of Ethertypes. 12992 * Returns: 12993 * BCM_E_XXX 12994 */ 12995 int 12996 bcm_td2_l3_egress_ecmp_rh_ethertype_set( 12997 int unit, 12998 uint32 flags, 12999 int ethertype_count, 13000 int *ethertype_array) 13001 { 13002 uint32 control_reg; 13003 int i, j; 13004 rh_ecmp_ethertype_eligibility_map_entry_t ethertype_entry; 13005 13006 /* Input check */ 13007 if (ethertype_count > soc_mem_index_count(unit, 13008 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)) { 13009 return BCM_E_RESOURCE; 13010 } 13011 13012 /* Update ethertype eligibility control register */ 13013 SOC_IF_ERROR_RETURN 13014 (READ_RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg)); 13015 soc_reg_field_set(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 13016 &control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf, 13017 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0); 13018 soc_reg_field_set(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 13019 &control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf, 13020 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0); 13021 SOC_IF_ERROR_RETURN 13022 (WRITE_RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, control_reg)); 13023 13024 /* Update Ethertype eligibility map table */ 13025 for (i = 0; i < ethertype_count; i++) { 13026 sal_memset(ðertype_entry, 0, 13027 sizeof(rh_ecmp_ethertype_eligibility_map_entry_t)); 13028 soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 13029 ðertype_entry, VALIDf, 1); 13030 soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 13031 ðertype_entry, ETHERTYPEf, ethertype_array[i]); 13032 SOC_IF_ERROR_RETURN(WRITE_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 13033 MEM_BLOCK_ALL, i, ðertype_entry)); 13034 } 13035 13036 /* Zero out remaining entries of Ethertype eligibility map table */ 13037 for (j = i; j < soc_mem_index_count(unit, 13038 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); j++) { 13039 SOC_IF_ERROR_RETURN(WRITE_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 13040 MEM_BLOCK_ALL, j, soc_mem_entry_null(unit, 13041 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm))); 13042 } 13043 13044 return BCM_E_NONE; 13045 } 13046 13047 /* 13048 * Function: 13049 * bcm_td2_l3_egress_ecmp_rh_ethertype_get 13050 * Purpose: 13051 * Get the Ethertypes that are eligible or ineligible for 13052 * ECMP resilient hashing. 13053 * Parameters: 13054 * unit - (IN) Unit number. 13055 * flags - (INOUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags. 13056 * ethertype_max - (IN) Number of elements in ethertype_array. 13057 * ethertype_array - (OUT) Array of Ethertypes. 13058 * ethertype_count - (OUT) Number of elements returned in ethertype_array. 13059 * Returns: 13060 * BCM_E_XXX 13061 */ 13062 int 13063 bcm_td2_l3_egress_ecmp_rh_ethertype_get( 13064 int unit, 13065 uint32 *flags, 13066 int ethertype_max, 13067 int *ethertype_array, 13068 int *ethertype_count) 13069 { 13070 uint32 control_reg; 13071 int i; 13072 int ethertype; 13073 rh_ecmp_ethertype_eligibility_map_entry_t ethertype_entry; 13074 13075 *ethertype_count = 0; 13076 13077 /* Get flags */ 13078 SOC_IF_ERROR_RETURN 13079 (READ_RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg)); 13080 if (soc_reg_field_get(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 13081 control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) { 13082 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE; 13083 } 13084 if (soc_reg_field_get(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 13085 control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) { 13086 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER; 13087 } 13088 13089 /* Get Ethertypes */ 13090 for (i = 0; i < soc_mem_index_count(unit, 13091 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); i++) { 13092 SOC_IF_ERROR_RETURN(READ_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 13093 MEM_BLOCK_ANY, i, ðertype_entry)); 13094 if (soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 13095 ðertype_entry, VALIDf)) { 13096 ethertype = soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 13097 ðertype_entry, ETHERTYPEf); 13098 if (NULL != ethertype_array) { 13099 ethertype_array[*ethertype_count] = ethertype; 13100 } 13101 (*ethertype_count)++; 13102 if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) { 13103 break; 13104 } 13105 } 13106 } 13107 13108 return BCM_E_NONE; 13109 } 13110 13111 /* 13112 * Function: 13113 * bcm_td2_l3_egress_ecmp_rh_shared_copy 13114 * Purpose: 13115 * For members shared by the old and the new ECMP groups, 13116 * copy the resilient hash flow set entries containing these 13117 * members from the old to the new ECMP group, in order to minimize 13118 * flow-to-member reassignments when the old ECMP group in a route 13119 * entry is replaced by the new one. 13120 * Parameters: 13121 * unit - (IN) SOC unit number. 13122 * old_ecmp_group - (IN) Old ECMP group. 13123 * new_ecmp_group - (IN) New ECMP group. 13124 * Returns: 13125 * BCM_E_XXX 13126 */ 13127 int 13128 bcm_td2_l3_egress_ecmp_rh_shared_copy(int unit, int old_ecmp_group, 13129 int new_ecmp_group) 13130 { 13131 int rv = BCM_E_NONE; 13132 bcm_l3_egress_ecmp_t old_ecmp, new_ecmp; 13133 int old_intf_count, new_intf_count; 13134 bcm_if_t *old_intf_array = NULL; 13135 bcm_if_t *new_intf_array = NULL; 13136 int offset; 13137 int count; 13138 int max_shared; 13139 bcm_if_t *shared_intf_array = NULL; 13140 bcm_if_t *ex_old_intf_array = NULL; 13141 bcm_if_t *ex_new_intf_array = NULL; 13142 bcm_if_t *temp_old_intf_array = NULL; 13143 int shared_intf_count, ex_new_intf_count, ex_old_intf_count; 13144 int i, j; 13145 ecmp_count_entry_t ecmp_count_entry; 13146 int entry_base_ptr, flow_set_size, num_entries; 13147 int alloc_size; 13148 uint32 *buf_ptr = NULL; 13149 int index_min, index_max; 13150 13151 /* Check if there are any routing entries pointing to the 13152 * new ECMP group. If so, the new ECMP group's flow set 13153 * entries should not be modified. 13154 */ 13155 if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), 13156 new_ecmp_group) > 2) { 13157 /* When the new ECMP group was created, its reference count 13158 * was set to 1. Then, in bcm_xgs3_defip_add, its reference count 13159 * was incremented before this procedure is invoked. Hence, 13160 * if there are any routing entry already pointing at the new 13161 * ECMP group, the reference count would be greater than 2. 13162 */ 13163 return BCM_E_NONE; 13164 } 13165 13166 /* Check if the old ECMP group is resilient hash enabled. */ 13167 bcm_l3_egress_ecmp_t_init(&old_ecmp); 13168 old_ecmp.ecmp_intf = old_ecmp_group + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 13169 BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_ecmp_get(unit, &old_ecmp, 13170 0, NULL, &old_intf_count)); 13171 if (old_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 13172 /* The old ECMP group was not resilient hash enabled. Copying 13173 * flow set entries is not applicable. 13174 */ 13175 return BCM_E_NONE; 13176 } 13177 13178 /* Check if the new ECMP group is resilient hash enabled. */ 13179 bcm_l3_egress_ecmp_t_init(&new_ecmp); 13180 new_ecmp.ecmp_intf = new_ecmp_group + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 13181 BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_ecmp_get(unit, &new_ecmp, 13182 0, NULL, &new_intf_count)); 13183 if (new_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) { 13184 /* The new ECMP group is not resilient hash enabled. Copying 13185 * flow set entries is not applicable. 13186 */ 13187 return BCM_E_NONE; 13188 } 13189 13190 if (old_ecmp.dynamic_size != new_ecmp.dynamic_size) { 13191 /* The number of flow set entries in old ECMP group is not the 13192 * same as the number in new ECMP group. Copying 13193 * flow set entries is not applicable. 13194 */ 13195 return BCM_E_NONE; 13196 } 13197 13198 /* Get old ECMP group members */ 13199 old_intf_array = sal_alloc(old_intf_count * sizeof(bcm_if_t), 13200 "old ecmp member array"); 13201 if (NULL == old_intf_array) { 13202 rv = BCM_E_MEMORY; 13203 goto cleanup; 13204 } 13205 sal_memset(old_intf_array, 0, old_intf_count * sizeof(bcm_if_t)); 13206 rv = bcm_esw_l3_egress_ecmp_get(unit, &old_ecmp, old_intf_count, 13207 old_intf_array, &count); 13208 if (BCM_FAILURE(rv)) { 13209 goto cleanup; 13210 } 13211 for (i = 0; i < old_intf_count; i++) { 13212 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, old_intf_array[i])) { 13213 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 13214 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, old_intf_array[i])) { 13215 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 13216 } else { 13217 rv = BCM_E_PARAM; 13218 goto cleanup; 13219 } 13220 old_intf_array[i] -= offset; 13221 } 13222 13223 /* Get new ECMP group members */ 13224 new_intf_array = sal_alloc(new_intf_count * sizeof(bcm_if_t), 13225 "new ecmp member array"); 13226 if (NULL == new_intf_array) { 13227 rv = BCM_E_MEMORY; 13228 goto cleanup; 13229 } 13230 sal_memset(new_intf_array, 0, new_intf_count * sizeof(bcm_if_t)); 13231 rv = bcm_esw_l3_egress_ecmp_get(unit, &new_ecmp, new_intf_count, 13232 new_intf_array, &count); 13233 if (BCM_FAILURE(rv)) { 13234 goto cleanup; 13235 } 13236 for (i = 0; i < new_intf_count; i++) { 13237 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, new_intf_array[i])) { 13238 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 13239 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, new_intf_array[i])) { 13240 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 13241 } else { 13242 rv = BCM_E_PARAM; 13243 goto cleanup; 13244 } 13245 new_intf_array[i] -= offset; 13246 } 13247 13248 /* Determine members shared by old and new ECMP groups, and 13249 * members exclusive to the old and the new ECMP groups. 13250 */ 13251 max_shared = (old_intf_count > new_intf_count) ? new_intf_count : 13252 old_intf_count; 13253 shared_intf_array = sal_alloc(max_shared * sizeof(bcm_if_t), 13254 "shared ecmp member array"); 13255 if (NULL == shared_intf_array) { 13256 rv = BCM_E_MEMORY; 13257 goto cleanup; 13258 } 13259 sal_memset(shared_intf_array, 0, max_shared * sizeof(bcm_if_t)); 13260 13261 ex_old_intf_array = sal_alloc(old_intf_count * sizeof(bcm_if_t), 13262 "array of members exclusive to old ecmp group"); 13263 if (NULL == ex_old_intf_array) { 13264 rv = BCM_E_MEMORY; 13265 goto cleanup; 13266 } 13267 sal_memset(ex_old_intf_array, 0, old_intf_count * sizeof(bcm_if_t)); 13268 13269 ex_new_intf_array = sal_alloc(new_intf_count * sizeof(bcm_if_t), 13270 "array of members exclusive to new ecmp group"); 13271 if (NULL == ex_new_intf_array) { 13272 rv = BCM_E_MEMORY; 13273 goto cleanup; 13274 } 13275 sal_memset(ex_new_intf_array, 0, new_intf_count * sizeof(bcm_if_t)); 13276 13277 temp_old_intf_array = sal_alloc(old_intf_count * sizeof(bcm_if_t), 13278 "copy of old_intf_array"); 13279 if (NULL == temp_old_intf_array) { 13280 rv = BCM_E_MEMORY; 13281 goto cleanup; 13282 } 13283 sal_memcpy(temp_old_intf_array, old_intf_array, old_intf_count * sizeof(bcm_if_t)); 13284 13285 shared_intf_count = 0; 13286 ex_new_intf_count = 0; 13287 for (i = 0; i < new_intf_count; i++) { 13288 for (j = 0; j < old_intf_count; j++) { 13289 if (new_intf_array[i] == temp_old_intf_array[j]) { 13290 shared_intf_array[shared_intf_count++] = new_intf_array[i]; 13291 /* Mark the matched element invalid */ 13292 temp_old_intf_array[j] = BCM_XGS3_L3_INVALID_INDEX; 13293 break; 13294 } 13295 } 13296 if (j == old_intf_count) { 13297 ex_new_intf_array[ex_new_intf_count++] = new_intf_array[i]; 13298 } 13299 } 13300 13301 ex_old_intf_count = 0; 13302 for (i = 0; i < old_intf_count; i++) { 13303 if (temp_old_intf_array[i] != BCM_XGS3_L3_INVALID_INDEX) { 13304 ex_old_intf_array[ex_old_intf_count++] = temp_old_intf_array[i]; 13305 } 13306 } 13307 13308 if (shared_intf_count == 0) { 13309 /* The old and the new ECMP groups don't share any members. 13310 * Copying flow set entries is not applicable. 13311 */ 13312 rv = BCM_E_NONE; 13313 goto cleanup; 13314 } 13315 13316 /* Read old ECMP group's flow set entries into a buffer */ 13317 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, old_ecmp_group, 13318 &ecmp_count_entry); 13319 if (SOC_FAILURE(rv)) { 13320 goto cleanup; 13321 } 13322 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 13323 RH_FLOW_SET_BASEf); 13324 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 13325 RH_FLOW_SET_SIZEf); 13326 rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries); 13327 if (BCM_FAILURE(rv)) { 13328 goto cleanup; 13329 } 13330 alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t); 13331 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries"); 13332 if (NULL == buf_ptr) { 13333 rv = BCM_E_MEMORY; 13334 goto cleanup; 13335 } 13336 sal_memset(buf_ptr, 0, alloc_size); 13337 index_min = entry_base_ptr; 13338 index_max = index_min + num_entries - 1; 13339 rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY, 13340 index_min, index_max, buf_ptr); 13341 if (SOC_FAILURE(rv)) { 13342 goto cleanup; 13343 } 13344 13345 /* Modify the flow set entry buffer to achieve balance among 13346 * shared members and members exclusive to the new ECMP group, 13347 * while keeping modifications of entries containing the 13348 * shared members to a minimum. 13349 */ 13350 rv = _bcm_td2_ecmp_rh_balance_with_min_shared_mod(unit, 13351 num_entries, buf_ptr, 13352 shared_intf_count, shared_intf_array, 13353 ex_old_intf_count, ex_old_intf_array, 13354 ex_new_intf_count, ex_new_intf_array); 13355 if (BCM_FAILURE(rv)) { 13356 goto cleanup; 13357 } 13358 13359 /* Replace the new ECMP group's flow set entries with the buffer */ 13360 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, new_ecmp_group, 13361 &ecmp_count_entry); 13362 if (SOC_FAILURE(rv)) { 13363 goto cleanup; 13364 } 13365 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 13366 RH_FLOW_SET_BASEf); 13367 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry, 13368 RH_FLOW_SET_SIZEf); 13369 rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries); 13370 if (BCM_FAILURE(rv)) { 13371 goto cleanup; 13372 } 13373 index_min = entry_base_ptr; 13374 index_max = index_min + num_entries - 1; 13375 rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, 13376 index_min, index_max, buf_ptr); 13377 if (SOC_FAILURE(rv)) { 13378 goto cleanup; 13379 } 13380 13381 cleanup: 13382 if (old_intf_array) { 13383 sal_free(old_intf_array); 13384 } 13385 if (new_intf_array) { 13386 sal_free(new_intf_array); 13387 } 13388 if (shared_intf_array) { 13389 sal_free(shared_intf_array); 13390 } 13391 if (ex_old_intf_array) { 13392 sal_free(ex_old_intf_array); 13393 } 13394 if (ex_new_intf_array) { 13395 sal_free(ex_new_intf_array); 13396 } 13397 if (temp_old_intf_array) { 13398 sal_free(temp_old_intf_array); 13399 } 13400 if (buf_ptr) { 13401 soc_cm_sfree(unit, buf_ptr); 13402 } 13403 13404 return rv; 13405 } 13406 13407 #ifdef BCM_WARM_BOOT_SUPPORT 13408 13409 /* 13410 * Function: 13411 * bcm_td2_ecmp_rh_hw_recover 13412 * Purpose: 13413 * Recover ECMP resilient hashing internal state from hardware. 13414 * Parameters: 13415 * unit - (IN) SOC unit number. 13416 * Returns: 13417 * BCM_E_XXX 13418 */ 13419 int 13420 bcm_td2_ecmp_rh_hw_recover(int unit) 13421 { 13422 int rv = BCM_E_NONE; 13423 int alloc_size; 13424 uint32 *buf_ptr = NULL; 13425 int i; 13426 ecmp_count_entry_t *ecmp_count_entry; 13427 int flow_set_size; 13428 int entry_base_ptr; 13429 int block_base_ptr; 13430 int num_entries; 13431 int num_blocks, enhanced_hashing = 1; 13432 soc_field_t enhanced_hashing_fld; 13433 uint32 rval; 13434 13435 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) { 13436 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 13437 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 13438 RH_DLB_SELECTIONf)) { 13439 /* ECMP resilient hashing is not enabled chip-wide. */ 13440 return BCM_E_NONE; 13441 } 13442 } 13443 13444 /* Read entire L3_ECMP_COUNT table */ 13445 alloc_size = soc_mem_index_count(unit, L3_ECMP_COUNTm) * 13446 sizeof(ecmp_count_entry_t); 13447 buf_ptr = soc_cm_salloc(unit, alloc_size, "L3_ECMP_COUNT entries"); 13448 if (NULL == buf_ptr) { 13449 return BCM_E_MEMORY; 13450 } 13451 rv = soc_mem_read_range(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, 13452 soc_mem_index_min(unit, L3_ECMP_COUNTm), 13453 soc_mem_index_max(unit, L3_ECMP_COUNTm), 13454 buf_ptr); 13455 if (SOC_FAILURE(rv)) { 13456 soc_cm_sfree(unit, buf_ptr); 13457 return rv; 13458 } 13459 13460 /* Traverse ECMP groups to recover resilient hashing flow set 13461 * table usage. 13462 */ 13463 for (i = 0; i < soc_mem_index_count(unit, L3_ECMP_COUNTm); i++) { 13464 13465 /* An ECMP group can be in one of 3 resilient hashing states: 13466 * (1) RH not enabled: L3_ECMP_COUNT.RH_FLOW_SET_SIZE = 0. 13467 * (2) RH enabled but without any members: 13468 * L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero, 13469 * L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 0. 13470 * (3) RH enabled with members: 13471 * L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero, 13472 * L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 1. 13473 */ 13474 13475 ecmp_count_entry = soc_mem_table_idx_to_pointer(unit, L3_ECMP_COUNTm, 13476 ecmp_count_entry_t *, buf_ptr, i); 13477 flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, 13478 ecmp_count_entry, RH_FLOW_SET_SIZEf); 13479 if (0 == flow_set_size) { 13480 /* Resilient hashing is not enabled on this ECMP group. */ 13481 continue; 13482 } 13483 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){ 13484 enhanced_hashing_fld = LB_MODEf; 13485 enhanced_hashing = 4; 13486 } else { 13487 enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf; 13488 } 13489 if (soc_L3_ECMP_COUNTm_field32_get(unit, 13490 ecmp_count_entry, enhanced_hashing_fld) == enhanced_hashing) { 13491 /* Recover ECMP resilient hashing flow set block usage */ 13492 entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, 13493 ecmp_count_entry, RH_FLOW_SET_BASEf); 13494 block_base_ptr = entry_base_ptr >> \ 13495 _td2_ecmp_rh_info[unit]->ecmp_block_size; 13496 rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, 13497 &num_entries); 13498 if (BCM_FAILURE(rv)) { 13499 soc_cm_sfree(unit, buf_ptr); 13500 return rv; 13501 } 13502 num_blocks = num_entries >> \ 13503 _td2_ecmp_rh_info[unit]->ecmp_block_size ; 13504 _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, 13505 num_blocks); 13506 #ifdef BCM_TRIDENT3_SUPPORT 13507 if (soc_feature(unit, soc_feature_td3_dlb)) { 13508 ecmp_grp_enhanced_hashing[unit][i] = 1; 13509 } 13510 #endif 13511 } 13512 } 13513 13514 soc_cm_sfree(unit, buf_ptr); 13515 13516 return rv; 13517 } 13518 13519 #endif /* BCM_WARM_BOOT_SUPPORT */ 13520 13521 #ifndef BCM_SW_STATE_DUMP_DISABLE 13522 /* 13523 * Function: 13524 * bcm_td2_ecmp_rh_sw_dump 13525 * Purpose: 13526 * Displays ECMP resilient hashing state maintained by software. 13527 * Parameters: 13528 * unit - Device unit number 13529 * Returns: 13530 * None 13531 */ 13532 void bcm_td2_ecmp_rh_sw_dump(int unit) 13533 { 13534 int i, j; 13535 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 13536 _bcm_l3_bookkeeping_t *l3_bk_info = &_bcm_l3_bk_info[unit]; 13537 #endif 13538 13539 LOG_CLI((BSL_META_U(unit, 13540 " ECMP Resilient Hashing Info -\n"))); 13541 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 13542 if (( 13543 #if defined(BCM_RIOT_SUPPORT) 13544 l3_bk_info->riot_enable || 13545 #endif 13546 BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) && 13547 (l3_bk_info->l3_ecmp_rh_overlay_entries > 0)) { 13548 13549 LOG_CLI((BSL_META_U(unit, 13550 " Overlay RH Flowset Table Blocks Total: %d\n"), 13551 l3_bk_info->l3_ecmp_rh_overlay_entries >> \ 13552 _td2_ecmp_rh_info[unit]->ecmp_block_size)); 13553 13554 LOG_CLI((BSL_META_U(unit, 13555 " Underlay RH Flowset Table Blocks Total: %d\n"), 13556 _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks - 13557 (l3_bk_info->l3_ecmp_rh_overlay_entries >> \ 13558 _td2_ecmp_rh_info[unit]->ecmp_block_size))); 13559 } else 13560 #endif 13561 { 13562 13563 LOG_CLI((BSL_META_U(unit, 13564 " RH Flowset Table Blocks Total: %d\n"), 13565 _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks)); 13566 } 13567 13568 /* Print ECMP RH flowset table usage */ 13569 LOG_CLI((BSL_META_U(unit, 13570 " RH Flowset Table Blocks Used:"))); 13571 j = 0; 13572 for (i = 0; i < _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks; i++) { 13573 if (_BCM_ECMP_RH_FLOWSET_BLOCK_USED_GET(unit, i)) { 13574 j++; 13575 if (j % 15 == 1) { 13576 LOG_CLI((BSL_META_U(unit, 13577 "\n "))); 13578 } 13579 LOG_CLI((BSL_META_U(unit, 13580 " %4d"), i)); 13581 } 13582 } 13583 LOG_CLI((BSL_META_U(unit, 13584 "\n"))); 13585 13586 return; 13587 } 13588 13589 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 13590 13591 #endif /* INCLUDE_L3 && BCM_TRIDENT2_SUPPORT */