l3.c (402667B)
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 <soc/defs.h> 12 #include <shared/bsl.h> 13 #if defined(INCLUDE_L3) && defined(BCM_TRIUMPH3_SUPPORT) 14 #include <soc/drv.h> 15 #include <bcm/error.h> 16 17 #include <bcm/l3.h> 18 #include <soc/l3x.h> 19 #include <soc/lpm.h> 20 #include <bcm/tunnel.h> 21 #include <bcm/debug.h> 22 #include <bcm/error.h> 23 #include <bcm/stack.h> 24 25 #include <bcm_int/esw/triumph3.h> 26 #include <bcm_int/esw/firebolt.h> 27 #include <bcm_int/esw/triumph2.h> 28 #include <bcm_int/esw/stack.h> 29 #include <bcm_int/esw/flex_ctr.h> 30 #include <bcm_int/esw_dispatch.h> 31 #include <bcm_int/esw/lpmv6.h> 32 #include <bcm_int/esw/virtual.h> 33 #include <bcm_int/esw/tomahawk.h> 34 35 #if defined(BCM_TRX_SUPPORT) 36 #include <bcm_int/esw/trx.h> 37 #endif /* BCM_TRX_SUPPORT */ 38 #if defined(BCM_TRIDENT2_SUPPORT) 39 #include <bcm_int/esw/qos.h> 40 #endif /* BCM_TRIDENT_SUPPORT*/ 41 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 42 #include <bcm_int/esw/trident2plus.h> 43 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 44 #if defined(BCM_HGPROXY_COE_SUPPORT) 45 #include <bcm_int/esw/xgs5.h> 46 #endif /* BCM_HGPROXY_COE_SUPPORT */ 47 #if defined(BCM_TRIDENT3_SUPPORT) 48 #include <bcm_int/esw/trident3.h> 49 #endif /* BCM_TRIDENT_SUPPORT*/ 50 51 #if defined(BCM_TRIDENT3_SUPPORT) 52 #include <bcm_int/esw/trident3.h> 53 #endif /* BCM_TRIDENT3_SUPPORT */ 54 55 #define _BCM_TR3_NUM_ESM_HOST_TABLES (4) 56 #define _BCM_TR3_L3_MEM_BANKS_ALL (-1) 57 #define _BCM_TR3_HOST_ENTRY_NOT_FOUND (-1) 58 59 /* L3 ESM host table state */ 60 static int *_bcm_tr3_esm_host_tbl_freeidx_ptr 61 [_BCM_TR3_NUM_ESM_HOST_TABLES][SOC_MAX_NUM_DEVICES]; 62 #define _TR3_ESM_HOST_TBL_STATE(_u_, _tbl_) \ 63 (_bcm_tr3_esm_host_tbl_freeidx_ptr[(_tbl_)][(_u_)]) 64 #define _TR3_ESM_HOST_TBL_FREE_ENTRY(_u_, _tbl_) \ 65 (*_bcm_tr3_esm_host_tbl_freeidx_ptr[(_tbl_)][(_u_)]) 66 67 extern _bcm_defip_pair128_table_t *l3_defip_pair128[BCM_MAX_NUM_UNITS]; 68 /* ECMP dynamic load balancing internal state */ 69 70 typedef struct _tr3_ecmp_dlb_nh_membership_s { 71 int member_id; /* ECMP DLB member ID assigned to next hop index */ 72 int group; /* ECMP DLB group this member belongs to */ 73 struct _tr3_ecmp_dlb_nh_membership_s *next; 74 } _tr3_ecmp_dlb_nh_membership_t; 75 76 typedef struct _tr3_ecmp_dlb_nh_info_s { 77 int valid; 78 int nh_index; /* next hop index */ 79 _tr3_ecmp_dlb_nh_membership_t *nh_membership_list; 80 /* Linked list of ECMP DLB member IDs assigned to this 81 * next hop index and the ECMP DLB groups the member IDs 82 * belong to. 83 */ 84 } _tr3_ecmp_dlb_nh_info_t; 85 86 typedef struct _tr3_ecmp_dlb_bookkeeping_s { 87 int ecmp_dlb_nh_info_size; /* Size of ecmp_dlb_nh_info array */ 88 _tr3_ecmp_dlb_nh_info_t *ecmp_dlb_nh_info; 89 SHR_BITDCL *ecmp_dlb_id_used_bitmap; 90 SHR_BITDCL *ecmp_dlb_flowset_block_bitmap; /* Each block corresponds to 91 512 entries */ 92 SHR_BITDCL *ecmp_dlb_member_id_used_bitmap; 93 int ecmp_dlb_sample_rate; 94 int ecmp_dlb_tx_load_min_th; 95 int ecmp_dlb_tx_load_max_th; 96 int ecmp_dlb_qsize_min_th; 97 int ecmp_dlb_qsize_max_th; 98 int ecmp_dlb_exp_load_min_th; 99 int ecmp_dlb_exp_load_max_th; 100 int ecmp_dlb_imbalance_min_th; 101 int ecmp_dlb_imbalance_max_th; 102 uint8 *ecmp_dlb_load_weight; 103 soc_profile_mem_t *ecmp_dlb_quality_map_profile; 104 #ifdef BCM_WARM_BOOT_SUPPORT 105 uint8 recovered_from_scache; /* Indicates if the following members of this 106 structure have been recovered from scache: 107 ecmp_dlb_sample_rate, 108 ecmp_dlb_tx_load_min_th, 109 ecmp_dlb_tx_load_max_th, 110 ecmp_dlb_qsize_min_th, 111 ecmp_dlb_qsize_max_th, 112 ecmp_dlb_exp_load_min_th, 113 ecmp_dlb_exp_load_max_th, 114 ecmp_dlb_imbalance_min_th, 115 ecmp_dlb_imbalance_max_th, 116 ecmp_dlb_load_weight */ 117 #endif /* BCM_WARM_BOOT_SUPPORT */ 118 } _tr3_ecmp_dlb_bookkeeping_t; 119 120 static _tr3_ecmp_dlb_bookkeeping_t *_tr3_ecmp_dlb_bk[BCM_MAX_NUM_UNITS]; 121 122 #define ECMP_DLB_INFO(_unit_) (_tr3_ecmp_dlb_bk[_unit_]) 123 #define ECMP_DLB_NH_INFO(_unit_, _idx_) \ 124 (_tr3_ecmp_dlb_bk[_unit_]->ecmp_dlb_nh_info[_idx_]) 125 126 #define _BCM_ECMP_DLB_ID_USED_GET(_u_, _idx_) \ 127 SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_) 128 #define _BCM_ECMP_DLB_ID_USED_SET(_u_, _idx_) \ 129 SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_) 130 #define _BCM_ECMP_DLB_ID_USED_CLR(_u_, _idx_) \ 131 SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_) 132 133 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \ 134 SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_) 135 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \ 136 SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_) 137 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \ 138 SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_) 139 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \ 140 SHR_BITSET_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_) 141 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \ 142 SHR_BITCLR_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_) 143 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \ 144 SHR_BITTEST_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_, _result_) 145 146 #define _BCM_ECMP_DLB_MEMBER_ID_USED_GET(_u_, _idx_) \ 147 SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_member_id_used_bitmap, _idx_) 148 #define _BCM_ECMP_DLB_MEMBER_ID_USED_SET(_u_, _idx_) \ 149 SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_member_id_used_bitmap, _idx_) 150 #define _BCM_ECMP_DLB_MEMBER_ID_USED_CLR(_u_, _idx_) \ 151 SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_member_id_used_bitmap, _idx_) 152 153 /*----- STATIC FUNCS ----- */ 154 /* 155 * Function: 156 * _bcm_tr3_l3_ent_init 157 * Purpose: 158 * Tr3 helper routine used to init l3 host entry buffer 159 * Parameters: 160 * unit - (IN) SOC unit number. 161 * mem - (IN) L3 table memory. 162 * l3cfg - (IN/OUT) l3 entry lookup key & search result. 163 * l3x_entry - (IN) hw buffer. 164 * Returns: 165 * void 166 */ 167 STATIC int 168 _bcm_tr3_l3_ent_init(int unit, soc_mem_t mem, 169 _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 170 { 171 int esm; 172 int ipv6; /* Entry is IPv6 flag. */ 173 uint32 *buf_p; /* HW buffer address. */ 174 175 /* Get entry type. */ 176 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 177 178 esm = BCM_TR3_MEM_IS_ESM(unit, mem); 179 180 /* Zero destination buffer. */ 181 buf_p = (uint32 *)l3x_entry; 182 sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 183 184 if (esm) { 185 if (ipv6) { 186 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDRf, l3cfg->l3c_ip6, 0); 187 } else { 188 soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf, l3cfg->l3c_ip_addr); 189 } 190 soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, l3cfg->l3c_vrf); 191 /* ESM VALID bit is set/unset in EXT_TCAM_VBIT table in 192 * the ESM add/del function */ 193 } else { 194 if (ipv6) { /* ipv6 entry */ 195 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_LWR_64f, 196 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 197 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_UPR_64f, 198 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 199 soc_mem_field32_set(unit, mem, buf_p, IPV6UC__VRF_IDf, 200 l3cfg->l3c_vrf); 201 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 202 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 203 if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) { 204 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 2); 205 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 2); 206 } else if (BCM_XGS3_L3_MEM(unit, v6_4) == mem) { 207 /* ipv6 extended host entry */ 208 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 3); 209 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 3); 210 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_2f, 3); 211 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_3f, 3); 212 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 213 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 214 soc_mem_field32_set(unit, mem, buf_p, VALID_2f, 1); 215 soc_mem_field32_set(unit, mem, buf_p, VALID_3f, 1); 216 } else { 217 return BCM_E_NOT_FOUND; 218 } 219 } else { /* ipv4 entry */ 220 soc_mem_field32_set(unit, mem, buf_p, IPV4UC__IP_ADDRf, 221 l3cfg->l3c_ip_addr); 222 soc_mem_field32_set(unit, mem, buf_p, IPV4UC__VRF_IDf, 223 l3cfg->l3c_vrf); 224 if (BCM_XGS3_L3_MEM(unit, v4) == mem) { 225 /* ipv4 unicast */ 226 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 0); 227 soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1); 228 } else if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) { 229 /* ipv4 extended host entry */ 230 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 1); 231 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 1); 232 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 233 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 234 } else { 235 return BCM_E_NOT_FOUND; 236 } 237 } 238 } 239 240 return BCM_E_NONE; 241 } 242 243 /* 244 * Function: 245 * _bcm_tr3_l3_ipmc_ent_init 246 * Purpose: 247 * Set GROUP/SOURCE/VID/IMPC flag in the entry. 248 * Parameters: 249 * unit - (IN)SOC unit number. 250 * l3x_entry - (IN/OUT) IPMC entry to fill. 251 * l3cfg - (IN) Api IPMC data. 252 * Returns: 253 * BCM_E_XXX 254 */ 255 STATIC void 256 _bcm_tr3_l3_ipmc_ent_init(int unit, uint32 *buf_p, 257 _bcm_l3_cfg_t *l3cfg) 258 { 259 soc_mem_t mem; /* IPMC table memory. */ 260 int ipv6; /* IPv6 entry indicator. */ 261 int idx; /* Iteration index. */ 262 soc_field_t v4typef[] = { KEY_TYPE_0f, KEY_TYPE_1f }; 263 soc_field_t v6typef[] = { KEY_TYPE_0f, KEY_TYPE_1f, 264 KEY_TYPE_2f, KEY_TYPE_3f }; 265 soc_field_t validf[] = { VALID_0f, VALID_1f, VALID_2f, VALID_3f }; 266 267 /* Get entry type. */ 268 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 269 270 /* Get table memory. */ 271 mem = (ipv6) ? L3_ENTRY_4m : L3_ENTRY_2m; 272 273 sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 274 275 if (ipv6) { 276 /* Set group address. */ 277 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_96f, 278 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_96BIT); 279 l3cfg->l3c_ip6[0] = 0x0; /* Don't write ff entry already mcast. */ 280 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_24f, 281 l3cfg->l3c_ip6, SOC_MEM_IP6_BITS_119_96); 282 l3cfg->l3c_ip6[0] = 0xff; /* Restore The entry */ 283 284 /* Set source address. */ 285 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 286 l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY); 287 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 288 l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY); 289 290 for (idx = 0; idx < 4; idx++) { 291 /* Set key type */ 292 soc_mem_field32_set(unit, mem, buf_p, v6typef[idx], 293 SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST); 294 295 /* Set entry valid bit. */ 296 soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1); 297 298 } 299 300 /* Set vlan id or L3_IIF. */ 301 if (l3cfg->l3c_vid < 4096) { 302 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VLAN_IDf, l3cfg->l3c_vid); 303 } else { 304 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__L3_IIFf, l3cfg->l3c_vid); 305 } 306 307 /* Set virtual router id. */ 308 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VRF_IDf, l3cfg->l3c_vrf); 309 310 } else { 311 /* Set group id. */ 312 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf, 313 l3cfg->l3c_ip_addr); 314 315 /* Set source address. */ 316 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__SOURCE_IP_ADDRf, 317 l3cfg->l3c_src_ip_addr); 318 319 for (idx = 0; idx < 2; idx++) { 320 /* Set key type */ 321 soc_mem_field32_set(unit, mem, buf_p, v4typef[idx], 322 SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST); 323 324 /* Set entry valid bit. */ 325 soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1); 326 } 327 328 /* Set vlan id or L3_IIF. */ 329 if (l3cfg->l3c_vid < 4096) { 330 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VLAN_IDf, l3cfg->l3c_vid); 331 } else { 332 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__L3_IIFf, l3cfg->l3c_vid); 333 } 334 335 /* Set virtual router id. */ 336 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VRF_IDf, l3cfg->l3c_vrf); 337 } 338 339 return; 340 } 341 342 /* 343 * Function: 344 * _bcm_tr3_l3_ent_parse 345 * Purpose: 346 * Tr3 helper routine used to parse hw l3 entry to api format. 347 * Parameters: 348 * unit - (IN) SOC unit number. 349 * mem - (IN) L3 table memory. 350 * l3cfg - (IN/OUT) l3 entry key & parse result. 351 * nh_idx - (IN/OUT) Next hop index. 352 * l3x_entry - (IN) hw buffer. 353 * Returns: 354 * void 355 */ 356 STATIC int 357 _bcm_tr3_l3_ent_parse(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, 358 int *nh_idx, void *l3x_entry) 359 { 360 int idx; /* Iteration index. */ 361 int ipv6; /* Entry is IPv6 flag. */ 362 uint32 *buf_p; /* HW buffer address. */ 363 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 364 int embedded_nh = FALSE; 365 soc_field_t ism_hitf[] = {HIT_0f, HIT_1f, HIT_2f}; 366 soc_field_t esm_hitf[] = {SRC_HITf, DST_HITf}; 367 int esm = FALSE; 368 uint32 glp; 369 370 buf_p = (uint32 *)l3x_entry; 371 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 372 373 /* Set table fields */ 374 if (BCM_TR3_MEM_IS_ESM(unit, mem)) { 375 BCM_TR3_ESM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 376 esm = TRUE; 377 } else { 378 BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 379 } 380 381 /* Check if embedded NH table is being used */ 382 embedded_nh = (mem == L3_ENTRY_2m && !ipv6) || 383 (mem == L3_ENTRY_4m && ipv6) || 384 (mem == EXT_IPV4_UCAST_WIDEm) || 385 (mem == EXT_IPV6_128_UCAST_WIDEm); 386 387 /* Reset entry flags */ 388 l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0; 389 390 /* Set hit bit. */ 391 if (esm) { 392 /* For ESM Memory */ 393 if (soc_mem_field32_get(unit, mem, buf_p, esm_hitf[0])) { 394 l3cfg->l3c_flags |= BCM_L3_S_HIT; 395 } 396 if (soc_mem_field32_get(unit, mem, buf_p, esm_hitf[1])) { 397 l3cfg->l3c_flags |= BCM_L3_D_HIT; 398 } 399 } else { 400 /* For ISM Memory */ 401 for (idx = 0; idx < COUNTOF(ism_hitf); idx++) { 402 if (soc_mem_field32_get(unit, mem, buf_p, ism_hitf[idx])) { 403 l3cfg->l3c_flags |= BCM_L3_HIT; 404 } 405 } 406 } 407 408 /* Get priority override flag. */ 409 if (soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) { 410 l3cfg->l3c_flags |= BCM_L3_RPE; 411 } 412 413 /* Get destination discard flag. */ 414 if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) { 415 if (soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) { 416 l3cfg->l3c_flags |= BCM_L3_DST_DISCARD; 417 } 418 } 419 420 /* Get local addr bit. */ 421 if (SOC_MEM_FIELD_VALID(unit, mem, fld->local_addr)) { 422 if (soc_mem_field32_get(unit, mem, buf_p, fld->local_addr)) { 423 l3cfg->l3c_flags |= BCM_L3_HOST_LOCAL; 424 } 425 } 426 427 /* Get classification group id. */ 428 l3cfg->l3c_lookup_class = 429 soc_mem_field32_get(unit, mem, buf_p, fld->class_id); 430 431 /* Get priority. */ 432 l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority); 433 434 /* Get virtual router id. */ 435 l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf); 436 437 if (embedded_nh) { 438 uint8 port_mask_len = 0, modid_mask_len = 0; 439 uint32 temp = 0; 440 441 if (nh_idx) { 442 *nh_idx = BCM_XGS3_L3_INVALID_INDEX; /* Embedded NH */ 443 } 444 l3cfg->l3c_intf = soc_mem_field32_get(unit, mem, buf_p, 445 fld->l3_intf); 446 soc_mem_mac_addr_get(unit, mem, buf_p, fld->mac_addr, 447 l3cfg->l3c_mac_addr); 448 glp = soc_mem_field32_get(unit, mem, buf_p, fld->glp); 449 /* Determine length of port mask */ 450 temp = SOC_PORT_ADDR_MAX(unit); 451 while (0 != temp) { 452 port_mask_len++; 453 temp >>= 1; 454 } 455 /* Determine length of modid mask */ 456 temp = SOC_MODID_MAX(unit); 457 while (0 != temp) { 458 modid_mask_len++; 459 temp >>= 1; 460 } 461 462 if (glp & (1 << (port_mask_len + modid_mask_len))) { 463 l3cfg->l3c_flags |= BCM_L3_TGID; 464 l3cfg->l3c_port_tgid = glp & BCM_TGID_PORT_TRUNK_MASK(unit); 465 l3cfg->l3c_modid = 0; 466 } else { 467 l3cfg->l3c_port_tgid = glp & SOC_PORT_ADDR_MAX(unit); 468 l3cfg->l3c_modid = (glp >> port_mask_len) 469 & SOC_MODID_MAX(unit); 470 } 471 } else { 472 /* Get next hop info. */ 473 if (nh_idx) { 474 *nh_idx = soc_mem_field32_get(unit, mem, buf_p, fld->nh_idx); 475 } 476 } 477 478 return BCM_E_NONE; 479 } 480 481 /* 482 * Function: 483 * _bcm_tr3_l3_clear_hit 484 * Purpose: 485 * Clear hit bit on l3 entry 486 * Parameters: 487 * unit - (IN)SOC unit number. 488 * mem - (IN)L3 table memory. 489 * l3cfg - (IN)l3 entry info. 490 * l3x_entry - (IN)l3 entry filled hw buffer. 491 * Returns: 492 * BCM_E_XXX 493 */ 494 STATIC int 495 _bcm_tr3_l3_clear_hit(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, 496 void *l3x_entry, int l3_entry_idx) 497 { 498 uint32 *buf_p; /* HW buffer address. */ 499 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f}; 500 int i; 501 502 /* Input parameters check */ 503 if ((NULL == l3cfg) || (NULL == l3x_entry)) { 504 return (BCM_E_PARAM); 505 } 506 507 /* Init memory pointers. */ 508 buf_p = (uint32 *)l3x_entry; 509 510 /* If entry was not hit there is nothing to clear */ 511 if (!(l3cfg->l3c_flags & BCM_L3_HIT)) { 512 return (BCM_E_NONE); 513 } 514 515 /* Clear hit bits */ 516 for (i = 0; i < COUNTOF(hitf); i++) { 517 soc_mem_field32_set(unit, mem, buf_p, hitf[i], 0); 518 } 519 520 /* Write entry back to hw. */ 521 return BCM_XGS3_MEM_WRITE(unit, mem, l3_entry_idx, buf_p); 522 } 523 524 /* 525 * Function: 526 * _bcm_tr3_l3_ism_add 527 * Purpose: 528 * Add and entry to Tr3 ISM L3 host table. 529 * Parameters: 530 * unit - (IN) SOC unit number. 531 * l3cfg - (IN) L3 entry info. 532 * nh_idx - (IN) Next hop index. 533 * Returns: 534 * BCM_E_XXX 535 */ 536 STATIC int 537 _bcm_tr3_l3_ism_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 538 { 539 int idx; /* Iteration index. */ 540 int ipv6; 541 uint32 *bufp; /* Hardware buffer ptr */ 542 soc_mem_t mem; /* L3 table memory. */ 543 int rv = BCM_E_NONE; /* Operation status. */ 544 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 545 int embedded_nh = FALSE; 546 uint32 glp, port_id, modid; 547 _bcm_l3_intf_cfg_t l3_intf; 548 l3_entry_1_entry_t l3v4_entry; 549 l3_entry_2_entry_t l3v4v6_entry; 550 l3_entry_4_entry_t l3v6_ext_entry; 551 soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f}; 552 553 /* Get entry type. */ 554 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 555 556 /* Check if embedded NH table is being used */ 557 embedded_nh = BCM_TR3_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx); 558 559 /* Get table memory. */ 560 BCM_TR3_ISM_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx); 561 562 /* Set table fields */ 563 BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 564 565 /* Assign entry buf based on table being used */ 566 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, 567 l3v4_entry, 568 l3v4v6_entry, 569 l3v6_ext_entry); 570 571 /* Prepare ISM host entry for addition. */ 572 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, bufp)); 573 574 /* Set hit bit. */ 575 for (idx = 0; idx < COUNTOF(hitf); idx++) { 576 if (l3cfg->l3c_flags & BCM_L3_HIT) { 577 soc_mem_field32_set(unit, mem, bufp, hitf[idx], 1); 578 } 579 } 580 581 /* Set priority override bit. */ 582 if (l3cfg->l3c_flags & BCM_L3_RPE) { 583 soc_mem_field32_set(unit, mem, bufp, fld->rpe, 1); 584 } 585 586 /* Set destination discard bit. */ 587 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 588 soc_mem_field32_set(unit, mem, bufp, fld->dst_discard, 1); 589 } 590 591 /* Set local addr bit. */ 592 if (l3cfg->l3c_flags & BCM_L3_HOST_LOCAL) { 593 soc_mem_field32_set(unit, mem, bufp, fld->local_addr, 1); 594 } 595 596 /* Set classification group id. */ 597 soc_mem_field32_set(unit, mem, bufp, fld->class_id, 598 l3cfg->l3c_lookup_class); 599 /* Set priority. */ 600 soc_mem_field32_set(unit, mem, bufp, fld->priority, l3cfg->l3c_prio); 601 602 if (embedded_nh) { 603 sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 604 BCM_XGS3_L3_INTF_IDX_SET(l3_intf, l3cfg->l3c_intf); 605 606 BCM_XGS3_L3_MODULE_LOCK(unit); 607 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf); 608 BCM_XGS3_L3_MODULE_UNLOCK(unit); 609 if (rv >= 0) { 610 soc_mem_field32_set(unit, mem, bufp, fld->l3_oif, l3_intf.l3i_vid); 611 } 612 613 if (l3cfg->l3c_flags & BCM_L3_TGID) { 614 port_id = (BCM_TGID_PORT_TRUNK_MASK(unit) & l3cfg->l3c_port_tgid); 615 glp = (1 << (SOC_TRUNK_BIT_POS(unit))) |port_id; 616 } else { 617 port_id = (_BCM_TR3_L3_PORT_MASK & l3cfg->l3c_port_tgid); 618 modid = (_BCM_TR3_L3_MODID_MASK & l3cfg->l3c_modid) << 619 _BCM_TR3_L3_MODID_SHIFT; 620 glp = modid | port_id; 621 } 622 623 soc_mem_mac_addr_set(unit, mem, bufp, 624 fld->mac_addr, l3cfg->l3c_mac_addr); 625 soc_mem_field32_set(unit, mem, bufp, fld->l3_intf, l3cfg->l3c_intf); 626 soc_mem_field32_set(unit, mem, bufp, fld->glp, glp); 627 } else { 628 /* Set next hop index. */ 629 soc_mem_field32_set(unit, mem, bufp, fld->nh_idx, nh_idx); 630 } 631 632 /* Insert in ISM table */ 633 rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, bufp); 634 635 /* Handle host entry 'replace' actions */ 636 if ((BCM_E_EXISTS == rv) && (l3cfg->l3c_flags & BCM_L3_REPLACE)) { 637 rv = BCM_E_NONE; 638 } 639 640 /* Write status check. */ 641 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 642 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++; 643 } 644 645 return rv; 646 } 647 648 /* 649 * Function: 650 * _bcm_tr3_l3_esm_add 651 * Purpose: 652 * Add and entry to Tr3 ESM L3 host table. 653 * Parameters: 654 * unit - (IN) SOC unit number. 655 * l3cfg - (IN) L3 entry info. 656 * nh_idx - (IN) Next hop index. 657 * Returns: 658 * BCM_E_XXX 659 */ 660 STATIC int 661 _bcm_tr3_l3_esm_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 662 { 663 int ipv6; 664 uint32 *bufp; /* Hardware buffer ptr */ 665 soc_mem_t mem; /* ESM L3 table memory. */ 666 soc_mem_t mem_data; /* ESM L3 table memory - data only */ 667 int rv = BCM_E_NONE; /* Operation status. */ 668 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 669 int tbl, tbl_free_entry; 670 int embedded_nh = FALSE; 671 uint32 glp, port_id, modid; 672 _bcm_l3_intf_cfg_t l3_intf; 673 ext_ipv4_ucast_entry_t l3v4_entry; 674 ext_ipv4_ucast_wide_entry_t l3v4wide_entry; 675 ext_ipv6_128_ucast_entry_t l3v6_entry; 676 ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry; 677 678 /* Get entry type. */ 679 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 680 681 /* Check if embedded NH table is being used */ 682 embedded_nh = BCM_TR3_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx); 683 684 /* Get table memory. */ 685 BCM_TR3_ESM_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx); 686 687 /* Set table fields */ 688 BCM_TR3_ESM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 689 690 /* Assign entry buf based on table being used */ 691 BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, 692 l3v4_entry, 693 l3v4wide_entry, 694 l3v6_entry, 695 l3v6wide_entry); 696 697 /* Prepare ESM host entry for addition. */ 698 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, bufp)); 699 700 /* Set hit bit. */ 701 if (l3cfg->l3c_flags & BCM_L3_HIT) { 702 soc_mem_field32_set(unit, mem, bufp, fld->hit, 1); 703 } 704 705 /* Set priority override bit. */ 706 if (l3cfg->l3c_flags & BCM_L3_RPE) { 707 soc_mem_field32_set(unit, mem, bufp, fld->rpe, 1); 708 } 709 710 /* Set destination discard bit. */ 711 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 712 if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) { 713 soc_mem_field32_set(unit, mem, bufp, fld->dst_discard, 1); 714 } 715 } 716 717 /* Set local addr bit. */ 718 if (l3cfg->l3c_flags & BCM_L3_HOST_LOCAL) { 719 if (SOC_MEM_FIELD_VALID(unit, mem, fld->local_addr)) { 720 soc_mem_field32_set(unit, mem, bufp, fld->local_addr, 1); 721 } 722 } 723 724 /* Set classification group id. */ 725 soc_mem_field32_set(unit, mem, bufp, fld->class_id, 726 l3cfg->l3c_lookup_class); 727 /* Set priority. */ 728 soc_mem_field32_set(unit, mem, bufp, fld->priority, l3cfg->l3c_prio); 729 730 if (embedded_nh) { 731 sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t)); 732 BCM_XGS3_L3_INTF_IDX_SET(l3_intf, l3cfg->l3c_intf); 733 734 BCM_XGS3_L3_MODULE_LOCK(unit); 735 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf); 736 BCM_XGS3_L3_MODULE_UNLOCK(unit); 737 if (rv >= 0) { 738 soc_mem_field32_set(unit, mem, bufp, fld->l3_oif, l3_intf.l3i_vid); 739 } 740 741 if (l3cfg->l3c_flags & BCM_L3_TGID) { 742 port_id = (BCM_TGID_PORT_TRUNK_MASK(unit) & l3cfg->l3c_port_tgid); 743 glp = (1 << (SOC_TRUNK_BIT_POS(unit))) | port_id; 744 } else { 745 port_id = (_BCM_TR3_L3_PORT_MASK & l3cfg->l3c_port_tgid); 746 modid = (_BCM_TR3_L3_MODID_MASK & l3cfg->l3c_modid) << 747 _BCM_TR3_L3_MODID_SHIFT; 748 glp = modid | port_id; 749 } 750 751 soc_mem_mac_addr_set(unit, mem, bufp, 752 fld->mac_addr, l3cfg->l3c_mac_addr); 753 soc_mem_field32_set(unit, mem, bufp, fld->l3_intf, l3cfg->l3c_intf); 754 soc_mem_field32_set(unit, mem, bufp, fld->glp, glp); 755 } else { 756 /* Set next hop index. */ 757 soc_mem_field32_set(unit, mem, bufp, fld->nh_idx, nh_idx); 758 } 759 760 /* Write to ESM table */ 761 BCM_TR3_ESM_TBL_ENUMERATE(mem, tbl); 762 763 /* Perform lookup */ 764 rv = soc_tr3_search_ext_mem(unit, &mem, bufp, &tbl_free_entry); 765 if (BCM_E_NONE == rv) { /* Entry exists */ 766 if (l3cfg->l3c_flags & BCM_L3_REPLACE) { 767 l3cfg->l3c_hw_index = tbl_free_entry; 768 } else { 769 return rv; 770 } 771 } else if (BCM_E_NOT_FOUND == rv) { 772 tbl_free_entry = _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl); 773 rv = BCM_E_NONE; 774 775 } else { 776 return rv; 777 } 778 779 if (tbl_free_entry <= soc_mem_index_max(unit, mem)) { 780 BCM_IF_ERROR_RETURN(soc_mem_write( unit, mem, MEM_BLOCK_ALL, 781 tbl_free_entry, bufp)); 782 783 /* Point to next free entry in the table */ 784 _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) += 1; 785 tbl_free_entry = _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl); 786 787 /* Set invalid entry marker */ 788 if (tbl_free_entry <= soc_mem_index_max(unit, mem)) { 789 switch(mem) { 790 case EXT_IPV4_UCASTm: 791 mem_data = EXT_L3_UCAST_DATA_IPV4m; 792 break; 793 case EXT_IPV4_UCAST_WIDEm: 794 mem_data = EXT_L3_UCAST_DATA_WIDE_IPV4m; 795 break; 796 case EXT_IPV6_128_UCASTm: 797 mem_data = EXT_L3_UCAST_DATA_IPV6_128m; 798 break; 799 case EXT_IPV6_128_UCAST_WIDEm: 800 mem_data = EXT_L3_UCAST_DATA_WIDE_IPV6_128m; 801 break; 802 default: 803 return BCM_E_INTERNAL; /* should never happen */ 804 } 805 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem_data, MEM_BLOCK_ANY, 806 tbl_free_entry, bufp)); 807 soc_mem_field32_set(unit, mem_data, bufp, CLASS_IDf, 808 _TR3_ESM_HOST_ENTRY_INVALID_MARKER); 809 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem_data, MEM_BLOCK_ALL, 810 tbl_free_entry, bufp)); 811 } 812 813 } else { 814 rv = (BCM_E_FULL); 815 } 816 817 /* Write status check. */ 818 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 819 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++; 820 } 821 822 return rv; 823 } 824 825 /* 826 * Function: 827 * _bcm_tr3_l3_ism_get 828 * Purpose: 829 * Get an entry from Tr3 ISM L3 host table. 830 * Parameters: 831 * unit - (IN) SOC unit number. 832 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 833 * nh_index - (IN/OUT) Next hop index. 834 * embd - (OUT) If TRUE, entry was found as embedded NH. 835 * Returns: 836 * BCM_E_XXX 837 */ 838 STATIC int 839 _bcm_tr3_l3_ism_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int *embd) 840 { 841 int ipv6; /* IPv6 entry indicator. */ 842 int clear_hit; /* Clear hit bit. */ 843 int rv = BCM_E_NONE; /* Operation return status. */ 844 soc_mem_t mem, mem_ext; /* L3 table memories */ 845 uint32 *buf_key, *buf_entry; /* Key and entry buffer ptrs*/ 846 l3_entry_1_entry_t l3v4_key, l3v4_entry; /* Lookup key and entry */ 847 l3_entry_2_entry_t l3v4v6_key, l3v4v6_entry; /* Lookup key and entry*/ 848 l3_entry_4_entry_t l3v6_ext_key, l3v6_ext_entry; /* Lookup key and entry*/ 849 850 /* Indexed NH entry */ 851 *embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 852 853 /* Get entry type. */ 854 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 855 856 /* Preserve clear_hit value. */ 857 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 858 859 /* Table memories */ 860 if (ipv6) { 861 mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4); 862 } else { 863 mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2); 864 } 865 866 /* Assign entry-key buf based on table being used */ 867 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, 868 l3v4_key, 869 l3v4v6_key, 870 l3v6_ext_key); 871 872 /* Assign entry buf based on table being used */ 873 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 874 l3v4_entry, 875 l3v4v6_entry, 876 l3v6_ext_entry); 877 /* Prepare lookup key. */ 878 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_key)); 879 880 /* Perform lookup */ 881 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 882 _BCM_TR3_L3_MEM_BANKS_ALL, 883 buf_key, buf_entry, &l3cfg->l3c_hw_index); 884 if (BCM_SUCCESS(rv)) { 885 /* Indexed NH entry */ 886 *embd = FALSE; 887 /* Extract entry info. */ 888 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_parse(unit, mem, l3cfg, 889 nh_idx, buf_entry)); 890 /* Clear the HIT bit */ 891 if (clear_hit) { 892 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, 893 l3cfg, buf_entry, l3cfg->l3c_hw_index)); 894 } 895 } else if ((BCM_E_NOT_FOUND == rv) && 896 (soc_feature(unit, soc_feature_l3_extended_host_entry))) { 897 /* Search in the extended tables only if the extended host entry 898 * feature is supported and if the entry was not found in the 899 * regular host entry */ 900 901 /* Assign entry-key buf based on table being used */ 902 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key, 903 l3v4_key, 904 l3v4v6_key, 905 l3v6_ext_key); 906 907 /* Assign entry buf based on table being used */ 908 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 909 l3v4_entry, 910 l3v4v6_entry, 911 l3v6_ext_entry); 912 913 /* Prepare lookup key. */ 914 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem_ext, l3cfg, buf_key)); 915 916 /* Perform lookup hw. */ 917 rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY, 918 _BCM_TR3_L3_MEM_BANKS_ALL, 919 buf_key, buf_entry, &l3cfg->l3c_hw_index); 920 921 if (BCM_SUCCESS(rv)) { 922 923 /* Embedded NH entry */ 924 *embd = TRUE; 925 /* Extract entry info. */ 926 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_parse(unit, mem_ext, l3cfg, 927 nh_idx, buf_entry)); 928 /* Clear the HIT bit */ 929 if (clear_hit) { 930 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem_ext, 931 l3cfg, buf_entry, l3cfg->l3c_hw_index)); 932 } 933 } 934 } 935 936 return rv; 937 } 938 939 /* 940 * Function: 941 * _bcm_tr3_l3_esm_get 942 * Purpose: 943 * Get an entry from Tr3 ESM L3 host table. 944 * Parameters: 945 * unit - (IN) SOC unit number. 946 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 947 * nh_index - (IN/OUT) Next hop index. 948 * embd - (OUT) If TRUE, entry was found as embedded NH. 949 * Returns: 950 * BCM_E_XXX 951 */ 952 STATIC int 953 _bcm_tr3_l3_esm_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int *embd) 954 { 955 int ipv6; /* IPv6 entry indicator. */ 956 int clear_hit; /* Clear hit bit. */ 957 int rv = BCM_E_NONE; /* Operation return status. */ 958 soc_mem_t mem; /* L3 table memories */ 959 uint32 *buf_key; /* Key and entry buffer ptrs*/ 960 ext_ipv4_ucast_entry_t l3v4_key; 961 ext_ipv4_ucast_wide_entry_t l3v4wide_key; 962 ext_ipv6_128_ucast_entry_t l3v6_key; 963 ext_ipv6_128_ucast_wide_entry_t l3v6wide_key; 964 965 /* Indexed NH entry */ 966 *embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 967 968 /* Get entry type. */ 969 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 970 971 /* Preserve clear_hit value. */ 972 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 973 974 /* Table memories */ 975 if (ipv6) { 976 mem = BCM_XGS3_L3_MEM(unit, v6_esm); 977 } else { 978 mem = BCM_XGS3_L3_MEM(unit, v4_esm); 979 } 980 981 /* Assign entry-key buf based on table being used */ 982 BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, 983 l3v4_key, 984 l3v4wide_key, 985 l3v6_key, 986 l3v6wide_key); 987 988 /* Prepare lookup key. */ 989 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_key)); 990 991 /* Perform lookup */ 992 rv = soc_tr3_search_ext_mem(unit, &mem, buf_key, &l3cfg->l3c_hw_index); 993 994 if (BCM_SUCCESS(rv)) { 995 /* Set to true if the entry was found in a wide host entry */ 996 *embd = ((mem == BCM_XGS3_L3_MEM(unit, v6_esm_wide)) || 997 (mem == BCM_XGS3_L3_MEM(unit, v4_esm_wide))) ? TRUE : FALSE; 998 999 if ((*embd) && 1000 (!soc_feature(unit, soc_feature_l3_extended_host_entry))) { 1001 /* Flag error if the entry was found in the extended host table 1002 * but the extended host entries are not supported 1003 * NOTE: This should never occur, as the 'host add' operation 1004 * should take care of this. */ 1005 return BCM_E_PARAM; 1006 } 1007 1008 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, 1009 l3cfg->l3c_hw_index, buf_key)); 1010 /* Extract entry info. */ 1011 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_parse(unit, mem, l3cfg, 1012 nh_idx, buf_key)); 1013 /* Clear the HIT bit */ 1014 if (clear_hit) { 1015 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, 1016 l3cfg, buf_key, l3cfg->l3c_hw_index)); 1017 } 1018 } 1019 1020 return rv; 1021 } 1022 1023 /* 1024 * Function: 1025 * _bcm_tr3_l3_ism_del 1026 * Purpose: 1027 * Delete an entry from Tr3 ISM L3 host table. 1028 * Parameters: 1029 * unit - (IN) SOC unit number. 1030 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 1031 * nh_index - (IN/OUT) Next hop index. 1032 * Returns: 1033 * BCM_E_XXX 1034 */ 1035 STATIC int 1036 _bcm_tr3_l3_ism_del(int unit, _bcm_l3_cfg_t *l3cfg) 1037 { 1038 int ipv6; /* IPv6 entry indicator.*/ 1039 soc_mem_t mem, mem_ext; /* L3 table memory. */ 1040 int rv = BCM_E_NONE; /* Operation status. */ 1041 uint32 *buf_entry; /* Entry buffer ptrs */ 1042 l3_entry_1_entry_t l3v4_entry; /* Lookup entry */ 1043 l3_entry_2_entry_t l3v4v6_entry; /* Lookup entry */ 1044 l3_entry_4_entry_t l3v6_ext_entry; /* Lookup entry */ 1045 1046 /* Get entry type. */ 1047 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1048 1049 if (ipv6) { 1050 mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4); 1051 } else { 1052 mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2); 1053 } 1054 1055 /* Assign entry-key buf based on table being used */ 1056 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1057 l3v4_entry, 1058 l3v4v6_entry, 1059 l3v6_ext_entry); 1060 /* Prepare lookup key. */ 1061 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_entry)); 1062 1063 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void*) buf_entry); 1064 1065 if ((BCM_E_NOT_FOUND == rv) && 1066 (soc_feature(unit, soc_feature_l3_extended_host_entry))) { 1067 /* Delete from the extended tables only if the extended host entry 1068 * feature is supported and if the entry was not found in the 1069 * regular host entry */ 1070 1071 /* Assign entry-key buf based on table being used */ 1072 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 1073 l3v4_entry, 1074 l3v4v6_entry, 1075 l3v6_ext_entry); 1076 /* Prepare lookup key. */ 1077 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem_ext, l3cfg, buf_entry)); 1078 1079 rv = soc_mem_delete(unit, mem_ext, MEM_BLOCK_ANY, (void*) buf_entry); 1080 } 1081 1082 /* Write status check. */ 1083 if (BCM_SUCCESS(rv)) { 1084 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--; 1085 } 1086 1087 return rv; 1088 } 1089 1090 /* 1091 * Function: 1092 * _bcm_tr3_l3_esm_del 1093 * Purpose: 1094 * Delete an entry from Tr3 ESM L3 host table. 1095 * Parameters: 1096 * unit - (IN) SOC unit number. 1097 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 1098 * nh_index - (IN/OUT) Next hop index. 1099 * Returns: 1100 * BCM_E_XXX 1101 */ 1102 STATIC int 1103 _bcm_tr3_l3_esm_del(int unit, _bcm_l3_cfg_t *l3cfg) 1104 { 1105 int tbl; /* Table enumeration */ 1106 int ipv6; /* IPv6 entry indicator.*/ 1107 int l3_entry_idx; /* Index of L3 host entry */ 1108 void *null_entry; /* Null entry for delete opearation */ 1109 int rv = BCM_E_NONE; /* Operation status. */ 1110 soc_mem_t mem; /* L3 table memory. */ 1111 soc_mem_t mem_data; /* L3 table memory - associated data */ 1112 uint32 *buf_key, *buf_entry = NULL; /* Key and entry buffer ptrs*/ 1113 ext_ipv4_ucast_entry_t l3v4_entry; 1114 ext_ipv4_ucast_wide_entry_t l3v4wide_entry; 1115 ext_ipv6_128_ucast_entry_t l3v6_entry; 1116 ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry; 1117 1118 /* Get entry type. */ 1119 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1120 1121 if (ipv6) { 1122 mem = BCM_XGS3_L3_MEM(unit, v6_esm); 1123 } else { 1124 mem = BCM_XGS3_L3_MEM(unit, v4_esm); 1125 } 1126 1127 /* Assign entry-key buf based on table being used */ 1128 BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, 1129 l3v4_entry, 1130 l3v4wide_entry, 1131 l3v6_entry, 1132 l3v6wide_entry); 1133 1134 /* Prepare lookup key. */ 1135 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_key)); 1136 1137 /* Lookup TCAM with the key provided */ 1138 rv = soc_tr3_search_ext_mem(unit, &mem, buf_key, &l3_entry_idx); 1139 if (BCM_SUCCESS(rv)) { 1140 1141 if ((!soc_feature(unit, soc_feature_l3_extended_host_entry)) && 1142 ((mem == EXT_IPV4_UCAST_WIDEm) || (mem == EXT_IPV6_128_UCAST_WIDEm))) { 1143 /* Flag error if the entry was found in the extended host table 1144 * of ESM but the extended host entries are not supported 1145 * NOTE: This should never occur, as the 'host add' operation 1146 * should take care of this. */ 1147 return BCM_E_PARAM; 1148 } 1149 1150 /* Write null entry at l3_entry_idx, clear vbit */ 1151 null_entry = soc_mem_entry_null(unit, mem); 1152 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 1153 l3_entry_idx, null_entry)); 1154 soc_tr3_set_vbit(unit, mem, l3_entry_idx, 0); 1155 1156 /* Move the last valid entry in place of deleted entry to keep 1157 * entries contiguous - this works because host entry hit is 1158 * an exact match, not LPM */ 1159 BCM_TR3_ESM_TBL_ENUMERATE(mem, tbl); 1160 BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1161 l3v4_entry, 1162 l3v4wide_entry, 1163 l3v6_entry, 1164 l3v6wide_entry); 1165 /* Read last entry */ 1166 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY, 1167 (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) - 1), 1168 buf_entry)); 1169 /* Write last entry to index of entry that was deleted */ 1170 /* This entry is now valid */ 1171 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 1172 l3_entry_idx, buf_entry)); 1173 1174 /* The last entry is now invalid because it has been moved in place 1175 * of the deleted entry. Write invalid entry marker here */ 1176 soc_tr3_set_vbit(unit, mem, 1177 (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) - 1), 0); 1178 switch(mem) { 1179 case EXT_IPV4_UCASTm: 1180 mem_data = EXT_L3_UCAST_DATA_IPV4m; 1181 break; 1182 case EXT_IPV4_UCAST_WIDEm: 1183 mem_data = EXT_L3_UCAST_DATA_WIDE_IPV4m; 1184 break; 1185 case EXT_IPV6_128_UCASTm: 1186 mem_data = EXT_L3_UCAST_DATA_IPV6_128m; 1187 break; 1188 case EXT_IPV6_128_UCAST_WIDEm: 1189 mem_data = EXT_L3_UCAST_DATA_WIDE_IPV6_128m; 1190 break; 1191 default: 1192 mem_data = INVALIDm; 1193 break; 1194 } 1195 BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem_data, MEM_BLOCK_ANY, 1196 (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl)-1), 1197 buf_entry)); 1198 soc_mem_field32_set(unit, mem_data, buf_entry, CLASS_IDf, 1199 _TR3_ESM_HOST_ENTRY_INVALID_MARKER); 1200 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem_data, MEM_BLOCK_ALL, 1201 (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) - 1), 1202 buf_entry)); 1203 1204 /* Update free entry pointer */ 1205 _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) -= 1; 1206 } 1207 1208 /* Write status check. */ 1209 if (BCM_SUCCESS(rv)) { 1210 (ipv6) ? BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--; 1211 } 1212 1213 return rv; 1214 } 1215 1216 STATIC INLINE int 1217 _bcm_tr3_ip_key_to_l3cfg(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg) 1218 { 1219 int ipv6; /* IPV6 key. */ 1220 1221 /* Input parameters check */ 1222 if ((NULL == ipkey) || (NULL == l3cfg)) { 1223 return (BCM_E_PARAM); 1224 } 1225 1226 /* Reset destination buffer first. */ 1227 sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1228 1229 ipv6 = (ipkey->l3k_flags & BCM_L3_IP6); 1230 1231 /* Set vrf id. */ 1232 l3cfg->l3c_vrf = ipkey->l3k_vrf; 1233 l3cfg->l3c_vid = ipkey->l3k_vid; 1234 1235 if (ipv6) { 1236 if (BCM_IP6_MULTICAST(ipkey->l3k_ip6_addr)) { 1237 /* Copy ipv6 group, source & vid. */ 1238 sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t)); 1239 sal_memcpy(l3cfg->l3c_sip6, ipkey->l3k_sip6_addr, 1240 sizeof(bcm_ip6_t)); 1241 l3cfg->l3c_vid = ipkey->l3k_vid; 1242 l3cfg->l3c_flags = (BCM_L3_IP6 | BCM_L3_IPMC); 1243 } else { 1244 /* Copy ipv6 address. */ 1245 sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t)); 1246 l3cfg->l3c_flags = BCM_L3_IP6; 1247 } 1248 } else { 1249 if (BCM_IP4_MULTICAST(ipkey->l3k_ip_addr)) { 1250 /* Copy ipv4 mcast group, source & vid. */ 1251 l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr; 1252 l3cfg->l3c_src_ip_addr = ipkey->l3k_sip_addr; 1253 l3cfg->l3c_vid = ipkey->l3k_vid; 1254 l3cfg->l3c_flags = BCM_L3_IPMC; 1255 } else { 1256 /* Copy ipv4 address . */ 1257 l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr; 1258 } 1259 } 1260 return (BCM_E_NONE); 1261 } 1262 1263 STATIC INLINE int 1264 _bcm_tr3_l3cfg_to_ipkey(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg) 1265 { 1266 /* Input parameters check */ 1267 if ((NULL == ipkey) || (NULL == l3cfg)) { 1268 return (BCM_E_PARAM); 1269 } 1270 1271 /* Reset destination buffer first. */ 1272 sal_memset(ipkey, 0, sizeof(bcm_l3_key_t)); 1273 1274 ipkey->l3k_vrf = l3cfg->l3c_vrf; 1275 ipkey->l3k_vid = l3cfg->l3c_vid; 1276 1277 if (l3cfg->l3c_flags & BCM_L3_IP6) { 1278 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 1279 /* Copy ipv6 group, source & vid. */ 1280 sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 1281 sal_memcpy(ipkey->l3k_sip6_addr, l3cfg->l3c_sip6, 1282 sizeof(bcm_ip6_t)); 1283 ipkey->l3k_vid = l3cfg->l3c_vid; 1284 } else { 1285 /* Copy ipv6 address. */ 1286 sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t)); 1287 } 1288 } else { 1289 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 1290 /* Copy ipv4 mcast group, source & vid. */ 1291 ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr; 1292 ipkey->l3k_sip_addr = l3cfg->l3c_src_ip_addr; 1293 ipkey->l3k_vid = l3cfg->l3c_vid; 1294 } else { 1295 /* Copy ipv4 address . */ 1296 ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr; 1297 } 1298 } 1299 /* Store entry flags. */ 1300 ipkey->l3k_flags = l3cfg->l3c_flags; 1301 return (BCM_E_NONE); 1302 } 1303 1304 int 1305 bcm_tr3_l3_conflict_get(int unit, bcm_l3_key_t *ipkey, bcm_l3_key_t *cf_array, 1306 int cf_max, int *cf_count) 1307 { 1308 _bcm_l3_cfg_t l3cfg; 1309 uint32 *bufk, *bufp; 1310 soc_mem_t mem; 1311 int nh_idx, index, rv = BCM_E_NONE; 1312 _bcm_l3_fields_t *fld; 1313 l3_entry_1_entry_t l3v4_key, l3v4_entry; 1314 l3_entry_2_entry_t l3v4v6_key, l3v4v6_entry; 1315 l3_entry_4_entry_t l3v6_ext_key, l3v6_ext_entry; 1316 _soc_ism_mem_banks_t mem_banks; 1317 uint8 i, bidx, num_ent; 1318 uint32 result, bucket_index, *keyt; 1319 uint32 l3_entry[SOC_MAX_MEM_WORDS]; 1320 int ipmc, ipv6, embedded_nh; 1321 uint32 key_type_1[] = {SOC_MEM_KEY_L3_ENTRY_1_IPV4UC_IPV4_UNICAST, -1, -1}; 1322 uint32 key_type_2[] = {SOC_MEM_KEY_L3_ENTRY_2_IPV4UC_IPV4_UNICAST, 1323 SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST, 1324 SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST}; 1325 uint32 key_type_4[] = {SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST, 1326 SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST, -1}; 1327 1328 /* Make sure module was initialized. */ 1329 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 1330 return (BCM_E_INIT); 1331 } 1332 1333 /* Input parameters check. */ 1334 if ((NULL == ipkey) || (NULL == cf_count) || 1335 (NULL == cf_array) || (cf_max <= 0)) { 1336 return (BCM_E_PARAM); 1337 } 1338 1339 /* The wider entry may be specified or not */ 1340 embedded_nh = ipkey->l3k_flags & BCM_L3_DEREFERENCED_NEXTHOP; 1341 nh_idx = (embedded_nh) ? BCM_XGS3_L3_INVALID_INDEX : 0; 1342 1343 /* Translate lookup key to l3cfg format. */ 1344 BCM_IF_ERROR_RETURN(_bcm_tr3_ip_key_to_l3cfg(unit, ipkey, &l3cfg)); 1345 1346 /* Get entry type. */ 1347 ipv6 = (l3cfg.l3c_flags & BCM_L3_IP6); 1348 ipmc = (l3cfg.l3c_flags & BCM_L3_IPMC); 1349 1350 /* Get table memory. */ 1351 BCM_TR3_ISM_L3_HOST_TABLE_MEM(unit, l3cfg.l3c_intf, ipv6, mem, nh_idx); 1352 1353 if (!embedded_nh) { 1354 /* Look for the entry in wider tables */ 1355 if (ipv6) { 1356 mem = BCM_XGS3_L3_MEM(unit, v6_4); 1357 } else { 1358 mem = BCM_XGS3_L3_MEM(unit, v4_2); 1359 } 1360 /* Assign entry-key buf based on table being used */ 1361 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufk, l3v4_key, 1362 l3v4v6_key, l3v6_ext_key); 1363 1364 /* Assign entry buf based on table being used */ 1365 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry, 1366 l3v4v6_entry, l3v6_ext_entry); 1367 /* Prepare lookup key. */ 1368 if (ipmc) { 1369 _bcm_tr3_l3_ipmc_ent_init(unit, bufk, &l3cfg); 1370 } else { 1371 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, &l3cfg, bufk)); 1372 } 1373 1374 /* Perform lookup */ 1375 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 1376 _BCM_TR3_L3_MEM_BANKS_ALL, 1377 bufk, bufp, &l3cfg.l3c_hw_index); 1378 if (BCM_SUCCESS(rv)) { 1379 embedded_nh = BCM_L3_DEREFERENCED_NEXTHOP; 1380 } 1381 } 1382 1383 /* Bump up the size conditionally */ 1384 mem = (embedded_nh || ipmc) ? (ipv6 ? L3_ENTRY_4m : L3_ENTRY_2m) : 1385 (ipv6 ? L3_ENTRY_2m : L3_ENTRY_1m); 1386 1387 /* Set the key type field array */ 1388 keyt = (embedded_nh || ipmc) ? (ipv6 ? key_type_4 : key_type_2) : 1389 (ipv6 ? key_type_2 : key_type_1); 1390 1391 /* Set table fields */ 1392 BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1393 1394 /* Assign entry buf based on table being used */ 1395 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry, 1396 l3v4v6_entry, l3v6_ext_entry); 1397 1398 /* Prepare ISM host entry */ 1399 if (ipmc) { 1400 _bcm_tr3_l3_ipmc_ent_init(unit, bufp, &l3cfg); 1401 } else { 1402 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, &l3cfg, bufp)); 1403 } 1404 1405 *cf_count = 0; 1406 1407 rv = soc_ism_get_banks_for_mem(unit, mem, mem_banks.banks, 1408 mem_banks.bank_size, &mem_banks.count); 1409 if (SOC_FAILURE(rv)) { 1410 return BCM_E_INTERNAL; 1411 } 1412 if (mem_banks.count == 0) { 1413 return BCM_E_NOT_FOUND; 1414 } 1415 for (bidx = 0; bidx < mem_banks.count; bidx++) { 1416 rv = soc_generic_hash(unit, mem, bufp, (uint32)1 << mem_banks.banks[bidx], 1417 0, &index, &result, &bucket_index, &num_ent); 1418 if (SOC_FAILURE(rv)) { 1419 return BCM_E_INTERNAL; 1420 } 1421 for (i = 0; (i < num_ent) && (*cf_count < cf_max); i++) { 1422 rv = soc_mem_read(unit, mem, COPYNO_ALL, index + i, l3_entry); 1423 if (SOC_FAILURE(rv)) { 1424 return BCM_E_MEMORY; 1425 } 1426 if (soc_mem_field32_get(unit, mem, &l3_entry, fld->valid) && 1427 ((soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type) == keyt[0]) || 1428 (soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type) == keyt[1]) || 1429 (soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type) == keyt[2]))) { 1430 switch(soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type)) { 1431 case SOC_MEM_KEY_L3_ENTRY_1_IPV4UC_IPV4_UNICAST: 1432 l3cfg.l3c_flags = 0; 1433 break; 1434 case SOC_MEM_KEY_L3_ENTRY_2_IPV4UC_IPV4_UNICAST: 1435 l3cfg.l3c_flags = BCM_L3_DEREFERENCED_NEXTHOP; 1436 break; 1437 case SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST: 1438 l3cfg.l3c_flags = BCM_L3_IPMC; 1439 break; 1440 case SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST: 1441 l3cfg.l3c_flags = BCM_L3_IP6; 1442 break; 1443 case SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST: 1444 l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_DEREFERENCED_NEXTHOP; 1445 break; 1446 case SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST: 1447 l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 1448 break; 1449 default: 1450 break; 1451 } 1452 1453 rv = _bcm_tr3_l3_get_by_idx(unit, NULL, index + i, 1454 &l3cfg, &nh_idx); 1455 if (BCM_FAILURE(rv)) { 1456 continue; 1457 } 1458 1459 BCM_IF_ERROR_RETURN 1460 (_bcm_tr3_l3cfg_to_ipkey(unit, cf_array + (*cf_count), &l3cfg)); 1461 if ((++(*cf_count)) >= cf_max) { 1462 break; 1463 } 1464 } 1465 } 1466 } 1467 return BCM_E_NONE; 1468 } 1469 1470 /* 1471 * Function: 1472 * _bcm_tr3_l3_get_host_ent_by_idx 1473 * Purpose: 1474 * Parameters: 1475 * unit - (IN)SOC unit number. 1476 * dma_ptr - (IN)Table pointer in dma. 1477 * soc_mem_ - (IN)Table memory. 1478 * idx - (IN)Index to read. 1479 * l3cfg - (OUT)l3 entry search result. 1480 * nh_index - (OUT)Next hop index. 1481 * Returns: 1482 * BCM_E_XXX 1483 */ 1484 STATIC int 1485 _bcm_tr3_l3_get_host_ent_by_idx(int unit, void *dma_ptr, soc_mem_t mem, 1486 int idx, _bcm_l3_cfg_t *l3cfg, int *nh_idx) 1487 { 1488 uint32 ipv6; /* IPv6 entry indicator. */ 1489 int key_type; 1490 int clear_hit; /* Clear hit bit flag. */ 1491 int esm = TRUE; 1492 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 1493 uint32 *buf_entry; /* Key and entry buffer ptrs*/ 1494 l3_entry_1_entry_t l3v4_entry; /* Lookup entry */ 1495 l3_entry_2_entry_t l3v4v6_entry; /* Lookup entry*/ 1496 l3_entry_4_entry_t l3v6_ext_entry; /* Lookup entry*/ 1497 ext_ipv4_ucast_entry_t l3v4esm_entry; 1498 ext_ipv4_ucast_wide_entry_t l3v4wide_entry; 1499 ext_ipv6_128_ucast_entry_t l3v6_entry; 1500 ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry; 1501 1502 /* Get entry type. */ 1503 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1504 /* Get clear hit flag. */ 1505 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 1506 1507 if ((BCM_XGS3_L3_MEM(unit, v4) == mem) || 1508 (BCM_XGS3_L3_MEM(unit, v4_2) == mem) || 1509 (BCM_XGS3_L3_MEM(unit, v6_4) == mem)) { 1510 esm = FALSE; 1511 BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1512 BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1513 l3v4_entry, 1514 l3v4v6_entry, 1515 l3v6_ext_entry); 1516 } else { 1517 esm = TRUE; 1518 BCM_TR3_ESM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 1519 BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 1520 l3v4esm_entry, 1521 l3v4wide_entry, 1522 l3v6_entry, 1523 l3v6wide_entry); 1524 } 1525 1526 if (NULL == dma_ptr) { /* Read from hardware. */ 1527 /* Zero buffers. */ 1528 sal_memset(buf_entry, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 1529 1530 /* Read entry from hw. */ 1531 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_entry)); 1532 } else { /* Read from dma. */ 1533 buf_entry = soc_mem_table_idx_to_pointer(unit, mem, 1534 uint32 *, dma_ptr, idx); 1535 } 1536 1537 if (esm) { 1538 if (((BCM_XGS3_L3_MEM(unit, v6_esm)) == mem) || 1539 ((BCM_XGS3_L3_MEM(unit, v6_esm_wide)) == mem)) { 1540 l3cfg->l3c_flags = BCM_L3_IP6; 1541 ipv6 = TRUE; 1542 } 1543 1544 if (ipv6) { 1545 soc_mem_ip6_addr_get(unit, mem, buf_entry, 1546 IP_ADDRf, l3cfg->l3c_ip6, 0); 1547 } 1548 1549 } else { 1550 if(!soc_mem_field32_get(unit, mem, buf_entry, fld->valid)) { 1551 return (BCM_E_NOT_FOUND); 1552 } 1553 1554 key_type = soc_mem_field32_get(unit, mem, buf_entry, fld->key_type); 1555 1556 if (BCM_XGS3_L3_MEM(unit, v4) == mem) { 1557 if (key_type != SOC_MEM_KEY_L3_ENTRY_1_IPV4UC_IPV4_UNICAST) { 1558 return (BCM_E_NOT_FOUND); 1559 } 1560 l3cfg->l3c_flags = 0; 1561 } else if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) { 1562 if (key_type == SOC_MEM_KEY_L3_ENTRY_2_IPV4UC_IPV4_UNICAST) { 1563 l3cfg->l3c_flags = 0; 1564 } else if (key_type == 1565 SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST) { 1566 l3cfg->l3c_flags = BCM_L3_IPMC; 1567 } else if (key_type == 1568 SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST) { 1569 l3cfg->l3c_flags = BCM_L3_IP6; 1570 } else { 1571 return (BCM_E_NOT_FOUND); 1572 } 1573 } else if (BCM_XGS3_L3_MEM(unit, v6_4) == mem) { 1574 if (key_type == SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST) { 1575 l3cfg->l3c_flags = BCM_L3_IP6; 1576 } else if (key_type == 1577 SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST) { 1578 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 1579 } else { 1580 return (BCM_E_NOT_FOUND); 1581 } 1582 } 1583 1584 /* Ignore protocol mismatch & multicast entries. */ 1585 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 1586 (l3cfg->l3c_flags & BCM_L3_IPMC)) { 1587 return (BCM_E_NONE); 1588 } 1589 1590 if (ipv6) { 1591 /* Extract host info from the entry. */ 1592 soc_mem_ip6_addr_get(unit, mem, buf_entry, 1593 IPV6UC__IP_ADDR_LWR_64f, l3cfg->l3c_ip6, 1594 SOC_MEM_IP6_LOWER_ONLY); 1595 1596 soc_mem_ip6_addr_get(unit, mem, buf_entry, 1597 IPV6UC__IP_ADDR_UPR_64f, l3cfg->l3c_ip6, 1598 SOC_MEM_IP6_UPPER_ONLY); 1599 } 1600 } 1601 1602 /* Set index to l3cfg. */ 1603 l3cfg->l3c_hw_index = idx; 1604 1605 if (!ipv6) { 1606 l3cfg->l3c_ip_addr = 1607 soc_mem_field32_get(unit, mem, buf_entry, fld->ip4); 1608 } 1609 1610 /* Parse entry data. */ 1611 BCM_IF_ERROR_RETURN( 1612 _bcm_tr3_l3_ent_parse(unit, mem, l3cfg, nh_idx, buf_entry)); 1613 1614 /* Clear the HIT bit */ 1615 if (clear_hit) { 1616 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, l3cfg, 1617 (void *)buf_entry, idx)); 1618 } 1619 1620 return (BCM_E_NONE); 1621 } 1622 1623 /* 1624 * Function: 1625 * _bcm_tr3_l3_get_tbl_info 1626 * Purpose: 1627 * Get an entry from Tr3 ISM/ESM L3 host table 1628 * and also the info where it was found. 1629 * Parameters: 1630 * unit - (IN) SOC unit number. 1631 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 1632 * nh_index - (IN/OUT) Next hop index. 1633 * esm - (OUT) If TRUE, entry found in ESM. 1634 * embd - (OUT) If TRUE, entry is embedded NH entry. 1635 * Returns: 1636 * BCM_E_XXX 1637 */ 1638 STATIC int 1639 _bcm_tr3_l3_get_tbl_info(int unit, _bcm_l3_cfg_t *l3cfg, 1640 int *nh_idx, int *esm, int *embd) 1641 { 1642 int rv; 1643 *esm = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 1644 *embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 1645 1646 /* Search ISM tables first */ 1647 rv = _bcm_tr3_l3_ism_get(unit, l3cfg, nh_idx, embd); 1648 if (BCM_E_NOT_FOUND == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 1649 /* Not found in ISM, search ESM */ 1650 rv = _bcm_tr3_l3_esm_get(unit, l3cfg, nh_idx, embd); 1651 if (BCM_SUCCESS(rv)) { 1652 *esm = TRUE; 1653 } 1654 return rv; 1655 } else if (BCM_FAILURE(rv)) { 1656 /* ISM search failed */ 1657 return rv; 1658 } else { 1659 /* Found match in ISM */ 1660 *esm = FALSE; 1661 return BCM_E_NONE; 1662 } 1663 } 1664 1665 /* 1666 * Function: 1667 * _bcm_tr3_l3_ipmc_ent_parse 1668 * Purpose: 1669 * Service routine used to parse hw l3 ipmc entry to api format. 1670 * Parameters: 1671 * unit - (IN)SOC unit number. 1672 * l3cfg - (IN/OUT)l3 entry parsing destination buf. 1673 * l3x_entry - (IN/OUT)hw buffer. 1674 * Returns: 1675 * void 1676 */ 1677 STATIC void 1678 _bcm_tr3_l3_ipmc_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg, 1679 l3_entry_4_entry_t *l3x_entry) 1680 { 1681 soc_mem_t mem; /* IPMC table memory. */ 1682 uint32 *buf_p; /* HW buffer address. */ 1683 int ipv6; /* IPv6 entry indicator. */ 1684 int idx; /* Iteration index. */ 1685 soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f}; 1686 soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, class_id, pri; 1687 1688 buf_p = (uint32 *)l3x_entry; 1689 1690 /* Get entry type. */ 1691 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 1692 1693 /* Get table memory and table fields */ 1694 if (ipv6) { 1695 mem = L3_ENTRY_4m; 1696 pri = IPV6MC__PRIf; 1697 rpe = IPV6MC__RPEf; 1698 vrf_id = IPV6MC__VRF_IDf; 1699 l3mc_idx = IPV6MC__L3MC_INDEXf; 1700 class_id = IPV6MC__CLASS_IDf; 1701 dst_discard = IPV6MC__DST_DISCARDf; 1702 } else { 1703 mem = L3_ENTRY_2m; 1704 pri = IPV4MC__PRIf; 1705 rpe = IPV4MC__RPEf; 1706 vrf_id = IPV4MC__VRF_IDf; 1707 l3mc_idx = IPV4MC__L3MC_INDEXf; 1708 class_id = IPV4MC__CLASS_IDf; 1709 dst_discard = IPV4MC__DST_DISCARDf; 1710 } 1711 1712 /* Mark entry as multicast & clear rest of the flags. */ 1713 l3cfg->l3c_flags = BCM_L3_IPMC; 1714 if (ipv6) { 1715 l3cfg->l3c_flags |= BCM_L3_IP6; 1716 } 1717 1718 /* Read hit value. */ 1719 if(soc_mem_field32_get(unit, mem, buf_p, HIT_0f)) { 1720 l3cfg->l3c_flags |= BCM_L3_HIT; 1721 } else if (ipv6) { 1722 /* Get hit bit. */ 1723 for (idx = 0; idx < 3; idx++) { 1724 if(soc_mem_field32_get(unit, mem, buf_p, hitf[idx])) { 1725 l3cfg->l3c_flags |= BCM_L3_HIT; 1726 break; 1727 } 1728 } 1729 } 1730 1731 /* Set ipv6 group address to multicast. */ 1732 if (ipv6) { 1733 l3cfg->l3c_ip6[0] = 0xff; /* Set entry ip to mcast address. */ 1734 } 1735 1736 /* Read priority override */ 1737 if(soc_mem_field32_get(unit, mem, buf_p, rpe)) { 1738 l3cfg->l3c_flags |= BCM_L3_RPE; 1739 } 1740 1741 /* Read destination discard bit. */ 1742 if(soc_mem_field32_get(unit, mem, buf_p, dst_discard)) { 1743 l3cfg->l3c_flags |= BCM_L3_DST_DISCARD; 1744 } 1745 1746 /* Read Virtual Router Id. */ 1747 l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, vrf_id); 1748 1749 /* Pointer to ipmc replication table. */ 1750 l3cfg->l3c_ipmc_ptr = soc_mem_field32_get(unit, mem, buf_p, l3mc_idx); 1751 1752 /* Classification lookup class id. */ 1753 l3cfg->l3c_lookup_class = soc_mem_field32_get(unit, mem, buf_p, class_id); 1754 1755 /* Read priority value. */ 1756 l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, pri); 1757 return; 1758 } 1759 1760 /* 1761 * Function: 1762 * _bcm_tr3_l3_defip_mem_get 1763 * Purpose: 1764 * Resolve route table memory for a given route entry. 1765 * Parameters: 1766 * unit - (IN)SOC unit number. 1767 * flags - (IN)IPv6/IPv4 route. 1768 * plen - (IN)Prefix length. 1769 * mem - (OUT)Route table memory. 1770 * Returns: 1771 * BCM_E_XXX 1772 */ 1773 STATIC int 1774 _bcm_tr3_l3_defip_mem_get(int unit, uint32 flags, int plen, soc_mem_t *mem) 1775 { 1776 /* default value */ 1777 *mem = L3_DEFIPm; 1778 1779 if (flags & BCM_L3_IP6) { 1780 if (plen > 64) { 1781 *mem = (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) ?\ 1782 EXT_IPV6_128_DEFIPm : L3_DEFIP_PAIR_128m; 1783 } else { 1784 *mem = (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_64_DEFIPm)) ?\ 1785 EXT_IPV6_64_DEFIPm : 1786 ((BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) ?\ 1787 EXT_IPV6_128_DEFIPm : L3_DEFIPm); 1788 } 1789 } else { 1790 *mem = (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) ?\ 1791 EXT_IPV4_DEFIPm : L3_DEFIPm ; 1792 } 1793 1794 return BCM_E_NONE; 1795 } 1796 1797 /* 1798 * Function: 1799 * _bcm_tr3_defip_pair128_init 1800 * Purpose: 1801 * Initialize sw image for L3_DEFIP_PAIR_128 internal tcam. 1802 * Parameters: 1803 * unit - (IN)SOC unit number. 1804 * Returns: 1805 * BCM_E_XXX 1806 */ 1807 STATIC int 1808 _bcm_tr3_defip_pair128_init(int unit) 1809 { 1810 int rv; 1811 int mem_sz; 1812 int defip_config; 1813 int ipv6_128_depth; 1814 int ranger_device; /* Ranger specific config */ 1815 1816 /* De-allocate any existing structures. */ 1817 if (BCM_DEFIP_PAIR128(unit) != NULL) { 1818 rv = _bcm_defip_pair128_deinit(unit); 1819 BCM_IF_ERROR_RETURN(rv); 1820 } 1821 1822 /* Allocate cam control structure. */ 1823 mem_sz = sizeof(_bcm_defip_pair128_table_t); 1824 BCM_DEFIP_PAIR128(unit) = sal_alloc(mem_sz, "tr3_l3_defip_pair128"); 1825 if (BCM_DEFIP_PAIR128(unit) == NULL) { 1826 return (BCM_E_MEMORY); 1827 } 1828 1829 /* Reset cam control structure. */ 1830 sal_memset(BCM_DEFIP_PAIR128(unit), 0, mem_sz); 1831 1832 ranger_device = FALSE; 1833 if (soc_feature(unit, soc_feature_l3_256_defip_table)) { 1834 ranger_device = TRUE; 1835 } 1836 1837 defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1838 ((ranger_device) ? 0 : 1)); 1839 ipv6_128_depth = SOC_L3_DEFIP_MAX_128B_ENTRIES(unit); 1840 1841 if (ranger_device ) { 1842 if (defip_config) { 1843 ipv6_128_depth = _BCM_HX4_RANGER_DEFIP_TCAM_DEPTH; 1844 } else { /* tcams are not paired - no ipv6/65-ipv6/128 routes */ 1845 ipv6_128_depth = 0; 1846 } 1847 } 1848 1849 BCM_DEFIP_PAIR128_TOTAL(unit) = ipv6_128_depth; 1850 BCM_DEFIP_PAIR128_URPF_OFFSET(unit) = 0; 1851 BCM_DEFIP_PAIR128_IDX_MAX(unit) = ipv6_128_depth - 1; 1852 BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit) = ipv6_128_depth; 1853 if (ipv6_128_depth) { 1854 mem_sz = ipv6_128_depth * sizeof(_bcm_defip_pair128_entry_t); 1855 BCM_DEFIP_PAIR128_ARR(unit) = 1856 sal_alloc(mem_sz, "tr3_l3_defip_pair128_entry_array"); 1857 if (BCM_DEFIP_PAIR128_ARR(unit) == NULL) { 1858 BCM_IF_ERROR_RETURN(_bcm_defip_pair128_deinit(unit)); 1859 return (BCM_E_MEMORY); 1860 } 1861 sal_memset(BCM_DEFIP_PAIR128_ARR(unit), 0, mem_sz); 1862 } 1863 1864 rv = _bcm_defip_pair128_field_cache_init(unit); 1865 if (BCM_FAILURE(rv)) { 1866 BCM_IF_ERROR_RETURN(_bcm_defip_pair128_deinit(unit)); 1867 return rv; 1868 } 1869 1870 return (BCM_E_NONE); 1871 } 1872 1873 /* 1874 * Function: 1875 * _bcm_tr3_l3_host_stat_get_table_info 1876 * Description: 1877 * Provides relevant flex table information(table-name,index with 1878 * direction) for given L3 Host entry 1879 * 1880 * Parameters: 1881 * unit - (IN) unit number 1882 * port - (IN) GPORT ID 1883 * num_of_tables - (OUT) Number of flex counter tables 1884 * table_info - (OUT) Flex counter tables information 1885 * 1886 * Return Value: 1887 * BCM_E_XXX 1888 * Notes: 1889 */ 1890 STATIC bcm_error_t 1891 _bcm_tr3_l3_host_stat_get_table_info( 1892 int unit, 1893 bcm_l3_host_t *info, 1894 uint32 *num_of_tables, 1895 bcm_stat_flex_table_info_t *table_info) 1896 { 1897 int rv, embd; 1898 soc_mem_t mem; 1899 _bcm_l3_cfg_t l3cfg; 1900 1901 if (NULL == info) { 1902 return (BCM_E_PARAM); 1903 } 1904 1905 if (!(soc_feature(unit, soc_feature_l3_extended_host_entry))) { 1906 return BCM_E_UNAVAIL; 1907 } 1908 1909 mem = INVALIDm; 1910 /* Vrf is in device supported range check. */ 1911 if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 1912 (info->l3a_vrf < BCM_L3_VRF_DEFAULT)) { 1913 return (BCM_E_PARAM); 1914 } 1915 1916 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 1917 l3cfg.l3c_flags = info->l3a_flags; 1918 l3cfg.l3c_vrf = info->l3a_vrf; 1919 1920 if (info->l3a_flags & BCM_L3_IP6) { 1921 sal_memcpy(l3cfg.l3c_ip6, info->l3a_ip6_addr, BCM_IP6_ADDRLEN); 1922 } else { 1923 l3cfg.l3c_ip_addr = info->l3a_ip_addr; 1924 } 1925 1926 rv = _bcm_tr3_l3_ism_get(unit, &l3cfg, NULL, &embd); 1927 if (BCM_SUCCESS(rv)) { /* Entry found in ISM */ 1928 mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_4m : 1929 L3_ENTRY_2m; 1930 } 1931 1932 if (BCM_E_NOT_FOUND == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 1933 /* Not found in ISM, search ESM */ 1934 rv = _bcm_tr3_l3_esm_get(unit, &l3cfg, NULL, &embd); 1935 if (BCM_SUCCESS(rv)) { /* Entry found in ESM */ 1936 mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? 1937 EXT_IPV6_128_UCAST_WIDEm : 1938 EXT_IPV4_UCAST_WIDEm; 1939 } 1940 } 1941 1942 if (BCM_SUCCESS(rv)) { 1943 table_info[*num_of_tables].table = mem; 1944 table_info[*num_of_tables].index = l3cfg.l3c_hw_index; 1945 table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress; 1946 (*num_of_tables)++; 1947 } 1948 1949 return rv; 1950 } 1951 1952 /*----- END STATIC FUNCS ----- */ 1953 1954 /* 1955 * Function: 1956 * _bcm_tr3_l3_add 1957 * Purpose: 1958 * Add and entry to Tr3 ISM/ESM L3 host table. 1959 * The decision to add to ISM/ESM is based on 1960 * switch control(s) and ESM/ISM table full conditions. 1961 * conditions. 1962 * Parameters: 1963 * unit - (IN) SOC unit number. 1964 * l3cfg - (IN) L3 entry info. 1965 * nh_idx - (IN) Next hop index. 1966 * Returns: 1967 * BCM_E_XXX 1968 */ 1969 int 1970 _bcm_tr3_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx) 1971 { 1972 int rv; 1973 1974 /* Access ISM before ESM */ 1975 rv = _bcm_tr3_l3_ism_add(unit, l3cfg, nh_idx); 1976 if (BCM_E_FULL == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 1977 if (BCM_L3_RPE_SET(l3cfg->l3c_flags)) { 1978 if (l3cfg->l3c_lookup_class > SOC_ADDR_CLASS_MAX(unit)) { 1979 return (BCM_E_PARAM); 1980 } 1981 } else { 1982 l3cfg->l3c_prio = (l3cfg->l3c_lookup_class & 0x3C0) >> 6; 1983 l3cfg->l3c_lookup_class = l3cfg->l3c_lookup_class & 0x3F; 1984 } 1985 1986 /* ISM host table full, try to add to ESM */ 1987 return (_bcm_tr3_l3_esm_add(unit, l3cfg, nh_idx)); 1988 } else if (BCM_FAILURE(rv)) { 1989 /* ISM host add failed */ 1990 return rv; 1991 } else { 1992 /* ISM host add successful */ 1993 return BCM_E_NONE; 1994 } 1995 } 1996 1997 /* 1998 * Function: 1999 * _bcm_tr3_l3_get 2000 * Purpose: 2001 * Get an entry from Tr3 ISM/ESM L3 host table. 2002 * Parameters: 2003 * unit - (IN) SOC unit number. 2004 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 2005 * nh_index - (IN/OUT) Next hop index. 2006 * Returns: 2007 * BCM_E_XXX 2008 */ 2009 int 2010 _bcm_tr3_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx) 2011 { 2012 int rv; 2013 int embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 2014 2015 /* Search ISM tables first */ 2016 rv = _bcm_tr3_l3_ism_get(unit, l3cfg, nh_idx, &embd); 2017 if (BCM_E_NOT_FOUND == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 2018 /* Not found in ISM, search ESM */ 2019 BCM_IF_ERROR_RETURN((_bcm_tr3_l3_esm_get(unit, l3cfg, nh_idx, &embd))); 2020 if (!BCM_L3_RPE_SET(l3cfg->l3c_flags)) { 2021 l3cfg->l3c_lookup_class = (((l3cfg->l3c_prio & 0xF) << 6) | 2022 (l3cfg->l3c_lookup_class & 0x3F)); 2023 } 2024 2025 return BCM_E_NONE; 2026 } else if (BCM_FAILURE(rv)) { 2027 /* ISM search failed */ 2028 return rv; 2029 } else { 2030 /* Found match in ISM */ 2031 return BCM_E_NONE; 2032 } 2033 } 2034 2035 /* 2036 * Function: 2037 * _bcm_tr3_l3_del 2038 * Purpose: 2039 * Del an entry from Tr3 ISM/ESM L3 host table. 2040 * Parameters: 2041 * unit - (IN) SOC unit number. 2042 * l3cfg - (IN/OUT) L3 entry lookup key & search result. 2043 * nh_index - (IN/OUT) Next hop index. 2044 * Returns: 2045 * BCM_E_XXX 2046 */ 2047 int 2048 _bcm_tr3_l3_del(int unit, _bcm_l3_cfg_t *l3cfg) 2049 { 2050 int rv; 2051 2052 /* Attempt to delete entry from ISM tables first */ 2053 rv = _bcm_tr3_l3_ism_del(unit, l3cfg); 2054 if ((BCM_E_NOT_FOUND == rv) && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 2055 rv = _bcm_tr3_l3_esm_del(unit, l3cfg); 2056 if (BCM_E_NOT_FOUND == rv) { 2057 rv = BCM_E_NONE; /* Ignore if entry to del is not found */ 2058 } 2059 } 2060 2061 return rv; 2062 } 2063 2064 /* 2065 * Function: 2066 * _bcm_tr3_l3_traverse 2067 * Purpose: 2068 * Walk over range of entries in l3 host table. 2069 * Parameters: 2070 * unit - SOC unit number. 2071 * flags - L3 entry flags to match during traverse. 2072 * start - First index to read. 2073 * end - Last index to read. 2074 * cb - Caller notification callback. 2075 * user_data - User cookie, which should be returned in cb. 2076 * Returns: 2077 * BCM_E_XXX 2078 */ 2079 int 2080 _bcm_tr3_l3_traverse(int unit, int flags, uint32 start, uint32 end, 2081 bcm_l3_host_traverse_cb cb, void *user_data) 2082 { 2083 int rv = BCM_E_NONE; 2084 int ipv6; /* Protocol IPv6/IPv4 */ 2085 int nh_idx; /* Next hop index. */ 2086 int total = 0; /* Total number of entries walked. */ 2087 int table_size; /* Number of entries in the table. */ 2088 int table_ent_size; /* Table entry size. */ 2089 bcm_l3_host_t info; /* Callback info buffer. */ 2090 _bcm_l3_cfg_t l3cfg; /* HW entry info. */ 2091 uint8 *l3_tbl_buf = NULL; /* Table dma pointer. */ 2092 int tbl, idx, idx_min, idx_max; /* Min and Max iteration index */ 2093 int chunk_size, num_chunks, chunk_index; 2094 int num_tables = _BCM_TR3_NUM_ESM_HOST_TABLES/2; 2095 soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES] = 2096 {INVALIDm, INVALIDm, INVALIDm, INVALIDm}; 2097 int host_table_entry = 0; 2098 2099 /* If no callback provided, we are done. */ 2100 if (NULL == cb) { 2101 return (BCM_E_NONE); 2102 } 2103 2104 ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE; 2105 /* If table is empty -> there is nothing to read. */ 2106 if (ipv6 && (!BCM_XGS3_L3_IP6_CNT(unit))) { 2107 return (BCM_E_NONE); 2108 } 2109 if (!ipv6 && (!BCM_XGS3_L3_IP4_CNT(unit))) { 2110 return (BCM_E_NONE); 2111 } 2112 2113 if (ipv6) { 2114 mem[0] = BCM_XGS3_L3_MEM(unit, v6); 2115 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2116 mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 2117 num_tables++; 2118 } 2119 } else { 2120 mem[0] = BCM_XGS3_L3_MEM(unit, v4); 2121 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2122 mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 2123 num_tables++; 2124 } 2125 } 2126 2127 for(tbl = 0; tbl < num_tables; tbl++) { 2128 2129 if (INVALIDm == mem[tbl]) { 2130 continue; 2131 } 2132 if (soc_mem_index_count(unit, mem[tbl]) == 0) { 2133 continue; 2134 } 2135 2136 chunk_size = 1024; 2137 table_size = soc_mem_index_count(unit, mem[tbl]); 2138 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]); 2139 num_chunks = soc_mem_index_count(unit, mem[tbl]) / chunk_size; 2140 if (soc_mem_index_count(unit, mem[tbl]) % chunk_size) { 2141 num_chunks++; 2142 } 2143 2144 l3_tbl_buf = soc_cm_salloc(unit, table_ent_size * chunk_size, 2145 "l3_tbl_chunk buffer"); 2146 if (NULL == l3_tbl_buf) { 2147 rv = BCM_E_MEMORY; 2148 goto cleanup; 2149 } 2150 2151 for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) { 2152 idx_min = chunk_index * chunk_size; 2153 idx_max = idx_min + chunk_size - 1; 2154 if (idx_max > soc_mem_index_max(unit, mem[tbl])) { 2155 idx_max = soc_mem_index_max(unit, mem[tbl]); 2156 } 2157 2158 /* Reset allocated buffer. */ 2159 sal_memset(l3_tbl_buf, 0, (table_ent_size * chunk_size)); 2160 2161 rv = soc_mem_read_range(unit, mem[tbl], MEM_BLOCK_ANY, 2162 idx_min, idx_max, l3_tbl_buf); 2163 if (SOC_FAILURE(rv)) { 2164 goto cleanup; 2165 } 2166 2167 /* Input index`s sanity. */ 2168 if (start > (uint32)table_size || start > end) { 2169 if(l3_tbl_buf) { 2170 soc_cm_sfree(unit, l3_tbl_buf); 2171 l3_tbl_buf = NULL; 2172 } 2173 return (BCM_E_NOT_FOUND); 2174 } 2175 2176 /* Iterate over all the entries - show matching ones. */ 2177 for (idx = idx_min; idx <= idx_max; idx++) { 2178 /* Reset buffer before read. */ 2179 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2180 l3cfg.l3c_flags = flags; 2181 2182 /* Get entry from hw. */ 2183 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, l3_tbl_buf, mem[tbl], 2184 (idx % chunk_size), &l3cfg, &nh_idx); 2185 2186 /* Check for read errors & invalid entries. */ 2187 if (rv < 0) { 2188 if (rv != BCM_E_NOT_FOUND) { 2189 break; 2190 } 2191 continue; 2192 } 2193 2194 /* Check read entry flags & update index accordingly. */ 2195 if (BCM_L3_CMP_EQUAL != 2196 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 2197 continue; 2198 } 2199 2200 /* Valid entry found -> increment total table_sizeer */ 2201 total++; 2202 if ((uint32)total < start) { 2203 continue; 2204 } 2205 2206 /* Don't read beyond last required index. */ 2207 if ((uint32)total > end) { 2208 break; 2209 } 2210 2211 /* Get next hop info. */ 2212 rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx); 2213 if (rv < 0) { 2214 continue; 2215 } 2216 2217 /* Fill host info. */ 2218 _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info); 2219 rv = (*cb) (unit, total, &info, user_data); 2220 #ifdef BCM_CB_ABORT_ON_ERR 2221 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2222 break; 2223 } 2224 #endif 2225 } 2226 } 2227 if(l3_tbl_buf) { 2228 soc_cm_sfree(unit, l3_tbl_buf); 2229 l3_tbl_buf = NULL; 2230 } 2231 } 2232 2233 if (BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 2234 idx = 0; 2235 num_tables = 1; 2236 2237 if (ipv6) { 2238 mem[0] = BCM_XGS3_L3_MEM(unit, v6_esm); 2239 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2240 mem[1] = BCM_XGS3_L3_MEM(unit, v6_esm_wide); 2241 num_tables++; 2242 } 2243 } else { 2244 mem[0] = BCM_XGS3_L3_MEM(unit, v4_esm); 2245 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2246 mem[1] = BCM_XGS3_L3_MEM(unit, v4_esm_wide); 2247 num_tables++; 2248 } 2249 } 2250 2251 for(tbl = 0; tbl < num_tables; tbl++) { 2252 2253 if (INVALIDm == mem[tbl]) { 2254 continue; 2255 } 2256 if (soc_mem_index_count(unit, mem[tbl]) == 0) { 2257 continue; 2258 } 2259 2260 table_size = soc_mem_index_count(unit, mem[tbl]); 2261 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]); 2262 chunk_size = 1024; 2263 num_chunks = soc_mem_index_count(unit, mem[tbl]) / chunk_size; 2264 if (soc_mem_index_count(unit, mem[tbl]) % chunk_size) { 2265 num_chunks++; 2266 } 2267 2268 l3_tbl_buf = soc_cm_salloc(unit, table_ent_size * chunk_size, 2269 "l3esm_tbl_chunk buffer"); 2270 if (NULL == l3_tbl_buf) { 2271 rv = BCM_E_MEMORY; 2272 goto cleanup; 2273 } 2274 host_table_entry = _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl+(2 * ipv6)); 2275 2276 for (chunk_index = num_chunks - 1; chunk_index >= 0; chunk_index--) { 2277 idx_min = chunk_index * chunk_size; 2278 idx_max = idx_min + chunk_size - 1; 2279 if (idx_max > soc_mem_index_max(unit, mem[tbl])) { 2280 idx_max = soc_mem_index_max(unit, mem[tbl]); 2281 } 2282 2283 if (idx_min > host_table_entry) { 2284 continue; 2285 } 2286 2287 /* Reset allocated buffer. */ 2288 sal_memset(l3_tbl_buf, 0, (table_ent_size * chunk_size)); 2289 2290 rv = soc_mem_read_range(unit, mem[tbl], MEM_BLOCK_ANY, 2291 idx_min, idx_max, l3_tbl_buf); 2292 if (SOC_FAILURE(rv)) { 2293 goto cleanup; 2294 } 2295 2296 /* Input index`s sanity. */ 2297 if (start > (uint32)table_size || start > end) { 2298 if(l3_tbl_buf) { 2299 soc_cm_sfree(unit, l3_tbl_buf); 2300 l3_tbl_buf = NULL; 2301 } 2302 return (BCM_E_NOT_FOUND); 2303 } 2304 2305 /* Iterate over all the entries - show matching ones. */ 2306 for (idx = idx_min; idx <= idx_max; idx++) { 2307 if (idx < host_table_entry) { 2308 /* Reset buffer before read. */ 2309 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 2310 l3cfg.l3c_flags = flags; 2311 2312 /* Get entry from hw. */ 2313 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, l3_tbl_buf, 2314 mem[tbl], (idx % chunk_size), &l3cfg, &nh_idx); 2315 2316 /* Check for read errors & invalid entries. */ 2317 if (rv < 0) { 2318 if (rv != BCM_E_NOT_FOUND) { 2319 break; 2320 } 2321 continue; 2322 } 2323 2324 /* Check read entry flags & update index accordingly. */ 2325 if (BCM_L3_CMP_EQUAL != 2326 _bcm_xgs3_trvrs_flags_cmp(unit, flags, 2327 l3cfg.l3c_flags, &idx)) { 2328 continue; 2329 } 2330 2331 /* Valid entry found -> increment total table_sizeer */ 2332 total++; 2333 if ((uint32)total < start) { 2334 continue; 2335 } 2336 2337 /* Don't read beyond last required index. */ 2338 if ((uint32)total > end) { 2339 break; 2340 } 2341 2342 /* Get next hop info. */ 2343 rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx); 2344 if (rv < 0) { 2345 break; 2346 } 2347 2348 /* Fill host info. */ 2349 _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info); 2350 rv = (*cb) (unit, total, &info, user_data); 2351 #ifdef BCM_CB_ABORT_ON_ERR 2352 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2353 break; 2354 } 2355 #endif 2356 } 2357 } 2358 } 2359 if(l3_tbl_buf) { 2360 soc_cm_sfree(unit, l3_tbl_buf); 2361 l3_tbl_buf = NULL; 2362 } 2363 } 2364 } 2365 2366 /* Reset last read status. */ 2367 if (BCM_E_NOT_FOUND == rv) { 2368 rv = BCM_E_NONE; 2369 } 2370 2371 cleanup: 2372 if (l3_tbl_buf) { 2373 soc_cm_sfree(unit, l3_tbl_buf); 2374 } 2375 2376 return (rv); 2377 2378 } 2379 2380 /* 2381 * Function: 2382 * bcm_tr3_l3_replace 2383 * Purpose: 2384 * Replace an entry in TR3 L3 host table. 2385 * Parameters: 2386 * unit - (IN)SOC unit number. 2387 * l3cfg - (IN)L3 entry information. 2388 * Returns: 2389 * BCM_E_XXX 2390 */ 2391 int 2392 bcm_tr3_l3_replace(int unit, _bcm_l3_cfg_t *l3cfg) 2393 { 2394 2395 _bcm_l3_cfg_t entry; /* Original l3 entry. */ 2396 int nh_idx_old; /* Original entry next hop index. */ 2397 int nh_idx_new; /* New allocated next hop index */ 2398 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 2399 int esm_old, embd_old, embd_new; 2400 2401 /* Make sure module was initialized. */ 2402 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 2403 return (BCM_E_INIT); 2404 } 2405 2406 /* Input parameters check. */ 2407 if (NULL == l3cfg) { 2408 return (BCM_E_PARAM); 2409 } 2410 2411 /* Set lookup key. */ 2412 entry = *l3cfg; 2413 2414 esm_old = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 2415 embd_old = _BCM_TR3_HOST_ENTRY_NOT_FOUND; 2416 2417 if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) { 2418 /* Check if identical entry exits. */ 2419 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) { 2420 BCM_XGS3_L3_MODULE_LOCK(unit); 2421 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, &entry); 2422 BCM_XGS3_L3_MODULE_UNLOCK(unit); 2423 } 2424 if (rv < 0) { 2425 return rv; 2426 } 2427 2428 /* Write mcast entry to hw. */ 2429 l3cfg->l3c_hw_index = entry.l3c_hw_index; /*Replacement index & flag. */ 2430 if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) { 2431 BCM_XGS3_L3_MODULE_LOCK(unit); 2432 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg); 2433 BCM_XGS3_L3_MODULE_UNLOCK(unit); 2434 } else { 2435 return (BCM_E_UNAVAIL); 2436 } 2437 } else { 2438 if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) { 2439 /* Trunk id validation. */ 2440 BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags, 2441 l3cfg->l3c_port_tgid); 2442 } 2443 2444 /* Check if identical entry exits. */ 2445 rv = _bcm_tr3_l3_get_tbl_info(unit, &entry, &nh_idx_old, &esm_old, &embd_old); 2446 2447 if ((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) { 2448 return bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv); 2449 } else if (BCM_FAILURE(rv)) { 2450 return rv; 2451 } 2452 2453 if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid)) { 2454 nh_idx_new = 0; 2455 } else { /* If new entry is in indexed NH table */ 2456 /* Get next hop index. */ 2457 BCM_IF_ERROR_RETURN 2458 (_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx_new)); 2459 } 2460 2461 embd_new = BCM_TR3_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx_new); 2462 if (embd_old != embd_new) { 2463 rv = bcm_xgs3_l3_del(unit, &entry); 2464 l3cfg->l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX; 2465 } else { 2466 /*Replacement index & flag. */ 2467 l3cfg->l3c_hw_index = entry.l3c_hw_index; 2468 } 2469 if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) { 2470 BCM_XGS3_L3_MODULE_LOCK(unit); 2471 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add)(unit, l3cfg, nh_idx_new); 2472 BCM_XGS3_L3_MODULE_UNLOCK(unit); 2473 } else { 2474 rv = BCM_E_UNAVAIL; 2475 } 2476 2477 /* Do best effort clean_up if needed. */ 2478 if (BCM_FAILURE(rv)) { 2479 bcm_xgs3_nh_del(unit, 0, nh_idx_new); 2480 } 2481 2482 /* Free original next hop index. */ 2483 if (embd_old == embd_new) { 2484 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx_old)); 2485 } 2486 } 2487 return rv; 2488 } 2489 2490 /* 2491 * Function: 2492 * bcm_tr3_l3_del_intf 2493 * Purpose: 2494 * Delete all the entries in Tr3 L3 host table with 2495 * NH matching a certain interface. 2496 * Parameters: 2497 * unit - (IN)SOC unit number. 2498 * l3cfg - (IN)Pointer to memory for l3 table related information. 2499 * negate - (IN)0 means interface match; 1 means not match 2500 * Returns: 2501 * BCM_E_XXX 2502 */ 2503 int 2504 bcm_tr3_l3_del_intf(int unit, _bcm_l3_cfg_t *l3cfg, int negate) 2505 { 2506 int rv; /* Operation return status. */ 2507 int tmp_rv; /* First error occured. */ 2508 bcm_if_t intf; /* Deleted interface id. */ 2509 int nh_index; /* Next hop index. */ 2510 bcm_l3_egress_t egr; /* Egress object. */ 2511 _bcm_if_del_pattern_t pattern; /* Interface & negate combination 2512 to be used for every l3 entry 2513 comparision. */ 2514 2515 /* Make sure module was initialized. */ 2516 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 2517 return (BCM_E_INIT); 2518 } 2519 2520 /* Input parameters check */ 2521 if (NULL == l3cfg) { 2522 return (BCM_E_PARAM); 2523 } 2524 2525 intf = l3cfg->l3c_intf; 2526 2527 /* Check l3 switching mode. */ 2528 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 2529 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 2530 BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 2531 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 2532 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 2533 } else { 2534 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 2535 } 2536 /* Get egress object information. */ 2537 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr)); 2538 /* Use egress object interface for iteration */ 2539 intf = egr.intf; 2540 } 2541 } 2542 2543 pattern.l3_intf = intf; 2544 pattern.negate = negate; 2545 2546 /* Delete all ipv4 entries matching the interface. */ 2547 tmp_rv = _bcm_tr3_l3_del_match(unit, 0, (void *)&pattern, 2548 _bcm_xgs3_l3_intf_cmp, NULL, NULL); 2549 2550 /* Delete all ipv6 entries matching the interface. */ 2551 rv = _bcm_tr3_l3_del_match(unit, BCM_L3_IP6, (void *)&pattern, 2552 _bcm_xgs3_l3_intf_cmp, NULL, NULL); 2553 2554 return (tmp_rv < 0) ? tmp_rv : rv; 2555 } 2556 2557 /* 2558 * Function: 2559 * _bcm_tr3_l3_get_by_idx 2560 * Purpose: 2561 * Get an entry from L3 table by index. 2562 * Parameters: 2563 * unit - (IN)SOC unit number. 2564 * dma_ptr - (IN)Table pointer in dma. 2565 * idx - (IN)Index to read. 2566 * l3cfg - (OUT)l3 entry search result. 2567 * nh_index - (OUT)Next hop index. 2568 * Returns: 2569 * BCM_E_XXX 2570 */ 2571 int 2572 _bcm_tr3_l3_get_by_idx(int unit, void *dma_ptr, int idx, 2573 _bcm_l3_cfg_t *l3cfg, int *nh_idx) 2574 { 2575 int v6; 2576 int embeded_nh; 2577 soc_mem_t mem; 2578 int rv = BCM_E_UNAVAIL; /* Operation return code. */ 2579 2580 /* Make sure module was initialized. */ 2581 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 2582 return (BCM_E_INIT); 2583 } 2584 2585 if (l3cfg->l3c_flags & BCM_L3_IPMC) { 2586 /* Get multicast entry. */ 2587 rv = _bcm_tr3_l3_ipmc_get_by_idx(unit, NULL, idx, l3cfg); 2588 } else { 2589 /* Get unicast entry. */ 2590 v6 = (l3cfg->l3c_flags & BCM_L3_IP6); 2591 embeded_nh = (l3cfg->l3c_flags & BCM_L3_DEREFERENCED_NEXTHOP); 2592 mem = (v6) ? 2593 ((embeded_nh) ? 2594 BCM_XGS3_L3_MEM(unit, v6_4) : BCM_XGS3_L3_MEM(unit, v6)) : 2595 ((embeded_nh) ? 2596 BCM_XGS3_L3_MEM(unit, v4_2) : BCM_XGS3_L3_MEM(unit, v4)); 2597 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, NULL, mem, idx, l3cfg, nh_idx); 2598 } 2599 return rv; 2600 } 2601 2602 /* 2603 * Function: 2604 * _bcm_tr3_l3_del_match 2605 * Purpose: 2606 * Delete an entry in L3 table matches a certain rule. 2607 * Parameters: 2608 * unit - (IN)SOC unit number. 2609 * flags. - (IN)Generic l3 flags. 2610 * pattern - (IN)Comparison match argurment. 2611 * cmp_func - (IN)Comparison function. 2612 * notify_cb - (IN)Delete notification callback. 2613 * user_data - (IN)User provided cookie for callback. 2614 * Returns: 2615 * BCM_E_XXX 2616 */ 2617 int 2618 _bcm_tr3_l3_del_match(int unit, int flags, void *pattern, 2619 bcm_xgs3_ent_op_cb cmp_func, 2620 bcm_l3_host_traverse_cb notify_cb, void *user_data) 2621 { 2622 int rv; 2623 int ipv6; /* IPv6/IPv4 lookup flag. */ 2624 int nh_idx; /* Next hop index. */ 2625 int tbl, idx; /* Iteration indices. */ 2626 int cmp_result; /* Compare against pattern result. */ 2627 bcm_l3_host_t info; /* Host cb buffer. */ 2628 _bcm_l3_cfg_t l3cfg; /* Hw entry info. */ 2629 int idx_max; 2630 int num_tables = 1; 2631 int table_ent_size; 2632 int table_size; 2633 char *l3_tbl_ptr = NULL; 2634 2635 soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES] = 2636 {INVALIDm, INVALIDm, INVALIDm, INVALIDm}; 2637 2638 /* Check Protocol. */ 2639 ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE; 2640 2641 if (ipv6) { 2642 if (BCM_XGS3_L3_IP6_CNT(unit) == 0) { 2643 /* No Ipv6 entries. Nothing to delete */ 2644 return BCM_E_NONE; 2645 } 2646 mem[0] = BCM_XGS3_L3_MEM(unit, v6); 2647 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2648 mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 2649 num_tables++; 2650 } 2651 } else { 2652 if (BCM_XGS3_L3_IP4_CNT(unit) == 0) { 2653 /* No Ipv4 entries. Nothing to delete */ 2654 return BCM_E_NONE; 2655 } 2656 mem[0] = BCM_XGS3_L3_MEM(unit, v4); 2657 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2658 mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 2659 num_tables++; 2660 } 2661 } 2662 2663 for (tbl = 0; tbl < num_tables; tbl++) { 2664 if (INVALIDm == mem[tbl]) { 2665 continue; 2666 } 2667 idx_max = soc_mem_index_max(unit, mem[tbl]); 2668 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]); 2669 BCM_IF_ERROR_RETURN( 2670 bcm_xgs3_l3_tbl_dma(unit, mem[tbl], table_ent_size, 2671 "l3_tbl", &l3_tbl_ptr, &table_size)); 2672 2673 for (idx = 0; idx <= idx_max; idx++) { 2674 2675 /* Set protocol. */ 2676 l3cfg.l3c_flags = flags; 2677 2678 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, l3_tbl_ptr, mem[tbl], idx, 2679 &l3cfg, &nh_idx); 2680 /* Check for read errors & invalid entries. */ 2681 if (rv < 0) { 2682 if (rv != BCM_E_NOT_FOUND) { 2683 if (l3_tbl_ptr) { 2684 soc_cm_sfree(unit, l3_tbl_ptr); 2685 } 2686 return rv; 2687 } 2688 continue; 2689 } 2690 2691 /* Check read entry flags & update index accordingly. */ 2692 if (BCM_L3_CMP_EQUAL != 2693 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 2694 continue; 2695 } 2696 2697 /* If compare function provided match the entry against pattern */ 2698 if (cmp_func) { 2699 rv = (*cmp_func) (unit, pattern, (void *)&l3cfg, 2700 (void *)&nh_idx, &cmp_result); 2701 if (BCM_FAILURE(rv)) { 2702 soc_cm_sfree(unit, l3_tbl_ptr); 2703 return rv; 2704 } 2705 /* If entry doesn't match the pattern don't delete it. */ 2706 if (BCM_L3_CMP_EQUAL != cmp_result) { 2707 continue; 2708 } 2709 } 2710 2711 /* Entry matches the rule -> delete it. */ 2712 rv = _bcm_tr3_l3_ism_del(unit, &l3cfg); 2713 if (BCM_FAILURE(rv)) { 2714 soc_cm_sfree(unit, l3_tbl_ptr); 2715 return rv; 2716 } 2717 2718 /* Release next hop index. */ 2719 rv = bcm_xgs3_nh_del(unit, 0, nh_idx); 2720 if (BCM_FAILURE(rv)) { 2721 soc_cm_sfree(unit, l3_tbl_ptr); 2722 return rv; 2723 } 2724 2725 /* Check if notification required. */ 2726 if (notify_cb) { 2727 /* Fill host info. */ 2728 _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info); 2729 /* Call notification callback. */ 2730 (*notify_cb) (unit, idx, &info, user_data); 2731 } 2732 } 2733 2734 if (l3_tbl_ptr) { 2735 soc_cm_sfree(unit, l3_tbl_ptr); 2736 l3_tbl_ptr = NULL; 2737 } 2738 } 2739 2740 if (BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 2741 idx = 0; 2742 num_tables = 1; 2743 if (ipv6) { 2744 mem[0] = BCM_XGS3_L3_MEM(unit, v6_esm); 2745 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2746 mem[1] = BCM_XGS3_L3_MEM(unit, v6_esm_wide); 2747 num_tables++; 2748 } 2749 } else { 2750 mem[0] = BCM_XGS3_L3_MEM(unit, v4_esm); 2751 if (soc_feature(unit, soc_feature_l3_extended_host_entry)) { 2752 mem[1] = BCM_XGS3_L3_MEM(unit, v4_esm_wide); 2753 num_tables++; 2754 } 2755 } 2756 2757 for (tbl = 0; tbl < num_tables; tbl++) { 2758 idx = 0; /* reset idx for each table */ 2759 if (INVALIDm == mem[tbl]) { 2760 continue; 2761 } 2762 2763 while (idx < _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, (tbl + (2 * ipv6)))) { 2764 2765 /* Set protocol. */ 2766 l3cfg.l3c_flags = flags; 2767 2768 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, NULL, mem[tbl], idx, 2769 &l3cfg, &nh_idx); 2770 /* Check for read errors & invalid entries. */ 2771 if (rv < 0) { 2772 if (rv != BCM_E_NOT_FOUND) { 2773 return rv; 2774 } 2775 idx++; 2776 continue; 2777 } 2778 /* Check read entry flags & update index accordingly. */ 2779 if (BCM_L3_CMP_EQUAL != 2780 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) { 2781 idx++; 2782 continue; 2783 } 2784 2785 /* If compare function provided match the entry against pattern */ 2786 if (cmp_func) { 2787 BCM_IF_ERROR_RETURN((*cmp_func) (unit, pattern, (void *)&l3cfg, 2788 (void *)&nh_idx, &cmp_result)); 2789 /* If entry doesn't match the pattern don't delete it. */ 2790 if (BCM_L3_CMP_EQUAL != cmp_result) { 2791 idx++; 2792 continue; 2793 } 2794 } 2795 2796 /* Entry matches the rule -> delete it. */ 2797 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_esm_del(unit, &l3cfg)); 2798 2799 /* Release next hop index. */ 2800 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx)); 2801 2802 /* Check if notification required. */ 2803 if (notify_cb) { 2804 /* Fill host info. */ 2805 _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info); 2806 /* Call notification callback. */ 2807 (*notify_cb) (unit, idx, &info, user_data); 2808 } 2809 } 2810 } /* per esm table */ 2811 } /* esm */ 2812 2813 return (BCM_E_NONE); 2814 } 2815 2816 /* 2817 * Function: 2818 * _bcm_tr3_esm_host_tbl_init 2819 * Purpose: 2820 * Initialize TR3 external host table sw state. 2821 * Parameters: 2822 * unit - (IN)SOC unit number. 2823 * Returns: 2824 * BCM_E_XXX 2825 */ 2826 int 2827 _bcm_tr3_esm_host_tbl_init(int unit) 2828 { 2829 int tbl; 2830 int v6 = 0; 2831 uint32 *esm_entry; 2832 2833 soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES]; 2834 ext_ipv4_ucast_entry_t l3v4_entry; 2835 ext_ipv4_ucast_wide_entry_t l3v4wide_entry; 2836 ext_ipv6_128_ucast_entry_t l3v6_entry; 2837 ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry; 2838 2839 mem[0] = EXT_L3_UCAST_DATA_IPV4m; 2840 mem[1] = EXT_L3_UCAST_DATA_WIDE_IPV4m; 2841 mem[2] = EXT_L3_UCAST_DATA_IPV6_128m; 2842 mem[3] = EXT_L3_UCAST_DATA_WIDE_IPV6_128m; 2843 2844 for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES; tbl++) { 2845 if (_TR3_ESM_HOST_TBL_STATE(unit, tbl) != NULL) { 2846 sal_free(_TR3_ESM_HOST_TBL_STATE(unit, tbl)); 2847 _TR3_ESM_HOST_TBL_STATE(unit, tbl) = NULL; 2848 } 2849 2850 _TR3_ESM_HOST_TBL_STATE(unit, tbl) = (int*) 2851 sal_alloc(sizeof (int), "ESM host free idx info"); 2852 2853 if (NULL == _TR3_ESM_HOST_TBL_STATE(unit, tbl)) { 2854 return (BCM_E_MEMORY); 2855 } 2856 2857 if (soc_mem_index_count(unit, mem[tbl])) { 2858 /* ESM table exists and its size is configured */ 2859 if ((mem[tbl] == EXT_L3_UCAST_DATA_IPV6_128m) || 2860 (mem[tbl] == EXT_L3_UCAST_DATA_WIDE_IPV6_128m)) { 2861 v6 = 1; 2862 } 2863 2864 BCM_TR3_ESM_L3_HOST_ENTRY_BUF(v6, mem[tbl], esm_entry, 2865 l3v4_entry, 2866 l3v4wide_entry, 2867 l3v6_entry, 2868 l3v6wide_entry); 2869 SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem[tbl], 2870 MEM_BLOCK_ANY, 0, esm_entry)); 2871 2872 soc_mem_field32_set(unit, mem[tbl], esm_entry, CLASS_IDf, 2873 _TR3_ESM_HOST_ENTRY_INVALID_MARKER); 2874 2875 BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem[tbl], 2876 MEM_BLOCK_ALL, 0, esm_entry)); 2877 } 2878 _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) = 0; 2879 } 2880 2881 return (BCM_E_NONE); 2882 } 2883 2884 /* 2885 * Function: 2886 * _bcm_tr3_esm_host_tbl_deinit 2887 * Purpose: 2888 * Free the TR3 external host table sw state. 2889 * Parameters: 2890 * unit - (IN)SOC unit number. 2891 * Returns: 2892 * BCM_E_XXX 2893 */ 2894 int 2895 _bcm_tr3_esm_host_tbl_deinit(int unit) 2896 { 2897 int tbl; 2898 2899 for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES; tbl++) { 2900 if (_TR3_ESM_HOST_TBL_STATE(unit, tbl) != NULL) { 2901 sal_free(_TR3_ESM_HOST_TBL_STATE(unit, tbl)); 2902 _TR3_ESM_HOST_TBL_STATE(unit, tbl) = NULL; 2903 } 2904 } 2905 2906 return (BCM_E_NONE); 2907 } 2908 2909 /* 2910 * Function: 2911 * _bcm_hx4_l3_defip_init 2912 * Purpose: 2913 * Configure HX4 internal route table as per soc properties. 2914 * (tcam pairing for IPv4, 64/128 bit IPV6 prefixes) 2915 * Parameters: 2916 * unit - (IN)SOC unit number. 2917 * Returns: 2918 * BCM_E_XXX 2919 */ 2920 STATIC int 2921 _bcm_hx4_l3_defip_init(int unit) 2922 { 2923 int defip_config; 2924 int ipv6_64_depth = 0; 2925 uint32 defip_key_sel_0 = 0; 2926 uint32 defip_key_sel_1 = 0; 2927 int mem_v4, mem_v6, mem_v6_128; /* Route table memories */ 2928 int ranger_device; /* Ranger specific config */ 2929 int num_ipv6_128b_entries; 2930 int tcam_pair_count = 0; 2931 int tcam_idx = 0; 2932 int start_index = 0; 2933 int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 2934 2935 ranger_device = FALSE; 2936 if (soc_feature(unit, soc_feature_l3_256_defip_table)) { 2937 ranger_device = TRUE; 2938 } 2939 2940 defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 2941 ((ranger_device) ? 0 : 1)); 2942 num_ipv6_128b_entries = SOC_L3_DEFIP_MAX_128B_ENTRIES(unit); 2943 BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit) = num_ipv6_128b_entries; 2944 2945 2946 if (num_ipv6_128b_entries) { 2947 tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) + 2948 ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0); 2949 } else { 2950 tcam_pair_count = 0; 2951 } 2952 2953 if (tcam_pair_count > (SOC_CONTROL(unit)->l3_defip_max_tcams / 2)) { 2954 tcam_pair_count = (SOC_CONTROL(unit)->l3_defip_max_tcams / 2); 2955 } 2956 2957 if (!defip_config) { 2958 if (ranger_device) { 2959 ipv6_64_depth = _BCM_HX4_RANGER_DEFIP_TCAM_DEPTH; 2960 } else { 2961 ipv6_64_depth = SOC_CONTROL(unit)->l3_defip_max_tcams * tcam_depth; 2962 } 2963 } else { 2964 for (tcam_idx = 0; tcam_idx < tcam_pair_count; tcam_idx++) { 2965 defip_key_sel_0 |= (0x01 << tcam_idx); 2966 } 2967 2968 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 2969 if (ranger_device) { 2970 defip_key_sel_0 = 0x3; 2971 ipv6_64_depth = 0; 2972 } 2973 } 2974 2975 /* LPM config regs. */ 2976 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_0r(unit, defip_key_sel_0)); 2977 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_1r(unit, defip_key_sel_1)); 2978 2979 /* Get memory for IPv4 entries. */ 2980 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, 0, 0, &mem_v4)); 2981 2982 /* Initialize IPv4 entries lookup engine. */ 2983 BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit)); 2984 2985 /* Get memory for IPv6 entries. */ 2986 BCM_IF_ERROR_RETURN 2987 (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6)); 2988 2989 /* Initialize IPv6 entries lookup engine. */ 2990 if (mem_v4 != mem_v6) { 2991 BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit)); 2992 } 2993 2994 /* Overriding defaults set during lpm init */ 2995 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 2996 BCM_IF_ERROR_RETURN(soc_fb_lpm128_init(unit)); 2997 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2); 2998 start_index = (tcam_pair_count * tcam_depth * 2); 2999 } else { 3000 start_index = 0; 3001 } 3002 3003 SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit))) = ipv6_64_depth; 3004 SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index; 3005 SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit))) = start_index - 1; 3006 3007 BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 3008 start_index)); 3009 3010 /* Get memory for IPv6 entries with prefix length > 64. */ 3011 BCM_IF_ERROR_RETURN 3012 (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 3013 BCM_XGS3_L3_IPV6_PREFIX_LEN, 3014 &mem_v6_128)); 3015 3016 /* Initialize IPv6 entries lookup engine. */ 3017 if (mem_v6 != mem_v6_128) { 3018 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3019 return soc_fb_lpm128_init(unit); 3020 } else { 3021 BCM_IF_ERROR_RETURN(_bcm_tr3_defip_pair128_init(unit)); 3022 } 3023 } 3024 3025 return BCM_E_NONE; 3026 } 3027 3028 /* 3029 * Function: 3030 * _bcm_tr3_l3_defip_init 3031 * Purpose: 3032 * Configure TR3 internal route table as per soc properties. 3033 * (tcam pairing for IPv4, 64/128 bit IPV6 prefixes) 3034 * Parameters: 3035 * unit - (IN)SOC unit number. 3036 * Returns: 3037 * BCM_E_XXX 3038 */ 3039 int 3040 _bcm_tr3_l3_defip_init(int unit) 3041 { 3042 int defip_config; 3043 int index_min, index_max; 3044 uint32 defip_key_sel_val = 0; 3045 int mem_v4, mem_v6, mem_v6_128; /* Route table memories */ 3046 int ipv6_64_depth = 0; 3047 int rangerplus_device; /* Ranger plus specific config */ 3048 int num_ipv6_128b_entries; 3049 int start_index = 0; 3050 int tcam_pair_count = 0; 3051 int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 3052 3053 if (soc_feature(unit, soc_feature_l3_expanded_defip_table)) { 3054 return _bcm_hx4_l3_defip_init(unit);/* HX4, Ranger */ 3055 } 3056 3057 rangerplus_device = FALSE; 3058 if (soc_feature(unit, soc_feature_l3_256_defip_table)) { 3059 rangerplus_device = TRUE; 3060 } 3061 3062 defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 3063 (rangerplus_device) ? 0 : 1); 3064 num_ipv6_128b_entries = SOC_L3_DEFIP_MAX_128B_ENTRIES(unit); 3065 BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit) = num_ipv6_128b_entries; 3066 3067 3068 if (num_ipv6_128b_entries) { 3069 tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) + 3070 ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0); 3071 } else { 3072 tcam_pair_count = 0; 3073 } 3074 3075 if ((rangerplus_device == TRUE) || 3076 soc_feature(unit, soc_feature_l3_reduced_defip_table)) { 3077 if (!defip_config) { 3078 if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) { 3079 ipv6_64_depth = 6 * _BCM_TR3_DEFIP_TCAM_DEPTH; 3080 } else { 3081 ipv6_64_depth = 8 * _BCM_TR3_DEFIP_TCAM_DEPTH; 3082 if (rangerplus_device) { 3083 ipv6_64_depth = _BCM_HX4_RANGER_DEFIP_TCAM_DEPTH; 3084 } 3085 } 3086 } else if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) { 3087 switch (tcam_pair_count) { 3088 case 1: 3089 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3090 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3091 0x1); 3092 break; 3093 3094 case 2: 3095 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3096 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3097 0x1); 3098 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3099 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3100 0x1); 3101 break; 3102 3103 case 3: 3104 default: 3105 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3106 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3107 0x1); 3108 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3109 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3110 0x1); 3111 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3112 &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 3113 0x1); 3114 break; 3115 3116 } 3117 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3118 } else { 3119 3120 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3121 V6_KEY_SEL_CAM0_1f, 0x1); 3122 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3123 V6_KEY_SEL_CAM2_3f, 0x1); 3124 3125 ipv6_64_depth = 4 * _BCM_TR3_DEFIP_TCAM_DEPTH; 3126 if (rangerplus_device) { 3127 ipv6_64_depth = 0; 3128 } 3129 } 3130 } else { /* Tr3 case */ 3131 switch (tcam_pair_count) { 3132 case 1: 3133 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3134 V6_KEY_SEL_CAM0_1f, 0x1); 3135 break; 3136 3137 case 2: 3138 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3139 V6_KEY_SEL_CAM0_1f, 0x1); 3140 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3141 V6_KEY_SEL_CAM2_3f, 0x1); 3142 break; 3143 3144 case 3: 3145 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3146 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3147 0x1); 3148 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3149 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3150 0x1); 3151 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3152 &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 3153 0x1); 3154 break; 3155 3156 case 4: 3157 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3158 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3159 0x1); 3160 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3161 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3162 0x1); 3163 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3164 &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 3165 0x1); 3166 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3167 &defip_key_sel_val, V6_KEY_SEL_CAM6_7f, 3168 0x1); 3169 break; 3170 3171 default: 3172 break; 3173 } 3174 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3175 } 3176 3177 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SELr(unit, defip_key_sel_val)); 3178 3179 /* Get memory for IPv4 entries. */ 3180 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, 0, 0, &mem_v4)); 3181 3182 /* Initialize IPv4 entries lookup engine. */ 3183 if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) { 3184 BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_init(unit, mem_v4)); 3185 } else { 3186 BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit)); 3187 } 3188 3189 /* Get memory for IPv6 entries. */ 3190 BCM_IF_ERROR_RETURN 3191 (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6)); 3192 3193 /* Initialize IPv6 entries lookup engine. */ 3194 if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_64_DEFIPm) || 3195 BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) { 3196 BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_init(unit, mem_v6)); 3197 } else { 3198 if (mem_v4 != mem_v6) { 3199 BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit)); 3200 } 3201 /* Overriding defaults set during lpm init */ 3202 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3203 BCM_IF_ERROR_RETURN(soc_fb_lpm128_init(unit)); 3204 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2); 3205 start_index = (tcam_pair_count * tcam_depth * 2); 3206 } else { 3207 start_index = 0; 3208 } 3209 3210 SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index; 3211 SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit))) = start_index - 1; 3212 SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit))) = ipv6_64_depth; 3213 BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 3214 start_index)); 3215 } 3216 3217 /* Get memory for IPv6 entries with prefix length > 64. */ 3218 BCM_IF_ERROR_RETURN 3219 (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 3220 BCM_XGS3_L3_IPV6_PREFIX_LEN, 3221 &mem_v6_128)); 3222 3223 /* Initialize IPv6 entries lookup engine. */ 3224 if (mem_v6 != mem_v6_128) { 3225 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3226 return soc_fb_lpm128_init(unit); 3227 } else { 3228 BCM_IF_ERROR_RETURN(_bcm_tr3_defip_pair128_init(unit)); 3229 } 3230 } 3231 3232 /* Update defip size in l3 book keeping if ESM present */ 3233 if (soc_feature(unit, soc_feature_esm_support) && (L3_DEFIPm != mem_v4)) { 3234 index_min = soc_mem_index_min(unit, mem_v4); 3235 index_max = soc_mem_index_max(unit, mem_v4); 3236 BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = index_max - index_min + 1; 3237 } 3238 if (!SOC_LPM_STAT_INIT_CHECK(unit)) { 3239 if (soc_feature(unit, soc_feature_l3_shared_defip_table)) { 3240 if (soc_fb_lpm_stat_init(unit) < 0) { 3241 /* COVERITY 3242 * soc_fb_lpm_deinit is called in error condition. 3243 * so irrespective of its return value we are going to release lpm lock 3244 * and return E_INTERNAL. Hence we can ignore the return value 3245 */ 3246 /* coverity[check_return] */ 3247 soc_fb_lpm_deinit(unit); 3248 return SOC_E_INTERNAL; 3249 } 3250 } 3251 } 3252 return BCM_E_NONE; 3253 } 3254 3255 /* 3256 * Function: 3257 * _bcm_tr3_l3_defip_deinit 3258 * Purpose: 3259 * De-initialize route table for triumph3 devices. 3260 * Parameters: 3261 * unit - (IN) SOC unit number. 3262 * Returns: 3263 * BCM_E_XXX 3264 */ 3265 int 3266 _bcm_tr3_l3_defip_deinit(int unit) 3267 { 3268 soc_mem_t mem_v4; /* IPv4 Route table memory. */ 3269 soc_mem_t mem_v6; /* IPv6 Route table memory. */ 3270 soc_mem_t mem_v6_128; /* IPv6 full prefix route table memory. */ 3271 3272 /* Get memory for IPv4 entries. */ 3273 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, 0, 0, &mem_v4)); 3274 3275 /* Initialize IPv4 entries lookup engine. */ 3276 if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) { 3277 BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_deinit(unit, mem_v4)); 3278 } else { 3279 BCM_IF_ERROR_RETURN(soc_fb_lpm_deinit(unit)); 3280 } 3281 3282 /* Get memory for IPv6 entries. */ 3283 BCM_IF_ERROR_RETURN 3284 (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6)); 3285 3286 /* Initialize IPv6 entries lookup engine. */ 3287 if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_64_DEFIPm) || 3288 BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) { 3289 BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_deinit(unit, mem_v6)); 3290 } else { 3291 if (mem_v4 != mem_v6) { 3292 BCM_IF_ERROR_RETURN(soc_fb_lpm_deinit(unit)); 3293 } 3294 } 3295 3296 /* Get memory for IPv6 entries with prefix length > 64. */ 3297 BCM_IF_ERROR_RETURN 3298 (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 3299 BCM_XGS3_L3_IPV6_PREFIX_LEN, 3300 &mem_v6_128)); 3301 3302 /* Initialize IPv6 entries lookup engine. */ 3303 if (mem_v6 != mem_v6_128) { 3304 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3305 BCM_IF_ERROR_RETURN(soc_fb_lpm128_deinit(unit)); 3306 } else { 3307 BCM_IF_ERROR_RETURN(_bcm_defip_pair128_deinit(unit)); 3308 } 3309 } 3310 return (BCM_E_NONE); 3311 3312 } 3313 3314 /* 3315 * Function: 3316 * _bcm_tr3_l3_lpm_get 3317 * Purpose: 3318 * Get an entry from the route table. 3319 * Parameters: 3320 * unit - (IN)SOC unit number. 3321 * lpm_cfg - (IN)Buffer to fill defip information. 3322 * nh_ecmp_idx - (IN)Next hop or ecmp group index 3323 * Returns: 3324 * BCM_E_XXX 3325 */ 3326 int 3327 _bcm_tr3_l3_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 3328 { 3329 soc_mem_t mem = L3_DEFIPm; 3330 uint32 max_v6_entries = BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit); 3331 3332 /* Input parameters check */ 3333 if (NULL == lpm_cfg) { 3334 return (BCM_E_PARAM); 3335 } 3336 3337 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 3338 lpm_cfg->defip_sub_len, &mem)); 3339 3340 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3341 if (mem == L3_DEFIPm || mem == L3_DEFIP_PAIR_128m) { 3342 return _bcm_l3_scaled_lpm_get(unit, lpm_cfg, nh_ecmp_idx); 3343 } 3344 } 3345 3346 switch (mem) { 3347 case EXT_IPV4_DEFIPm: 3348 case EXT_IPV6_64_DEFIPm: 3349 case EXT_IPV6_128_DEFIPm: 3350 return _bcm_tr3_ext_lpm_match(unit, lpm_cfg, nh_ecmp_idx); 3351 case L3_DEFIP_PAIR_128m: 3352 if (max_v6_entries > 0) { 3353 return _bcm_l3_defip_pair128_get(unit, lpm_cfg, nh_ecmp_idx); 3354 } 3355 break; 3356 default: 3357 if (soc_mem_index_count(unit, L3_DEFIPm) > 0) { 3358 return _bcm_fb_lpm_get(unit, lpm_cfg, nh_ecmp_idx); 3359 } 3360 break; 3361 } 3362 3363 return (BCM_E_NOT_FOUND); 3364 } 3365 3366 /* 3367 * Function: 3368 * _bcm_tr3_l3_lpm_add 3369 * Purpose: 3370 * Add an entry to TR3 route table table. 3371 * Parameters: 3372 * unit - (IN)SOC unit number. 3373 * lpm_cfg - (IN)Buffer to fill defip information. 3374 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 3375 * Returns: 3376 * BCM_E_XXX 3377 */ 3378 int 3379 _bcm_tr3_l3_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 3380 { 3381 soc_mem_t mem = L3_DEFIPm; 3382 3383 /* Input parameters check */ 3384 if (NULL == lpm_cfg) { 3385 return (BCM_E_PARAM); 3386 } 3387 3388 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 3389 lpm_cfg->defip_sub_len, &mem)); 3390 3391 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3392 if (mem == L3_DEFIPm || mem == L3_DEFIP_PAIR_128m) { 3393 return _bcm_l3_scaled_lpm_add(unit, lpm_cfg, nh_ecmp_idx); 3394 } 3395 } 3396 3397 switch (mem) { 3398 case EXT_IPV4_DEFIPm: 3399 case EXT_IPV6_64_DEFIPm: 3400 case EXT_IPV6_128_DEFIPm: 3401 if (BCM_L3_RPE_SET(lpm_cfg->defip_flags)) { 3402 if (lpm_cfg->defip_lookup_class > SOC_ADDR_CLASS_MAX(unit)) { 3403 return (BCM_E_PARAM); 3404 } 3405 } else { 3406 lpm_cfg->defip_prio = (lpm_cfg->defip_lookup_class & 0x3C0) >> 6; 3407 lpm_cfg->defip_lookup_class = lpm_cfg->defip_lookup_class & 0x3F; 3408 } 3409 3410 return _bcm_tr3_ext_lpm_add(unit, lpm_cfg, nh_ecmp_idx); 3411 case L3_DEFIP_PAIR_128m: 3412 if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) > 0) { 3413 return _bcm_l3_defip_pair128_add(unit, lpm_cfg, nh_ecmp_idx); 3414 } 3415 break; 3416 default: 3417 if (soc_mem_index_count(unit, L3_DEFIPm) > 0) { 3418 return _bcm_fb_lpm_add(unit, lpm_cfg, nh_ecmp_idx); 3419 } 3420 break; 3421 } 3422 3423 return (BCM_E_FULL); 3424 } 3425 3426 /* 3427 * Function: 3428 * _bcm_tr3_l3_lpm_del 3429 * Purpose: 3430 * Delete an entry from the route table. 3431 * Parameters: 3432 * unit - (IN)SOC unit number. 3433 * lpm_cfg - (IN)Buffer to fill defip information. 3434 * Returns: 3435 * BCM_E_XXX 3436 */ 3437 int 3438 _bcm_tr3_l3_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 3439 { 3440 soc_mem_t mem = L3_DEFIPm; 3441 uint32 max_v6_entries = BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit); 3442 3443 /* Input parameters check */ 3444 if (NULL == lpm_cfg) { 3445 return (BCM_E_PARAM); 3446 } 3447 3448 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, lpm_cfg->defip_flags, 3449 lpm_cfg->defip_sub_len, &mem)); 3450 3451 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3452 if (mem == L3_DEFIPm || mem == L3_DEFIP_PAIR_128m) { 3453 return _bcm_l3_scaled_lpm_del(unit, lpm_cfg); 3454 } 3455 } 3456 3457 switch (mem) { 3458 case EXT_IPV4_DEFIPm: 3459 case EXT_IPV6_64_DEFIPm: 3460 case EXT_IPV6_128_DEFIPm: 3461 return _bcm_tr3_ext_lpm_delete(unit, lpm_cfg); 3462 case L3_DEFIP_PAIR_128m: 3463 if (max_v6_entries > 0) { 3464 return _bcm_l3_defip_pair128_del(unit, lpm_cfg); 3465 } 3466 break; 3467 default: 3468 if (soc_mem_index_count(unit, L3_DEFIPm) > 0) { 3469 return _bcm_fb_lpm_del(unit, lpm_cfg); 3470 } 3471 break; 3472 } 3473 3474 return (BCM_E_NOT_FOUND); 3475 } 3476 3477 /* 3478 * Function: 3479 * _bcm_tr3_l3_lpm_update_match 3480 * Purpose: 3481 * Update/Delete all entries in defip table matching a certain rule. 3482 * Parameters: 3483 * unit - (IN)SOC unit number. 3484 * trv_data - (IN)Delete pattern + compare,act,notify routines. 3485 * Returns: 3486 * BCM_E_XXX 3487 */ 3488 int 3489 _bcm_tr3_l3_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 3490 { 3491 soc_mem_t mem = L3_DEFIPm; /* Route table memory. */ 3492 int rv1 = BCM_E_NONE; 3493 int rv2 = BCM_E_NONE; 3494 uint32 max_v6_entries = BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit); 3495 3496 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, trv_data->flags, 0, &mem)); 3497 3498 switch (mem) { 3499 case EXT_IPV4_DEFIPm: 3500 case EXT_IPV6_64_DEFIPm: 3501 case EXT_IPV6_128_DEFIPm: 3502 return _bcm_tr3_defip_traverse(unit, trv_data); 3503 default: 3504 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3505 return _bcm_l3_scaled_lpm_update_match(unit, trv_data); 3506 } 3507 3508 if ((trv_data->flags & BCM_L3_IP6) && (max_v6_entries > 0)) { 3509 rv2 = _bcm_l3_defip_pair128_update_match(unit, trv_data); 3510 } 3511 3512 if (soc_mem_index_count(unit, L3_DEFIPm) > 0) { 3513 rv1 = _bcm_fb_lpm_update_match(unit, trv_data); 3514 } 3515 BCM_IF_ERROR_RETURN(rv1); 3516 BCM_IF_ERROR_RETURN(rv2); 3517 } 3518 3519 return (BCM_E_NONE); 3520 } 3521 3522 /* 3523 * Function: 3524 * _bcm_fs_l3_defip_urpf_enable 3525 * Purpose: 3526 * Configure HX4 internal route table for URPF mode 3527 * Parameters: 3528 * unit - (IN)SOC unit number. 3529 * enable - (IN)Enable/disable URPF. 3530 * Returns: 3531 * BCM_E_XXX 3532 */ 3533 STATIC int 3534 _bcm_fs_l3_defip_urpf_enable(int unit, int enable) 3535 { 3536 int defip_config; 3537 int ipv6_64_depth = 0; 3538 int ipv6_128_depth = 0; 3539 int ipv6_128_dip_offset = 0; 3540 uint32 defip_key_sel_0 = 0; 3541 uint32 defip_key_sel_1 = 0; 3542 uint32 num_ipv6_128b_entries = 0; 3543 int tcam_pair_count = 0; 3544 uint32 tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 3545 int tcam_idx = 0; 3546 int start_index = 0; 3547 3548 defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1); 3549 num_ipv6_128b_entries = SOC_L3_DEFIP_MAX_128B_ENTRIES(unit); 3550 3551 if (num_ipv6_128b_entries) { 3552 tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) + 3553 ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0); 3554 } else { 3555 tcam_pair_count = 0; 3556 } 3557 3558 if (tcam_pair_count > (SOC_CONTROL(unit)->l3_defip_max_tcams / 2)) { 3559 tcam_pair_count = (SOC_CONTROL(unit)->l3_defip_max_tcams / 2); 3560 } 3561 3562 if (enable) { 3563 3564 /* Ranger device does not support URPF */ 3565 defip_key_sel_1 = 0xFF00; 3566 if (defip_config) { 3567 switch (tcam_pair_count) { 3568 case 0: 3569 ipv6_64_depth = 8 * tcam_depth; 3570 start_index = 0; 3571 break; 3572 3573 case 1: 3574 case 2: 3575 defip_key_sel_0 = 0x11; 3576 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3577 ipv6_64_depth = 6 * tcam_depth; 3578 start_index = 2 * tcam_depth; 3579 } 3580 break; 3581 case 3: 3582 case 4: 3583 defip_key_sel_0 = 0x33; 3584 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3585 ipv6_64_depth = 4 * tcam_depth; 3586 start_index = 4 * tcam_depth; 3587 } 3588 break; 3589 case 5: 3590 case 6: 3591 defip_key_sel_0 = 0x77; 3592 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3593 ipv6_64_depth = 2 * tcam_depth; 3594 start_index = 6 * tcam_depth; 3595 } 3596 break; 3597 case 7: 3598 case 8: 3599 default: 3600 defip_key_sel_0 = 0xFF; 3601 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3602 ipv6_64_depth = 0; 3603 start_index = 8 * tcam_depth; 3604 } 3605 break; 3606 } 3607 3608 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3609 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm) / 2; 3610 ipv6_128_dip_offset = num_ipv6_128b_entries / 2; 3611 ipv6_128_depth = num_ipv6_128b_entries / 2; 3612 } 3613 } else { 3614 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm) / 2; 3615 ipv6_128_dip_offset = 0; 3616 ipv6_128_depth = 0; 3617 } 3618 } else { /* Disable uRPF */ 3619 if (defip_config) { 3620 for (tcam_idx = 0; tcam_idx < tcam_pair_count; tcam_idx++) { 3621 defip_key_sel_0 |= (0x01 << tcam_idx); 3622 } 3623 3624 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3625 ipv6_128_dip_offset = num_ipv6_128b_entries; 3626 ipv6_128_depth = num_ipv6_128b_entries; 3627 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3628 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2); 3629 start_index = (tcam_pair_count * tcam_depth * 2); 3630 } 3631 } else { 3632 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3633 ipv6_128_dip_offset = 0; 3634 ipv6_128_depth = 0; 3635 } 3636 3637 } 3638 3639 SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit))) = ipv6_64_depth; 3640 3641 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3642 BCM_DEFIP_PAIR128_URPF_OFFSET(unit) = ipv6_128_dip_offset; 3643 BCM_DEFIP_PAIR128_IDX_MAX(unit) = ipv6_128_depth - 1; 3644 BCM_DEFIP_PAIR128_TOTAL(unit) = ipv6_128_depth; 3645 } 3646 3647 SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index; 3648 SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit))) = start_index-1; 3649 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_0r(unit, defip_key_sel_0)); 3650 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_1r(unit, defip_key_sel_1)); 3651 3652 return BCM_E_NONE; 3653 } 3654 /* 3655 * Function: 3656 * _bcm_hx4_l3_defip_urpf_enable 3657 * Purpose: 3658 * Configure HX4 internal route table for URPF mode 3659 * Parameters: 3660 * unit - (IN)SOC unit number. 3661 * enable - (IN)Enable/disable URPF. 3662 * Returns: 3663 * BCM_E_XXX 3664 */ 3665 STATIC int 3666 _bcm_hx4_l3_defip_urpf_enable(int unit, int enable) 3667 { 3668 int defip_config; 3669 int ipv6_64_depth = 0; 3670 int ipv6_128_depth = 0; 3671 int ipv6_128_dip_offset = 0; 3672 uint32 defip_key_sel_0 = 0; 3673 uint32 defip_key_sel_1 = 0; 3674 uint32 num_ipv6_128b_entries = 0; 3675 int tcam_pair_count = 0; 3676 uint32 tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 3677 int tcam_idx = 0; 3678 int start_index = 0; 3679 3680 defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1); 3681 num_ipv6_128b_entries = SOC_L3_DEFIP_MAX_128B_ENTRIES(unit); 3682 3683 if (num_ipv6_128b_entries) { 3684 tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) + 3685 ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0); 3686 } else { 3687 tcam_pair_count = 0; 3688 } 3689 3690 if (tcam_pair_count > (SOC_CONTROL(unit)->l3_defip_max_tcams / 2)) { 3691 tcam_pair_count = (SOC_CONTROL(unit)->l3_defip_max_tcams / 2); 3692 } 3693 3694 if (enable) { 3695 3696 /* Ranger device does not support URPF */ 3697 defip_key_sel_1 = 0xF0; 3698 if (SOC_CONTROL(unit)->l3_defip_max_tcams == 4) { 3699 defip_key_sel_1 = 0xC; 3700 } 3701 3702 if (defip_config) { 3703 switch (tcam_pair_count) { 3704 case 0: 3705 ipv6_64_depth = 4 * tcam_depth; 3706 start_index = 0; 3707 break; 3708 3709 case 1: 3710 case 2: 3711 defip_key_sel_0 = 0x5; /* 0x0101 */ 3712 3713 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3714 ipv6_64_depth = 2 * tcam_depth; 3715 start_index = 2 * tcam_depth; 3716 3717 if (SOC_CONTROL(unit)->l3_defip_max_tcams == 4) { 3718 defip_key_sel_0 = 0x3; 3719 } 3720 } 3721 break; 3722 3723 case 3: 3724 case 4: 3725 default: 3726 defip_key_sel_0 = 0xF; /* 0x1111 */ 3727 3728 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3729 ipv6_64_depth = 0; 3730 start_index = 4 * tcam_depth; 3731 } 3732 break; 3733 } 3734 3735 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3736 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm) / 2; 3737 ipv6_128_dip_offset = num_ipv6_128b_entries / 2; 3738 ipv6_128_depth = num_ipv6_128b_entries / 2; 3739 } 3740 } else { 3741 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm) / 2; 3742 ipv6_128_dip_offset = 0; 3743 ipv6_128_depth = 0; 3744 } 3745 } else { /* Disable uRPF */ 3746 if (defip_config) { 3747 for (tcam_idx = 0; tcam_idx < tcam_pair_count; tcam_idx++) { 3748 defip_key_sel_0 |= (0x01 << tcam_idx); 3749 } 3750 3751 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3752 ipv6_128_dip_offset = num_ipv6_128b_entries; 3753 ipv6_128_depth = num_ipv6_128b_entries; 3754 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3755 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2); 3756 start_index = (tcam_pair_count * tcam_depth * 2); 3757 } 3758 } else { 3759 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3760 ipv6_128_dip_offset = 0; 3761 ipv6_128_depth = 0; 3762 } 3763 3764 } 3765 3766 SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit))) = ipv6_64_depth; 3767 3768 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3769 BCM_DEFIP_PAIR128_URPF_OFFSET(unit) = ipv6_128_dip_offset; 3770 BCM_DEFIP_PAIR128_IDX_MAX(unit) = ipv6_128_depth - 1; 3771 BCM_DEFIP_PAIR128_TOTAL(unit) = ipv6_128_depth; 3772 } 3773 3774 SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index; 3775 SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit))) = start_index-1; 3776 BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 3777 start_index)); 3778 3779 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_0r(unit, defip_key_sel_0)); 3780 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_1r(unit, defip_key_sel_1)); 3781 3782 return BCM_E_NONE; 3783 } 3784 3785 /* 3786 * Function: 3787 * _bcm_l3_expanded_defip_urpf_enable 3788 * Purpose: 3789 * Configure HX4 internal route table for URPF mode 3790 * Parameters: 3791 * unit - (IN)SOC unit number. 3792 * enable - (IN)Enable/disable URPF. 3793 * Returns: 3794 * BCM_E_XXX 3795 */ 3796 STATIC int 3797 _bcm_l3_expanded_defip_urpf_enable(int unit, int enable) 3798 { 3799 if (soc_feature(unit, soc_feature_l3_32k_defip_table)) { 3800 /* Firescout family - 16 tcams */ 3801 return _bcm_fs_l3_defip_urpf_enable(unit, enable); 3802 } else { 3803 /* Helix4 family - 8 tcams */ 3804 return _bcm_hx4_l3_defip_urpf_enable(unit, enable); 3805 } 3806 } 3807 3808 /* 3809 * Function: 3810 * _bcm_tr3_l3_defip_urpf_enable 3811 * Purpose: 3812 * Configure TR3 internal route table for URPF mode 3813 * Parameters: 3814 * unit - (IN)SOC unit number. 3815 * enable - (IN)Enable/disable URPF. 3816 * Returns: 3817 * BCM_E_XXX 3818 */ 3819 int 3820 _bcm_tr3_l3_defip_urpf_enable(int unit, int enable) 3821 { 3822 int defip_config; 3823 uint32 defip_key_sel_val = 0; 3824 int ipv6_64_depth = 0; 3825 int ipv6_128_dip_offset = 0, ipv6_128_depth = 0; 3826 int num_ipv6_128b_entries; 3827 int tcam_pair_count = 0; 3828 int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit); 3829 int start_index = 0; 3830 3831 if (soc_feature(unit, soc_feature_l3_expanded_defip_table)) {/* HX4 */ 3832 return _bcm_l3_expanded_defip_urpf_enable(unit, enable); 3833 } 3834 3835 defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1); 3836 num_ipv6_128b_entries = SOC_L3_DEFIP_MAX_128B_ENTRIES(unit); 3837 3838 if (num_ipv6_128b_entries) { 3839 tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) + 3840 ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0); 3841 } else { 3842 tcam_pair_count = 0; 3843 } 3844 3845 if (enable) { 3846 if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) {/*Apollo2*/ 3847 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3848 URPF_LOOKUP_CAM3f, 0x1); 3849 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3850 URPF_LOOKUP_CAM4f, 0x1); 3851 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3852 URPF_LOOKUP_CAM5f, 0x1); 3853 3854 if (defip_config) { 3855 switch (tcam_pair_count) { 3856 case 0: 3857 ipv6_64_depth = 3 * _BCM_TR3_DEFIP_TCAM_DEPTH; 3858 ipv6_128_depth = 0; 3859 ipv6_128_dip_offset = 0; 3860 break; 3861 3862 default: 3863 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3864 V6_KEY_SEL_CAM0_1f, 0x1); 3865 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3866 V6_KEY_SEL_CAM4_5f, 0x1); 3867 ipv6_128_dip_offset = num_ipv6_128b_entries / 2; 3868 ipv6_128_depth = num_ipv6_128b_entries / 2; 3869 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm) / 2; 3870 break; 3871 } 3872 } else { 3873 ipv6_64_depth = 3 * _BCM_TR3_DEFIP_TCAM_DEPTH; 3874 ipv6_128_dip_offset = 0; 3875 ipv6_128_depth = 0; 3876 } 3877 } else { /* TR3 */ 3878 /* All CAMs in URPF mode */ 3879 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3880 URPF_LOOKUP_CAM4f, 0x1); 3881 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3882 URPF_LOOKUP_CAM5f, 0x1); 3883 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3884 URPF_LOOKUP_CAM6f, 0x1); 3885 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3886 URPF_LOOKUP_CAM7f, 0x1); 3887 3888 switch (tcam_pair_count) { 3889 case 0: 3890 /* No pairing of tcams */ 3891 ipv6_64_depth = 4 * tcam_depth; 3892 break; 3893 3894 case 1: 3895 case 2: 3896 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3897 V6_KEY_SEL_CAM0_1f, 0x1); 3898 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3899 V6_KEY_SEL_CAM4_5f, 0x1); 3900 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3901 ipv6_64_depth = 2 * tcam_depth; 3902 start_index = 2 * tcam_depth; 3903 } 3904 break; 3905 3906 case 3: 3907 case 4: 3908 default: 3909 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3910 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3911 0x1); 3912 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3913 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3914 0x1); 3915 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3916 &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 3917 0x1); 3918 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3919 &defip_key_sel_val, V6_KEY_SEL_CAM6_7f, 3920 0x1); 3921 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3922 ipv6_64_depth = 0; 3923 start_index = 4 * tcam_depth; 3924 } 3925 3926 break; 3927 } 3928 3929 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 3930 ipv6_128_dip_offset = num_ipv6_128b_entries / 2; 3931 ipv6_128_depth = num_ipv6_128b_entries / 2; 3932 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm) / 2; 3933 } 3934 } 3935 } else { /* Disable urpf */ 3936 defip_key_sel_val = 0; /* reset */ 3937 if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) {/*Apollo2*/ 3938 if (defip_config) { 3939 switch (tcam_pair_count) { 3940 case 0: 3941 break; 3942 3943 case 1: 3944 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3945 V6_KEY_SEL_CAM0_1f, 0x1); 3946 break; 3947 3948 case 2: 3949 3950 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3951 V6_KEY_SEL_CAM0_1f, 0x1); 3952 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3953 V6_KEY_SEL_CAM2_3f, 0x1); 3954 break; 3955 3956 case 3: 3957 default: 3958 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3959 V6_KEY_SEL_CAM0_1f, 0x1); 3960 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3961 V6_KEY_SEL_CAM2_3f, 0x1); 3962 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 3963 V6_KEY_SEL_CAM4_5f, 0x1); 3964 } 3965 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 3966 ipv6_128_dip_offset = 0; 3967 ipv6_128_depth = num_ipv6_128b_entries; 3968 } else { 3969 ipv6_64_depth = 6 * _BCM_TR3_DEFIP_TCAM_DEPTH; 3970 ipv6_128_dip_offset = 0; 3971 ipv6_128_depth = 0; 3972 } 3973 } else { 3974 switch (tcam_pair_count) { 3975 case 1: 3976 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3977 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3978 0x1); 3979 break; 3980 3981 case 2: 3982 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3983 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3984 0x1); 3985 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3986 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3987 0x1); 3988 break; 3989 3990 case 3: 3991 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3992 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 3993 0x1); 3994 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3995 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 3996 0x1); 3997 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 3998 &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 3999 0x1); 4000 break; 4001 4002 case 4: 4003 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 4004 &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 4005 0x1); 4006 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 4007 &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 4008 0x1); 4009 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 4010 &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 4011 0x1); 4012 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 4013 &defip_key_sel_val, V6_KEY_SEL_CAM6_7f, 4014 0x1); 4015 break; 4016 4017 default: 4018 break; 4019 } 4020 4021 ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm); 4022 ipv6_128_dip_offset = 0; 4023 ipv6_128_depth = num_ipv6_128b_entries; 4024 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 4025 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2); 4026 start_index = (tcam_pair_count * tcam_depth * 2); 4027 } 4028 } 4029 } 4030 4031 if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 4032 if (BCM_DEFIP_PAIR128_INIT_CHECK(unit)) { 4033 BCM_DEFIP_PAIR128_URPF_OFFSET(unit) = ipv6_128_dip_offset; 4034 BCM_DEFIP_PAIR128_IDX_MAX(unit) = ipv6_128_depth - 1; 4035 BCM_DEFIP_PAIR128_TOTAL(unit) = ipv6_128_depth; 4036 } 4037 } 4038 4039 if (SOC_LPM_INIT_CHECK(unit)) { 4040 SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit))) = ipv6_64_depth; 4041 SOC_LPM_STATE_START(unit, MAX_PFX_INDEX(unit)) = start_index; 4042 SOC_LPM_STATE_END(unit, MAX_PFX_INDEX(unit)) = start_index - 1; 4043 BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 4044 start_index)); 4045 } 4046 4047 BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SELr(unit, defip_key_sel_val)); 4048 SOC_IF_ERROR_RETURN(soc_fb_lpm_stat_init(unit)); 4049 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) { 4050 SOC_IF_ERROR_RETURN(soc_fb_lpm128_stat_init(unit)); 4051 } 4052 return BCM_E_NONE; 4053 } 4054 4055 /* 4056 * Function: 4057 * _bcm_tr3_mtu_profile_index_get 4058 * Purpose: 4059 * Get TR3 L3 interface MTU profile table index 4060 * given the MTU value to set. 4061 * Parameters: 4062 * unit - (IN)SOC unit number. 4063 * mtu - (IN)MTU value to set. 4064 * index - (OUT)MTU profile index. 4065 * Returns: 4066 * BCM_E_XXX 4067 */ 4068 int 4069 _bcm_tr3_mtu_profile_index_get(int unit, uint32 mtu, uint32 *index) 4070 { 4071 ing_l3_next_hop_attribute_1_entry_t mtu_value_buf; 4072 uint32 *mtu_value_buf_p; /* Attribute table buff address */ 4073 void *null_entry = soc_mem_entry_null(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m); 4074 void *entries[1]; 4075 4076 if (NULL == index) { 4077 return BCM_E_PARAM; 4078 } 4079 4080 /* Reset the buffer to default value. */ 4081 mtu_value_buf_p = (uint32 *)&mtu_value_buf; 4082 sal_memcpy(mtu_value_buf_p, null_entry, 4083 sizeof(ing_l3_next_hop_attribute_1_entry_t)); 4084 4085 soc_mem_field32_set(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m, 4086 mtu_value_buf_p, MTU_SIZEf, mtu); 4087 4088 entries[0] = mtu_value_buf_p; 4089 BCM_IF_ERROR_RETURN(_bcm_ing_l3_nh_attrib_entry_add(unit, entries, 1, 4090 (uint32 *)index)); 4091 return BCM_E_NONE; 4092 } 4093 4094 /* 4095 * Function: 4096 * _bcm_tr3_l3_intf_mtu_get 4097 * Purpose: 4098 * Get TR3 L3 interface MTU value. 4099 * Parameters: 4100 * unit - (IN)SOC unit number. 4101 * intf_info - (IN)Interface information. 4102 * Returns: 4103 * BCM_E_XXX 4104 */ 4105 int 4106 _bcm_tr3_l3_intf_mtu_get(int unit, _bcm_l3_intf_cfg_t *intf_info) 4107 { 4108 /* Buffer for mtu idx */ 4109 ing_l3_next_hop_attribute_1_index_entry_t mtu_idx_value_buf; 4110 /* Buffer for mtu profile table entry */ 4111 ing_l3_next_hop_attribute_1_entry_t mtu_value_buf; 4112 uint32 *mtu_idx_value_buf_p; /* Write buffer address */ 4113 uint32 *mtu_value_buf_p; /* Write buffer address */ 4114 int mtu_index, mtu_profile_index; 4115 int interface_map_mode = 0; 4116 4117 /* Input parameters check */ 4118 if (NULL == intf_info) { 4119 return (BCM_E_PARAM); 4120 } 4121 4122 /* Zero the buffer. */ 4123 mtu_idx_value_buf_p = (uint32 *)&mtu_idx_value_buf; 4124 sal_memset(mtu_idx_value_buf_p, 0, sizeof(ing_l3_next_hop_attribute_1_index_entry_t)); 4125 4126 mtu_value_buf_p = (uint32 *)&mtu_value_buf; 4127 sal_memset(mtu_value_buf_p, 0, sizeof(ing_l3_next_hop_attribute_1_entry_t)); 4128 4129 if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) { 4130 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 4131 BCM_IF_ERROR_RETURN( 4132 bcm_xgs3_l3_ingress_intf_map_get(unit, &interface_map_mode)); 4133 } 4134 if (!interface_map_mode) { 4135 mtu_index = intf_info->l3i_vid; 4136 } else { 4137 mtu_index = intf_info->l3i_index; 4138 } 4139 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 4140 ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm, 4141 mtu_index, mtu_idx_value_buf_p)); 4142 } else { 4143 /* Read mtu table entry by index. */ 4144 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 4145 ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm, 4146 intf_info->l3i_index, 4147 mtu_idx_value_buf_p)); 4148 } 4149 mtu_profile_index = 4150 soc_mem_field32_get(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm, 4151 mtu_idx_value_buf_p, INDEXf); 4152 4153 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m, 4154 mtu_profile_index, mtu_value_buf_p)); 4155 intf_info->l3i_mtu = 4156 soc_mem_field32_get(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m, 4157 mtu_value_buf_p, MTU_SIZEf); 4158 4159 return BCM_E_NONE; 4160 } 4161 4162 /* 4163 * Function: 4164 * _bcm_tr3_l3_intf_mtu_set 4165 * Purpose: 4166 * Set TR3 L3 interface MTU value. 4167 * Parameters: 4168 * unit - (IN)SOC unit number. 4169 * intf_info - (IN)Interface information. 4170 * Returns: 4171 * BCM_E_XXX 4172 */ 4173 int 4174 _bcm_tr3_l3_intf_mtu_set(int unit, _bcm_l3_intf_cfg_t *intf_info) 4175 { 4176 /* Buffer for mtu idx */ 4177 ing_l3_next_hop_attribute_1_index_entry_t mtu_idx_value_buf; 4178 void *null_idx_entry = 4179 soc_mem_entry_null(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm); 4180 int mtu_index, mtu_profile_index, interface_map_mode = 0; 4181 uint32 mtu = _BCM_TR3_L3_DEFAULT_MTU_SIZE; /* Default mtu size */ 4182 4183 /* Input parameters check */ 4184 if (NULL == intf_info) { 4185 return (BCM_E_PARAM); 4186 } 4187 4188 /* coverity[dead_error_begin : FALSE] */ 4189 if(!SOC_MEM_FIELD32_VALUE_FIT(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m, 4190 MTU_SIZEf, intf_info->l3i_mtu)) { 4191 return (BCM_E_PARAM); 4192 } 4193 4194 /* Set mtu. */ 4195 if (intf_info->l3i_mtu) { 4196 mtu = intf_info->l3i_mtu; 4197 } 4198 4199 /* Get mtu profile table index for the mtu */ 4200 BCM_IF_ERROR_RETURN( 4201 _bcm_tr3_mtu_profile_index_get(unit, mtu, 4202 (uint32 *)&mtu_profile_index)); 4203 4204 sal_memcpy(&mtu_idx_value_buf, null_idx_entry, 4205 sizeof(ing_l3_next_hop_attribute_1_index_entry_t)); 4206 soc_mem_field32_set(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm, 4207 &mtu_idx_value_buf, INDEXf, mtu_profile_index); 4208 if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) { 4209 if (soc_feature(unit, soc_feature_l3_ingress_interface)) { 4210 BCM_IF_ERROR_RETURN( 4211 bcm_xgs3_l3_ingress_intf_map_get(unit, &interface_map_mode)); 4212 } 4213 if (!interface_map_mode) { 4214 mtu_index = intf_info->l3i_vid; 4215 } else { 4216 mtu_index = intf_info->l3i_index; 4217 } 4218 WRITE_ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm(unit, MEM_BLOCK_ALL, 4219 mtu_index, &mtu_idx_value_buf); 4220 } else { 4221 WRITE_ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm(unit, MEM_BLOCK_ALL, 4222 intf_info->l3i_index, 4223 &mtu_idx_value_buf); 4224 } 4225 return BCM_E_NONE; 4226 } 4227 4228 /* 4229 * Function: 4230 * _bcm_tr3_l3_ecmp_grp_get 4231 * Purpose: 4232 * Get ecmp group next hop members by index. 4233 * Parameters: 4234 * unit - (IN) SOC unit number. 4235 * ecmp_grp - (IN) Ecmp group id to read. 4236 * ecmp_count - (IN) Maximum number of entries to read. 4237 * nh_idx - (OUT) Next hop indexes. 4238 * Returns: 4239 * BCM_E_XXX 4240 */ 4241 int 4242 _bcm_tr3_l3_ecmp_grp_get(int unit, int ecmp_grp, int ecmp_group_size, int *nh_idx) 4243 { 4244 int idx; 4245 void *ecmp_null_entry; 4246 void *ecmp_grp_null_entry; 4247 ecmp_entry_t ecmp_entry; 4248 ecmp_count_entry_t ecmp_grp_entry; 4249 int ecmp_idx, num_ecmp_entries; 4250 4251 /* Input parameters sanity check. */ 4252 if ((NULL == nh_idx) || (ecmp_group_size < 1)) { 4253 return (BCM_E_PARAM); 4254 } 4255 4256 ecmp_grp_null_entry = soc_mem_entry_null(unit, L3_ECMP_COUNTm); 4257 sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t)); 4258 4259 /* Read ECMP group table entry indexed by group ID */ 4260 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 4261 MEM_BLOCK_ANY, ecmp_grp, &ecmp_grp_entry)); 4262 4263 /* Base ptr & path count of the ECMP group in the ECMP entry table */ 4264 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTRf); 4265 num_ecmp_entries = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, COUNTf); 4266 num_ecmp_entries++; /* Count is zero based */ 4267 4268 sal_memset(nh_idx, 0, ecmp_group_size * sizeof(int)); 4269 ecmp_null_entry = soc_mem_entry_null(unit, L3_ECMPm); 4270 sal_memcpy(&ecmp_entry, ecmp_null_entry, sizeof(ecmp_entry_t)); 4271 4272 /* Read the NH index of each member of the ECMP group */ 4273 for (idx = 0; idx < num_ecmp_entries; idx++) { 4274 4275 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMPm, 4276 MEM_BLOCK_ANY, (ecmp_idx + idx), &ecmp_entry)); 4277 nh_idx[idx] = soc_mem_field32_get(unit, L3_ECMPm, 4278 &ecmp_entry, NEXT_HOP_INDEXf); 4279 } 4280 4281 return BCM_E_NONE; 4282 } 4283 4284 /* 4285 * Function: 4286 * _bcm_tr3_l3_ecmp_grp_add 4287 * Purpose: 4288 * Add ecmp group next hop members, or reset ecmp group entry. 4289 * NOTE: Function always writes all the entries in ecmp group. 4290 * If there is not enough nh indexes - next hops written 4291 * in cycle. 4292 * Parameters: 4293 * unit - (IN)SOC unit number. 4294 * ecmp_grp - (IN)ecmp group id to write. 4295 * buf - (IN)Next hop indexes or NULL for entry reset. 4296 * info - (IN)ECMP additional info 4297 * Returns: 4298 * BCM_E_XXX 4299 */ 4300 int 4301 _bcm_tr3_l3_ecmp_grp_add(int unit, int ecmp_grp, void *buf, void *info) 4302 { 4303 uint32 reg_val, value; 4304 _bcm_l3_tbl_op_t data; 4305 int *nh_idx = NULL; 4306 int nh_cycle_idx; 4307 int idx, ecmp_idx, entry_type; 4308 void *ecmp_null_entry, *initial_ecmp_null_entry; 4309 void *ecmp_grp_null_entry, *initial_ecmp_grp_null_entry; 4310 ecmp_entry_t ecmp_entry; 4311 ing_l3_next_hop_entry_t ing_nh; 4312 ecmp_count_entry_t ecmp_grp_entry; 4313 initial_l3_ecmp_entry_t initial_ecmp_entry; 4314 initial_l3_ecmp_group_entry_t initial_ecmp_grp_entry; 4315 int l3_ecmp_oif_flds[8] = { L3_OIF_0f, L3_OIF_1f, L3_OIF_2f, L3_OIF_3f, 4316 L3_OIF_4f, L3_OIF_5f, L3_OIF_6f, L3_OIF_7f }; 4317 int l3_ecmp_oif_type_flds[8] = { L3_OIF_0_TYPEf, L3_OIF_1_TYPEf, 4318 L3_OIF_2_TYPEf, L3_OIF_3_TYPEf, L3_OIF_4_TYPEf, 4319 L3_OIF_5_TYPEf, L3_OIF_6_TYPEf, L3_OIF_7_TYPEf }; 4320 ecmp_count_entry_t old_ecmp_count_entry; 4321 int dlb_id, group_enable; 4322 int rv; 4323 int ecmp_table_incr = 0; 4324 _bcm_l3_ecmp_group_info_t *ecmp_info = info; 4325 _bcm_l3_ecmp_group_buffer_t *ecmp_buffer = buf; 4326 4327 if (NULL == ecmp_buffer || NULL == ecmp_info || 4328 NULL == ecmp_buffer->group_buffer) { 4329 return (BCM_E_PARAM); 4330 } 4331 4332 nh_idx = ecmp_buffer->group_buffer; 4333 4334 /* Null ECMP and ECMP group table entries */ 4335 ecmp_null_entry = soc_mem_entry_null(unit, L3_ECMPm); 4336 ecmp_grp_null_entry = soc_mem_entry_null(unit, L3_ECMP_COUNTm); 4337 initial_ecmp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMPm); 4338 initial_ecmp_grp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMP_GROUPm); 4339 sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t)); 4340 sal_memcpy(&initial_ecmp_grp_entry, initial_ecmp_grp_null_entry, 4341 sizeof(initial_l3_ecmp_group_entry_t)); 4342 4343 if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 4344 ecmp_grp), ecmp_grp)) { 4345 /* Group has already exists, get base ptr from group table */ 4346 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 4347 MEM_BLOCK_ANY, ecmp_grp, &ecmp_grp_entry)); 4348 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 4349 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTRf); 4350 } else { 4351 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTR_0f); 4352 } 4353 } else { 4354 /* Get index to the first slot in the ECMP table 4355 * that can accomodate max_paths */ 4356 data.width = ecmp_info->max_paths; 4357 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 4358 data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 4359 data.entry_index = -1; 4360 4361 rv = _bcm_xgs3_tbl_free_idx_get(unit, &data); 4362 4363 if (BCM_E_FULL == rv) { 4364 /* Defragment ECMP table */ 4365 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0)); 4366 4367 /* Attempt to get free index again */ 4368 BCM_IF_ERROR_RETURN (_bcm_xgs3_tbl_free_idx_get(unit, &data)); 4369 4370 } else if (BCM_FAILURE(rv)) { 4371 return rv; 4372 } 4373 4374 ecmp_idx = data.entry_index; 4375 BCM_XGS3_L3_ENT_REF_CNT_INC(data.tbl_ptr, ecmp_idx, ecmp_info->max_paths); 4376 ecmp_table_incr = 1; 4377 } 4378 4379 sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t)); 4380 4381 for (idx = 0, nh_cycle_idx = 0; idx < ecmp_info->max_paths; idx++, nh_cycle_idx++) { 4382 sal_memcpy(&ecmp_entry, ecmp_null_entry, sizeof(ecmp_entry_t)); 4383 sal_memcpy(&initial_ecmp_entry, initial_ecmp_null_entry, 4384 sizeof(initial_l3_ecmp_entry_t)); 4385 4386 /* If this is the last nhop then program black-hole. */ 4387 if ( (!idx) && (!nh_idx[nh_cycle_idx]) ) { 4388 nh_cycle_idx = 0; 4389 } else if (!nh_idx[nh_cycle_idx]) { 4390 break; 4391 } 4392 4393 /* Write NHs to ECMP entry table */ 4394 soc_mem_field32_set(unit, L3_ECMPm, &ecmp_entry, 4395 NEXT_HOP_INDEXf, nh_idx[nh_cycle_idx]); 4396 rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 4397 (ecmp_idx + idx), &ecmp_entry); 4398 if (BCM_FAILURE(rv)) { 4399 if (ecmp_table_incr == 1) { 4400 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 4401 ecmp_idx, ecmp_info->max_paths); 4402 } 4403 return rv; 4404 } 4405 4406 /* Write NHs to initial ECMP entry table */ 4407 soc_mem_field32_set(unit, INITIAL_L3_ECMPm, &initial_ecmp_entry, 4408 NEXT_HOP_INDEXf, nh_idx[idx]); 4409 rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 4410 (ecmp_idx + idx), &initial_ecmp_entry); 4411 if (BCM_FAILURE(rv)) { 4412 if (ecmp_table_incr == 1) { 4413 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 4414 ecmp_idx, ecmp_info->max_paths); 4415 } 4416 return rv; 4417 } 4418 4419 if (soc_feature(unit, soc_feature_urpf)) { 4420 /* Check if URPF is enabled on device */ 4421 BCM_IF_ERROR_RETURN( 4422 READ_L3_DEFIP_RPF_CONTROLr(unit, ®_val)); 4423 if (reg_val) { 4424 if (idx < 8) { 4425 BCM_IF_ERROR_RETURN (soc_mem_read(unit, 4426 ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 4427 nh_idx[idx], &ing_nh)); 4428 4429 entry_type = 4430 soc_ING_L3_NEXT_HOPm_field32_get(unit, 4431 &ing_nh, ENTRY_TYPEf); 4432 4433 if (entry_type == 0x0) { 4434 /* 4435 * if l3_oif is valid then read it than vlan. 4436 * vlan and l3_oifs are overlaid fields. 4437 */ 4438 if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, 4439 L3_OIFf)) { 4440 value = soc_ING_L3_NEXT_HOPm_field32_get( 4441 unit, &ing_nh, L3_OIFf); 4442 } else { 4443 value = soc_ING_L3_NEXT_HOPm_field32_get( 4444 unit, &ing_nh, VLAN_IDf); 4445 } 4446 4447 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 4448 l3_ecmp_oif_type_flds[idx], entry_type); 4449 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 4450 l3_ecmp_oif_flds[idx], value); 4451 } else if (entry_type == 0x1) { 4452 value = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, L3_OIFf); 4453 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 4454 l3_ecmp_oif_type_flds[idx], entry_type); 4455 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 4456 l3_ecmp_oif_flds[idx], value); 4457 } 4458 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, URPF_COUNTf, idx); 4459 }else { 4460 /* Inorder to avoid TRAP_TO_CPU, urpf_mode on L3_IIF/PORT must be set 4461 to STRICT_MODE / LOOSE_MODE */ 4462 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, ECMP_GT8f , 1); 4463 } 4464 } 4465 } 4466 } 4467 4468 /* Write ECMP group count and base index to group table entry 4469 * indexed by group index */ 4470 if (!idx) { 4471 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, COUNTf, idx); 4472 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 4473 &initial_ecmp_grp_entry, COUNTf, idx); 4474 } else { 4475 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, COUNTf, idx-1); 4476 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 4477 &initial_ecmp_grp_entry, COUNTf, idx-1); 4478 } 4479 soc_mem_field32_set(unit, L3_ECMP_COUNTm, 4480 &ecmp_grp_entry, BASE_PTRf, ecmp_idx); 4481 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm, 4482 &initial_ecmp_grp_entry, BASE_PTRf, ecmp_idx); 4483 4484 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 4485 /* Preserve the old values of ECMP DLB related fields */ 4486 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, 4487 ecmp_grp, &old_ecmp_count_entry)); 4488 dlb_id = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &old_ecmp_count_entry, 4489 DLB_IDf); 4490 group_enable = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 4491 &old_ecmp_count_entry, GROUP_ENABLEf); 4492 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, DLB_IDf, 4493 dlb_id); 4494 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, GROUP_ENABLEf, 4495 group_enable); 4496 } 4497 4498 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 4499 ecmp_grp, &ecmp_grp_entry); 4500 if (BCM_FAILURE(rv)) { 4501 if (ecmp_table_incr == 1) { 4502 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 4503 ecmp_idx, ecmp_info->max_paths); 4504 } 4505 return rv; 4506 } 4507 4508 rv = soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL, 4509 ecmp_grp, &initial_ecmp_grp_entry); 4510 4511 if (BCM_FAILURE(rv)) { 4512 if (ecmp_table_incr == 1) { 4513 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 4514 ecmp_idx, ecmp_info->max_paths); 4515 } 4516 return rv; 4517 } 4518 4519 /* Save the max possible paths for this ECMP group in s/w */ 4520 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = ecmp_info->max_paths; 4521 4522 return BCM_E_NONE; 4523 } 4524 4525 /* 4526 * Function: 4527 * _bcm_tr3_l3_ecmp_grp_del 4528 * Purpose: 4529 * Reset ecmp group next hop members 4530 * Parameters: 4531 * unit - (IN)SOC unit number. 4532 * ecmp_grp - (IN)ecmp group id to write. 4533 * info - (IN)ECMP additional info 4534 * Returns: 4535 * BCM_E_XXX 4536 */ 4537 int 4538 _bcm_tr3_l3_ecmp_grp_del(int unit, int ecmp_grp, void *info) 4539 { 4540 int idx, ecmp_idx; 4541 _bcm_l3_tbl_op_t data; 4542 void *ecmp_null_entry, *initial_ecmp_null_entry; 4543 void *ecmp_grp_null_entry, *initial_ecmp_grp_null_entry; 4544 ecmp_entry_t ecmp_entry; 4545 ecmp_count_entry_t ecmp_grp_entry; 4546 initial_l3_ecmp_entry_t initial_ecmp_entry; 4547 initial_l3_ecmp_group_entry_t initial_ecmp_grp_entry; 4548 ecmp_count_entry_t old_ecmp_count_entry; 4549 int dlb_id, group_enable; 4550 4551 if (NULL == info) { 4552 return BCM_E_INTERNAL; 4553 } 4554 4555 /* Null ECMP and ECMP group table entries */ 4556 ecmp_null_entry = soc_mem_entry_null(unit, L3_ECMPm); 4557 ecmp_grp_null_entry = soc_mem_entry_null(unit, L3_ECMP_COUNTm); 4558 initial_ecmp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMPm); 4559 initial_ecmp_grp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMP_GROUPm); 4560 sal_memcpy(&ecmp_entry, ecmp_null_entry, sizeof(ecmp_entry_t)); 4561 sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t)); 4562 sal_memcpy(&initial_ecmp_entry, initial_ecmp_null_entry, 4563 sizeof(initial_l3_ecmp_entry_t)); 4564 sal_memcpy(&initial_ecmp_grp_entry, initial_ecmp_grp_null_entry, 4565 sizeof(initial_l3_ecmp_group_entry_t)); 4566 4567 /* Get the base entry index of the group */ 4568 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 4569 MEM_BLOCK_ANY, ecmp_grp, &ecmp_grp_entry)); 4570 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTRf); 4571 4572 /* Write null entries in the ECMP entry tables per group member 4573 * starting from the base group entry */ 4574 for (idx = 0; idx < ((_bcm_l3_ecmp_group_info_t*)info)->max_paths; idx++) { 4575 /* ECMP entry table */ 4576 BCM_IF_ERROR_RETURN(soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 4577 (ecmp_idx + idx), &ecmp_entry)); 4578 /* Initial ECMP entry table */ 4579 BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 4580 (ecmp_idx + idx), &initial_ecmp_entry)); 4581 } 4582 4583 /* Decrement ref count for the entries in ecmp table 4584 * Ref count for ecmp_group table is decremented in common table del func. */ 4585 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 4586 BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, ecmp_idx, 4587 ((_bcm_l3_ecmp_group_info_t*)info)->max_paths); 4588 4589 /* Reset group entry */ 4590 sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t)); 4591 4592 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 4593 /* Preserve the old values of ECMP DLB related fields */ 4594 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, 4595 ecmp_grp, &old_ecmp_count_entry)); 4596 dlb_id = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &old_ecmp_count_entry, 4597 DLB_IDf); 4598 group_enable = soc_mem_field32_get(unit, L3_ECMP_COUNTm, 4599 &old_ecmp_count_entry, GROUP_ENABLEf); 4600 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, DLB_IDf, 4601 dlb_id); 4602 soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, GROUP_ENABLEf, 4603 group_enable); 4604 } 4605 4606 /* Write null entries in the ECMP group tables indexed by group id */ 4607 BCM_IF_ERROR_RETURN(soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 4608 ecmp_grp, &ecmp_grp_entry)); 4609 BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL, 4610 ecmp_grp, &initial_ecmp_grp_entry)); 4611 4612 /* Reset the max paths of the deleted group */ 4613 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = 0; 4614 4615 return BCM_E_NONE; 4616 } 4617 4618 /* 4619 * Function: 4620 * _bcm_tr3_l3_tnl_term_add 4621 * Purpose: 4622 * Add tunnel termination entry to the hw. 4623 * Parameters: 4624 * unit - (IN) BCM device number. 4625 * tnl_info - (IN) Tunnel terminator parameters. 4626 * Returns: 4627 * BCM_E_XXX 4628 */ 4629 int 4630 _bcm_tr3_l3_tnl_term_add(int unit, uint32 *entry_ptr, bcm_tunnel_terminator_t *tnl_info) 4631 { 4632 bcm_module_t mod_in, mod_out, my_mod; 4633 bcm_port_t port_in, port_out; 4634 _bcm_l3_ingress_intf_t iif; 4635 int tunnel, wlan; 4636 int rv; 4637 4638 /* Program remote port */ 4639 if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 4640 (tnl_info->type == bcmTunnelTypeWlanAcToAc) || 4641 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) || 4642 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 4643 wlan = 1; 4644 } else { 4645 wlan = 0; 4646 } 4647 if (wlan) { 4648 if (tnl_info->flags & BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE) { 4649 if (!BCM_GPORT_IS_MODPORT(tnl_info->remote_port)) { 4650 return BCM_E_PARAM; 4651 } 4652 mod_in = BCM_GPORT_MODPORT_MODID_GET(tnl_info->remote_port); 4653 port_in = BCM_GPORT_MODPORT_PORT_GET(tnl_info->remote_port); 4654 BCM_IF_ERROR_RETURN 4655 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 4656 port_in, &mod_out, &port_out)); 4657 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 4658 return (BCM_E_BADID); 4659 } 4660 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 4661 return (BCM_E_PORT); 4662 } 4663 soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf, 4664 (mod_out << 6) | port_out); 4665 } else { 4666 /* Send to the local loopback port */ 4667 rv = bcm_esw_stk_my_modid_get(unit, &my_mod); 4668 BCM_IF_ERROR_RETURN(rv); 4669 port_in = AXP_PORT(unit,SOC_AXP_NLF_WLAN_DECAP); 4670 mod_in = my_mod; 4671 rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 4672 port_in, &mod_out, &port_out); 4673 BCM_IF_ERROR_RETURN(rv); 4674 4675 soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf, 4676 (mod_out << 6) | port_out); 4677 /* Locally Terminated */ 4678 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 4679 LOCAL_TUNNEL_TERMINATIONf, 1 ); 4680 } 4681 /* Program tunnel id */ 4682 if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) { 4683 if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) { 4684 return BCM_E_PARAM; 4685 } 4686 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) { 4687 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id); 4688 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf, 4689 tunnel); 4690 } 4691 } 4692 4693 /* Program HA/FA for Ac2Ac tunnels */ 4694 if (((tnl_info->type == bcmTunnelTypeWlanAcToAc) || 4695 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) && 4696 (tnl_info->flags & BCM_TUNNEL_TERM_WLAN_SET_ROAM)) { 4697 _bcm_tr3_wlan_tunnel_set_roam(unit, tnl_info->tunnel_id); 4698 } 4699 } 4700 if ((tnl_info->type == bcmTunnelTypeAutoMulticast) || 4701 (tnl_info->type == bcmTunnelTypeAutoMulticast6)) { 4702 /* Program L3_IIFm */ 4703 if(SOC_MEM_FIELD_VALID(unit, L3_IIFm, IPMC_L3_IIFf)) { 4704 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 4705 iif.intf_id = tnl_info->vlan; 4706 4707 rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 4708 BCM_IF_ERROR_RETURN(rv); 4709 iif.vrf = tnl_info->vrf; 4710 rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL); 4711 BCM_IF_ERROR_RETURN(rv); 4712 } 4713 4714 /* Program tunnel id */ 4715 if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) { 4716 if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) { 4717 return BCM_E_PARAM; 4718 } 4719 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) { 4720 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id); 4721 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf, 4722 tunnel); 4723 } 4724 } 4725 } 4726 return (BCM_E_NONE); 4727 } 4728 4729 /* 4730 * Function: 4731 * _bcm_tr3_nh_update_match 4732 * Purpose: 4733 * Update/Show/Delete all entries in nh table matching a certain rule. 4734 * Parameters: 4735 * unit - (IN)SOC unit number. 4736 * trv_data - (IN)Delete pattern + compare,act,notify routines. 4737 * Returns: 4738 * BCM_E_XXX 4739 */ 4740 int 4741 _bcm_tr3_nh_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 4742 { 4743 bcm_l3_egress_t nh_entry; /* Next hop entry info. */ 4744 uint32 *ing_entry_ptr; /* Ingress next hop entry pointer.*/ 4745 char *ing_tbl_ptr; /* Dma table pointer. */ 4746 int cmp_result; /* Test routine result. */ 4747 soc_mem_t mem; /* Next hop memory. */ 4748 soc_mem_t mem_egr_nh; /* Next hop memory. */ 4749 int idx; /* Iteration index. */ 4750 char *egr_tbl_buf; /* Dma egress nh table pointer. */ 4751 uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pinter. */ 4752 int rv = BCM_E_NONE; /* Operation return status. */ 4753 int table_ent_size; /* Table entry size. */ 4754 int idx_min, idx_max, chunk_size, num_chunks, chunk_index; 4755 int entry_type; 4756 4757 /* Get next table memory. */ 4758 mem = BCM_XGS3_L3_MEM(unit, nh); 4759 mem_egr_nh = EGR_L3_NEXT_HOPm; 4760 4761 /* Table DMA the nhtable to software copy */ 4762 BCM_IF_ERROR_RETURN 4763 (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl", 4764 &ing_tbl_ptr, NULL)); 4765 4766 chunk_size = 1024; 4767 table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem_egr_nh); 4768 num_chunks = soc_mem_index_count(unit, mem_egr_nh) / chunk_size; 4769 if (soc_mem_index_count(unit, mem_egr_nh) % chunk_size) { 4770 num_chunks++; 4771 } 4772 4773 egr_tbl_buf = soc_cm_salloc(unit, table_ent_size * chunk_size, 4774 "egr_tbl_chunk buffer"); 4775 if (NULL == egr_tbl_buf) { 4776 rv = BCM_E_MEMORY; 4777 goto cleanup; 4778 } 4779 4780 for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) { 4781 idx_min = chunk_index * chunk_size; 4782 idx_max = idx_min + chunk_size - 1; 4783 if (idx_max > soc_mem_index_max(unit, mem_egr_nh)) { 4784 idx_max = soc_mem_index_max(unit, mem_egr_nh); 4785 } 4786 4787 /* Reset allocated buffer. */ 4788 sal_memset(egr_tbl_buf, 0, (table_ent_size * chunk_size)); 4789 4790 rv = soc_mem_read_range(unit, mem_egr_nh, MEM_BLOCK_ANY, 4791 idx_min, idx_max, egr_tbl_buf); 4792 if (SOC_FAILURE(rv)) { 4793 goto cleanup; 4794 } 4795 4796 /* Iterate over all the entries - show matching ones. */ 4797 for (idx = idx_min; idx <= idx_max; idx++) { 4798 /* Skip unused entries. */ 4799 if (!BCM_XGS3_L3_ENT_REF_CNT (BCM_XGS3_L3_TBL_PTR(unit, 4800 next_hop), idx)) { 4801 continue; 4802 } 4803 4804 /* Skip trap to CPU entry internally installed entry. */ 4805 if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) { 4806 continue; 4807 } 4808 4809 /* Skip the internally installed BLACK_HOLE entry */ 4810 if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) == idx) { 4811 continue; 4812 } 4813 4814 /* Calculate entry ofset. */ 4815 ing_entry_ptr = 4816 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx); 4817 4818 /* Read egress next hop entry. */ 4819 egr_entry_ptr = 4820 soc_mem_table_idx_to_pointer(unit, mem_egr_nh, 4821 uint32 *, egr_tbl_buf, (idx % chunk_size)); 4822 entry_type = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 4823 egr_entry_ptr, ENTRY_TYPEf); 4824 if (entry_type == 0 || entry_type == 1 || entry_type == 7 || 4825 (entry_type == 4 && soc_feature(unit, soc_feature_wlan))) { 4826 /* Valid entry types for L3 egress object are L3UC, MPLS, 4827 * WLAN, and L3MC. 4828 */ 4829 } else { 4830 continue; 4831 } 4832 4833 /* coverity[var_deref_model : FALSE] */ 4834 _bcm_xgs3_nh_entry_parse(unit, ing_entry_ptr, egr_entry_ptr, NULL, idx, 4835 &nh_entry, NULL); 4836 4837 if (soc_feature(unit, soc_feature_ecmp_dlb)) { 4838 bcm_tr3_l3_egress_dlb_attr_get(unit, idx, &nh_entry); 4839 } 4840 4841 /* Execute operation routine if any. */ 4842 if (trv_data->op_cb) { 4843 rv = (*trv_data->op_cb)(unit, (void *)trv_data, 4844 (void *)&nh_entry,(void *)&idx, &cmp_result); 4845 if (rv < 0) { 4846 #ifdef BCM_CB_ABORT_ON_ERR 4847 if(SOC_CB_ABORT_ON_ERR(unit)) { 4848 break; 4849 } 4850 #endif 4851 } 4852 } 4853 } 4854 } 4855 4856 cleanup: 4857 if (ing_tbl_ptr) { 4858 soc_cm_sfree(unit, ing_tbl_ptr); 4859 } 4860 4861 if (egr_tbl_buf) { 4862 soc_cm_sfree(unit, egr_tbl_buf); 4863 } 4864 4865 return (rv); 4866 } 4867 4868 /* 4869 * Function: 4870 * _bcm_tr3_l3_tnl_term_entry_init 4871 * Purpose: 4872 * Initialize soc tunnel terminator entry key portion. 4873 * Parameters: 4874 * unit - (IN) BCM device number. 4875 * tnl_info - (IN) BCM buffer with tunnel info. 4876 * entry - (OUT) SOC buffer with key filled in. 4877 * Returns: 4878 * BCM_E_XXX 4879 */ 4880 int 4881 _bcm_tr3_l3_tnl_term_entry_init(int unit, bcm_tunnel_terminator_t *tnl_info, 4882 soc_tunnel_term_t *entry) 4883 { 4884 int idx; /* Entry iteration index. */ 4885 int idx_max; /* Entry widht. */ 4886 uint32 *entry_ptr; /* Filled entry pointer. */ 4887 _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */ 4888 int rv; /* Operation return status. */ 4889 4890 /* Input parameters check. */ 4891 if ((NULL == tnl_info) || (NULL == entry)) { 4892 return (BCM_E_PARAM); 4893 } 4894 4895 /* Get tunnel type & sub_type. */ 4896 BCM_IF_ERROR_RETURN 4897 (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type)); 4898 4899 /* Reset destination structure. */ 4900 sal_memset(entry, 0, sizeof(soc_tunnel_term_t)); 4901 4902 /* Set Destination/Source pair. */ 4903 entry_ptr = (uint32 *)&entry->entry_arr[0]; 4904 if (tnl_type.tnl_outer_hdr_ipv6) { 4905 /* Apply mask on source address. */ 4906 rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6); 4907 BCM_IF_ERROR_RETURN(rv); 4908 4909 /* SIP [0-63] */ 4910 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4911 (uint32 *)&entry->entry_arr[0], IP_ADDRf, 4912 tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY); 4913 /* SIP [64-127] */ 4914 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4915 (uint32 *)&entry->entry_arr[1], IP_ADDRf, 4916 tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY); 4917 /* DIP [0-63] */ 4918 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4919 (uint32 *)&entry->entry_arr[2], IP_ADDRf, 4920 tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY); 4921 /* DIP [64-127] */ 4922 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4923 (uint32 *)&entry->entry_arr[3], IP_ADDRf, 4924 tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY); 4925 4926 /* SIP MASK [0-63] */ 4927 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4928 (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf, 4929 tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY); 4930 /* SIP MASK [64-127] */ 4931 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4932 (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf, 4933 tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY); 4934 /* DIP MASK [0-63] */ 4935 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4936 (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf, 4937 tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY); 4938 /* DIP MASK [64-127] */ 4939 soc_mem_ip6_addr_set(unit, L3_TUNNELm, 4940 (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf, 4941 tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY); 4942 } else { 4943 tnl_info->sip &= tnl_info->sip_mask; 4944 4945 /* Set destination ip. */ 4946 soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIPf, tnl_info->dip); 4947 4948 /* Set source ip. */ 4949 soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIPf, tnl_info->sip); 4950 4951 /* Set destination subnet mask. */ 4952 soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIP_MASKf, 4953 tnl_info->dip_mask); 4954 4955 /* Set source subnet mask. */ 4956 soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIP_MASKf, 4957 tnl_info->sip_mask); 4958 } 4959 4960 /* Resolve number of entries hw entry occupies. */ 4961 idx_max = (tnl_type.tnl_outer_hdr_ipv6) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \ 4962 SOC_TNL_TERM_IPV4_ENTRY_WIDTH; 4963 4964 for (idx = 0; idx < idx_max; idx++) { 4965 entry_ptr = (uint32 *)&entry->entry_arr[idx]; 4966 4967 /* Set valid bit. */ 4968 soc_L3_TUNNELm_field32_set(unit, entry_ptr, VALIDf, 1); 4969 4970 /* Set tunnel subtype. */ 4971 soc_L3_TUNNELm_field32_set(unit, entry_ptr, SUB_TUNNEL_TYPEf, 4972 tnl_type.tnl_sub_type); 4973 4974 /* Set tunnel type. */ 4975 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_TYPEf, 4976 tnl_type.tnl_auto); 4977 4978 /* Set entry mode. */ 4979 soc_L3_TUNNELm_field32_set(unit, entry_ptr, KEY_TYPEf, 4980 tnl_type.tnl_outer_hdr_ipv6); 4981 soc_L3_TUNNELm_field32_set(unit, entry_ptr, KEY_TYPE_MASKf, 1); 4982 4983 if (0 == idx) { 4984 /* Set the PROTOCOL field */ 4985 if ((tnl_info->type == bcmTunnelTypeIpAnyIn4) || 4986 (tnl_info->type == bcmTunnelTypeIpAnyIn6)) 4987 { 4988 /* Set PROTOCOL and PROTOCOL_MASK field to zero for IpAnyInx tunnel type*/ 4989 soc_L3_TUNNELm_field32_set(unit, entry_ptr, PROTOCOLf, 0x0); 4990 soc_L3_TUNNELm_field32_set(unit, entry_ptr, PROTOCOL_MASKf, 0x0); 4991 } else { 4992 soc_L3_TUNNELm_field32_set(unit, entry_ptr, PROTOCOLf, 4993 tnl_type.tnl_protocol); 4994 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 4995 PROTOCOL_MASKf, 0xff); 4996 } 4997 } 4998 4999 if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 5000 (tnl_info->type == bcmTunnelTypeWlanAcToAc) || 5001 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) || 5002 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 5003 5004 /* Set the L4 ports - WLAN/AMT tunnels */ 5005 if (0 == idx) { 5006 soc_L3_TUNNELm_field32_set(unit, entry_ptr, L4_DEST_PORTf, 5007 tnl_info->udp_dst_port); 5008 5009 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 5010 L4_DEST_PORT_MASKf, 0xffff); 5011 5012 soc_L3_TUNNELm_field32_set(unit, entry_ptr, L4_SRC_PORTf, 5013 tnl_info->udp_src_port); 5014 5015 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 5016 L4_SRC_PORT_MASKf, 0xffff); 5017 } 5018 5019 /* Set UDP tunnel type. */ 5020 if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) { 5021 soc_L3_TUNNELm_field32_set(unit, entry_ptr, UDP_TUNNEL_TYPEf, 5022 tnl_type.tnl_udp_type); 5023 } 5024 /* Ignore UDP checksum */ 5025 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 5026 UDP_CHECKSUM_CONTROLf, 0x0); 5027 } else if (tnl_info->type == bcmTunnelTypeAutoMulticast) { 5028 5029 /* Set UDP tunnel type. */ 5030 if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) { 5031 soc_L3_TUNNELm_field32_set(unit, entry_ptr, UDP_TUNNEL_TYPEf, 5032 tnl_type.tnl_udp_type); 5033 } 5034 5035 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 5036 UDP_CHECKSUM_CONTROLf, 0x0); 5037 soc_L3_TUNNELm_field32_set(unit, entry_ptr, CTRL_PKTS_TO_CPUf, 5038 0x1); 5039 } else if (tnl_info->type == bcmTunnelTypeAutoMulticast6) { 5040 5041 /* Set UDP tunnel type. */ 5042 if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) { 5043 soc_L3_TUNNELm_field32_set(unit, entry_ptr, UDP_TUNNEL_TYPEf, 5044 tnl_type.tnl_udp_type); 5045 } 5046 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 5047 UDP_CHECKSUM_CONTROLf, 0x0); 5048 soc_L3_TUNNELm_field32_set(unit, entry_ptr, CTRL_PKTS_TO_CPUf, 0x1); 5049 } 5050 5051 /* Save vlan id for ipmc lookup.*/ 5052 soc_L3_TUNNELm_field32_set(unit, entry_ptr, L3_IIFf, tnl_info->vlan); 5053 5054 /* Set GRE payload */ 5055 if (tnl_type.tnl_gre) { 5056 /* GRE IPv6 payload is allowed. */ 5057 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV6f, 5058 tnl_type.tnl_gre_v6_payload); 5059 5060 /* GRE IPv6 payload is allowed. */ 5061 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV4f, 5062 tnl_type.tnl_gre_v4_payload); 5063 } 5064 } 5065 return (BCM_E_NONE); 5066 5067 } 5068 5069 /* 5070 * Function: 5071 * _bcm_tr3_l3_tnl_term_entry_parse 5072 * Purpose: 5073 * Parse tunnel terminator entry portion. 5074 * Parameters: 5075 * unit - (IN) BCM device number. 5076 * entry - (IN) SOC buffer with tunne information. 5077 * tnl_info - (OUT) BCM buffer with tunnel info. 5078 * Returns: 5079 * BCM_E_XXX 5080 */ 5081 int 5082 _bcm_tr3_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry, 5083 bcm_tunnel_terminator_t *tnl_info) 5084 { 5085 _bcm_tnl_term_type_t tnl_type; /* Tunnel type information. */ 5086 uint32 *entry_ptr; /* Filled entry pointer. */ 5087 int tunnel_id; /* Tunnel ID */ 5088 int remote_port; /* Remote port */ 5089 bcm_module_t mod, mod_out, my_mod; /* Module IDs */ 5090 bcm_port_t port, port_out; /* Physical ports */ 5091 5092 /* Input parameters check. */ 5093 if ((NULL == tnl_info) || (NULL == entry)) { 5094 return (BCM_E_PARAM); 5095 } 5096 5097 /* Reset destination structure. */ 5098 bcm_tunnel_terminator_t_init(tnl_info); 5099 sal_memset(&tnl_type, 0, sizeof(_bcm_tnl_term_type_t)); 5100 5101 entry_ptr = (uint32 *)&entry->entry_arr[0]; 5102 5103 /* Get valid bit. */ 5104 if (!soc_L3_TUNNELm_field32_get(unit, entry_ptr, VALIDf)) { 5105 return (BCM_E_NOT_FOUND); 5106 } 5107 5108 tnl_type.tnl_outer_hdr_ipv6 = 5109 (soc_L3_TUNNELm_field32_get(unit, entry_ptr, KEY_TYPEf) == 0x1) ? 1 : 0; 5110 5111 /* Get Destination/Source pair. */ 5112 if (tnl_type.tnl_outer_hdr_ipv6) { 5113 /* SIP [0-63] */ 5114 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5115 (uint32 *)&entry->entry_arr[0], IP_ADDRf, 5116 tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY); 5117 /* SIP [64-127] */ 5118 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5119 (uint32 *)&entry->entry_arr[1], IP_ADDRf, 5120 tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY); 5121 /* DIP [0-63] */ 5122 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5123 (uint32 *)&entry->entry_arr[2], IP_ADDRf, 5124 tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY); 5125 /* DIP [64-127] */ 5126 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5127 (uint32 *)&entry->entry_arr[3], IP_ADDRf, 5128 tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY); 5129 5130 /* SIP MASK [0-63] */ 5131 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5132 (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf, 5133 tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY); 5134 /* SIP MASK [64-127] */ 5135 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5136 (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf, 5137 tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY); 5138 /* DIP MASK [0-63] */ 5139 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5140 (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf, 5141 tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY); 5142 /* DIP MASK [64-127] */ 5143 soc_mem_ip6_addr_get(unit, L3_TUNNELm, 5144 (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf, 5145 tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY); 5146 5147 } else { 5148 /* Get destination ip. */ 5149 tnl_info->dip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, DIPf); 5150 5151 /* Get source ip. */ 5152 tnl_info->sip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, SIPf); 5153 5154 /* Destination subnet mask. */ 5155 tnl_info->dip_mask = BCM_XGS3_L3_IP4_FULL_MASK; 5156 5157 /* Source subnet mask. */ 5158 tnl_info->sip_mask = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5159 SIP_MASKf); 5160 } 5161 5162 /* Get tunnel subtype. */ 5163 tnl_type.tnl_sub_type = 5164 soc_L3_TUNNELm_field32_get(unit, entry_ptr, SUB_TUNNEL_TYPEf); 5165 5166 /* Get UDP tunnel type. */ 5167 if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) { 5168 tnl_type.tnl_udp_type = 5169 soc_L3_TUNNELm_field32_get(unit, entry_ptr, UDP_TUNNEL_TYPEf); 5170 } 5171 5172 /* Get tunnel type. */ 5173 tnl_type.tnl_auto = 5174 soc_L3_TUNNELm_field32_get(unit, entry_ptr, TUNNEL_TYPEf); 5175 5176 /* Copy DSCP from outer header flag. */ 5177 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_DSCPf)) { 5178 tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_DSCP; 5179 } 5180 /* Copy TTL from outer header flag. */ 5181 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_TTLf)) { 5182 tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_TTL; 5183 } 5184 /* Keep inner header DSCP flag. */ 5185 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5186 DONOT_CHANGE_INNER_HDR_DSCPf)) { 5187 tnl_info->flags |= BCM_TUNNEL_TERM_KEEP_INNER_DSCP; 5188 } 5189 5190 soc_mem_pbmp_field_get(unit, L3_TUNNELm, entry_ptr, ALLOWED_PORT_BITMAPf, 5191 &tnl_info->pbmp); 5192 5193 /* Tunnel or IPMC lookup vlan id */ 5194 tnl_info->vlan = soc_L3_TUNNELm_field32_get(unit, entry_ptr, IINTFf); 5195 5196 /* Get trust dscp per tunnel */ 5197 if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_DSCPf)) { 5198 tnl_info->flags |= BCM_TUNNEL_TERM_DSCP_TRUST; 5199 } 5200 5201 /* Get Tunnel class id for VFP match */ 5202 if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_CLASS_IDf)) { 5203 tnl_info->tunnel_class = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5204 TUNNEL_CLASS_IDf); 5205 } 5206 5207 /* Get the protocol field and make some decisions */ 5208 tnl_type.tnl_protocol = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5209 PROTOCOLf); 5210 switch (tnl_type.tnl_protocol) { 5211 case 0x2F: 5212 tnl_type.tnl_gre = 1; 5213 break; 5214 case 0x67: 5215 tnl_type.tnl_pim_sm = 1; 5216 default: 5217 break; 5218 } 5219 /* Get gre IPv4 payload allowed. */ 5220 tnl_type.tnl_gre_v4_payload = 5221 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV4f); 5222 5223 /* Get gre IPv6 payload allowed. */ 5224 tnl_type.tnl_gre_v6_payload = 5225 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV6f); 5226 5227 /* Get the L4 data */ 5228 if (soc_mem_field_valid (unit, L3_TUNNELm, L4_SRC_PORTf)) { 5229 tnl_info->udp_src_port = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5230 L4_SRC_PORTf); 5231 } 5232 if (soc_mem_field_valid (unit, L3_TUNNELm, L4_DEST_PORTf)) { 5233 tnl_info->udp_dst_port = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5234 L4_DEST_PORTf); 5235 } 5236 /* Get the tunnel ID */ 5237 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) { 5238 tunnel_id = soc_L3_TUNNELm_field32_get(unit, entry_ptr, TUNNEL_IDf); 5239 if (tunnel_id) { 5240 BCM_GPORT_TUNNEL_ID_SET(tnl_info->tunnel_id, tunnel_id); 5241 tnl_info->flags |= BCM_TUNNEL_TERM_TUNNEL_WITH_ID; 5242 } 5243 } 5244 5245 /* Get tunnel type, sub_type and protocol. */ 5246 BCM_IF_ERROR_RETURN 5247 (_bcm_xgs3_l3_get_tnl_term_type(unit, tnl_info, &tnl_type)); 5248 /* Get the remote port member */ 5249 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, REMOTE_TERM_GPPf)) { 5250 remote_port = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 5251 REMOTE_TERM_GPPf); 5252 mod = (remote_port >> 6) & 0x7F; 5253 port = remote_port & 0x3F; 5254 BCM_IF_ERROR_RETURN 5255 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 5256 mod, port, &mod_out, &port_out)); 5257 BCM_GPORT_MODPORT_SET(tnl_info->remote_port, mod_out, port_out); 5258 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_mod)); 5259 if (mod != my_mod) { 5260 if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 5261 (tnl_info->type == bcmTunnelTypeWlanAcToAc) || 5262 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) || 5263 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 5264 tnl_info->flags |= BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE; 5265 } 5266 } 5267 } 5268 if ((tnl_info->type == bcmTunnelTypeWlanAcToAc) || 5269 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 5270 if (_bcm_tr3_wlan_tunnel_get_roam(unit, tnl_info->tunnel_id)) { 5271 tnl_info->flags |= BCM_TUNNEL_TERM_WLAN_SET_ROAM; 5272 } 5273 } 5274 /* Get IIF if l3 ingress mode is not set */ 5275 if (!BCM_XGS3_L3_INGRESS_MODE_ISSET(unit) && 5276 BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (tnl_info->vlan > BCM_VLAN_MAX)) { 5277 _bcm_l3_ingress_intf_t iif; 5278 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 5279 iif.intf_id = tnl_info->vlan; 5280 BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif)); 5281 5282 tnl_info->vrf = iif.vrf; 5283 tnl_info->if_class = iif.if_class; 5284 tnl_info->qos_map_id = iif.qos_map_id; 5285 } 5286 5287 return (BCM_E_NONE); 5288 } 5289 5290 /* 5291 * Function: 5292 * _bcm_tr3_l3_ipmc_get 5293 * Purpose: 5294 * Get TR3 L3 multicast entry. 5295 * Parameters: 5296 * unit - (IN)SOC unit number. 5297 * l3cfg - (IN/OUT)Group/Source key & Get result buffer. 5298 * Returns: 5299 * BCM_E_XXX 5300 */ 5301 int 5302 _bcm_tr3_l3_ipmc_get(int unit, _bcm_l3_cfg_t *l3cfg) 5303 { 5304 l3_entry_4_entry_t l3x_key; /* Lookup key buffer. */ 5305 l3_entry_4_entry_t l3x_entry; /* Search result buffer. */ 5306 int clear_hit; /* Clear hit flag. */ 5307 soc_mem_t mem; /* IPMC table memory. */ 5308 int ipv6; /* IPv6 entry indicator. */ 5309 int rv; /* Return value. */ 5310 int l3_entry_idx; /* Entry index */ 5311 5312 /* Get entry type. */ 5313 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 5314 5315 /* Get table memory. */ 5316 mem = (ipv6) ? L3_ENTRY_4m : L3_ENTRY_2m; 5317 5318 /* Zero buffers. */ 5319 sal_memcpy(&l3x_key, soc_mem_entry_null(unit, mem), 5320 soc_mem_entry_words(unit,mem) * 4); 5321 sal_memcpy(&l3x_entry, soc_mem_entry_null(unit, mem), 5322 soc_mem_entry_words(unit,mem) * 4); 5323 5324 /* Check if clear hit bit is required. */ 5325 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 5326 5327 /* Lookup Key preparation. */ 5328 _bcm_tr3_l3_ipmc_ent_init(unit, (uint32 *)&l3x_key, l3cfg); 5329 5330 /* Perform hw lookup. */ 5331 MEM_LOCK(unit, mem); 5332 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 5333 _BCM_TR3_L3_MEM_BANKS_ALL, 5334 &l3x_key, &l3x_entry, &l3_entry_idx); 5335 l3cfg->l3c_hw_index = l3_entry_idx; 5336 5337 MEM_UNLOCK(unit, mem); 5338 BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND); 5339 5340 /* Extract buffer information. */ 5341 _bcm_tr3_l3_ipmc_ent_parse(unit, l3cfg, &l3x_entry); 5342 5343 /* Clear the HIT bit */ 5344 if (clear_hit) { 5345 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, l3cfg, &l3x_entry, 5346 l3_entry_idx)); 5347 } 5348 return rv; 5349 } 5350 5351 /* 5352 * Function: 5353 * _bcm_tr3_l3_ipmc_get_by_idx 5354 * Purpose: 5355 * Get l3 multicast entry by entry index. 5356 * Parameters: 5357 * unit - (IN)SOC unit number. 5358 * dma_ptr - (IN)Table pointer in dma. 5359 * idx - (IN)Index to read. 5360 * l3cfg - (IN/OUT)Entry data. 5361 * Returns: 5362 * BCM_E_XXX 5363 */ 5364 int 5365 _bcm_tr3_l3_ipmc_get_by_idx(int unit, void *dma_ptr, 5366 int idx, _bcm_l3_cfg_t *l3cfg) 5367 { 5368 l3_entry_4_entry_t l3_entry_v6; /* Read buffer. */ 5369 l3_entry_2_entry_t l3_entry_v4; /* Read buffer. */ 5370 void *buf_p; /* Hardware buffer ptr */ 5371 soc_mem_t mem; /* IPMC table memory. */ 5372 uint32 ipv6; /* IPv6 entry indicator. */ 5373 int clear_hit; /* Clear hit bit indicator.*/ 5374 int key_type; 5375 soc_field_t l3iif; 5376 5377 /* Get entry type. */ 5378 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 5379 5380 /* Get table memory. */ 5381 if (ipv6) { 5382 mem = L3_ENTRY_4m; 5383 buf_p = (l3_entry_4_entry_t *)&l3_entry_v6; 5384 l3iif = IPV6MC__L3_IIFf; 5385 } else { 5386 mem = L3_ENTRY_2m; 5387 buf_p = (l3_entry_2_entry_t *)&l3_entry_v4; 5388 l3iif = IPV4MC__L3_IIFf; 5389 } 5390 5391 /* Check if clear hit is required. */ 5392 clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR; 5393 5394 if (NULL == dma_ptr) { /* Read from hardware. */ 5395 /* Zero buffers. */ 5396 sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 5397 soc_mem_entry_words(unit,mem) * 4); 5398 5399 /* Read entry from hw. */ 5400 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_p)); 5401 } else { /* Read from dma. */ 5402 if (ipv6) { 5403 buf_p = soc_mem_table_idx_to_pointer(unit, mem, 5404 l3_entry_4_entry_t *, dma_ptr, idx); 5405 } else { 5406 buf_p = soc_mem_table_idx_to_pointer(unit, mem, 5407 l3_entry_2_entry_t *, dma_ptr, idx); 5408 } 5409 } 5410 5411 /* Ignore invalid entries. */ 5412 if (!soc_mem_field32_get(unit, mem, buf_p, VALID_0f)) { 5413 return (BCM_E_NOT_FOUND); 5414 } 5415 5416 key_type = soc_mem_field32_get(unit, mem, buf_p, KEY_TYPE_0f); 5417 5418 switch (key_type) { 5419 case SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST: 5420 l3cfg->l3c_flags = BCM_L3_IPMC; 5421 break; 5422 case SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST: 5423 case SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST: 5424 l3cfg->l3c_flags = BCM_L3_IP6; 5425 break; 5426 case SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST: 5427 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC; 5428 break; 5429 default: 5430 /* Catch all other key types, set flags to zero so that the 5431 * following flag check is effective for all key types */ 5432 l3cfg->l3c_flags = 0; 5433 break; 5434 } 5435 5436 /* Ignore protocol mismatch & multicast entries. */ 5437 if ((ipv6 != (l3cfg->l3c_flags & BCM_L3_IP6)) || 5438 (!(l3cfg->l3c_flags & BCM_L3_IPMC))) { 5439 return (BCM_E_NOT_FOUND); 5440 } 5441 5442 /* Set index to l3cfg. */ 5443 l3cfg->l3c_hw_index = idx; 5444 5445 if (ipv6) { 5446 /* Get group address. */ 5447 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_96f, 5448 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_96BIT); 5449 5450 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_24f, 5451 l3cfg->l3c_ip6, SOC_MEM_IP6_BITS_119_96); 5452 5453 /* Get source address. */ 5454 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 5455 l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY); 5456 soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 5457 l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY); 5458 5459 l3cfg->l3c_ip6[0] = 0xff; /* Set entry to multicast*/ 5460 } else { 5461 /* Get group id. */ 5462 l3cfg->l3c_ip_addr = 5463 soc_mem_field32_get(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf); 5464 5465 /* Get source address. */ 5466 l3cfg->l3c_src_ip_addr = 5467 soc_mem_field32_get(unit, mem, buf_p, IPV4MC__SOURCE_IP_ADDRf); 5468 } 5469 5470 /* Get L3_IIF or vlan id. */ 5471 l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, l3iif); 5472 5473 /* Parse entry data. */ 5474 _bcm_tr3_l3_ipmc_ent_parse(unit, l3cfg, buf_p); 5475 5476 /* Clear the HIT bit */ 5477 if (clear_hit) { 5478 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, l3cfg, buf_p, 5479 l3cfg->l3c_hw_index)); 5480 } 5481 return (BCM_E_NONE); 5482 } 5483 5484 /* 5485 * Function: 5486 * _bcm_tr3_l3_ipmc_add 5487 * Purpose: 5488 * Add TR3 L3 multicast entry. 5489 * Parameters: 5490 * unit - (IN)SOC unit number. 5491 * l3cfg - (IN/OUT)Group/Source key. 5492 * Returns: 5493 * BCM_E_XXX 5494 */ 5495 int 5496 _bcm_tr3_l3_ipmc_add(int unit, _bcm_l3_cfg_t *l3cfg) 5497 { 5498 l3_entry_4_entry_t l3x_entry; /* Write entry buffer. */ 5499 soc_mem_t mem; /* IPMC table memory. */ 5500 uint32 *buf_p; /* HW buffer address. */ 5501 int ipv6; /* IPv6 entry indicator. */ 5502 int idx; /* Iteration index. */ 5503 int rv; /* Return value. */ 5504 soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f}; 5505 soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, class_id, pri; 5506 5507 /* Get entry type. */ 5508 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 5509 5510 /* Get table memory and table fields */ 5511 if (ipv6) { 5512 mem = L3_ENTRY_4m; 5513 pri = IPV6MC__PRIf; 5514 rpe = IPV6MC__RPEf; 5515 vrf_id = IPV6MC__VRF_IDf; 5516 l3mc_idx = IPV6MC__L3MC_INDEXf; 5517 class_id = IPV6MC__CLASS_IDf; 5518 dst_discard = IPV6MC__DST_DISCARDf; 5519 } else { 5520 mem = L3_ENTRY_2m; 5521 pri = IPV4MC__PRIf; 5522 rpe = IPV4MC__RPEf; 5523 vrf_id = IPV4MC__VRF_IDf; 5524 l3mc_idx = IPV4MC__L3MC_INDEXf; 5525 class_id = IPV4MC__CLASS_IDf; 5526 dst_discard = IPV4MC__DST_DISCARDf; 5527 } 5528 5529 /* Zero buffers. */ 5530 buf_p = (uint32 *)&l3x_entry; 5531 sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 5532 soc_mem_entry_words(unit,mem) * 4); 5533 5534 /* Prepare entry to write. */ 5535 _bcm_tr3_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg); 5536 5537 /* Set priority override bit. */ 5538 if (l3cfg->l3c_flags & BCM_L3_RPE) { 5539 soc_mem_field32_set(unit, mem, buf_p, rpe, 1); 5540 } 5541 5542 /* Set destination discard. */ 5543 if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) { 5544 soc_mem_field32_set(unit, mem, buf_p, dst_discard, 1); 5545 } 5546 5547 /* Virtual router id. */ 5548 soc_mem_field32_set(unit, mem, buf_p, vrf_id, l3cfg->l3c_vrf); 5549 5550 /* Set priority. */ 5551 soc_mem_field32_set(unit, mem, buf_p, pri, l3cfg->l3c_prio); 5552 5553 /* Pointer to ipmc table. */ 5554 soc_mem_field32_set(unit, mem, buf_p, l3mc_idx, l3cfg->l3c_ipmc_ptr); 5555 5556 /* Classification lookup class id. */ 5557 soc_mem_field32_set(unit, mem, buf_p, class_id, l3cfg->l3c_lookup_class); 5558 5559 for (idx = 0; idx < COUNTOF(hitf); idx++) { 5560 /* Set hit bit. */ 5561 if (l3cfg->l3c_flags & BCM_L3_HIT) { 5562 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 1); 5563 } 5564 } 5565 5566 /* Write entry to the hw. */ 5567 MEM_LOCK(unit, mem); 5568 /* Handle replacement. */ 5569 if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) { 5570 rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p); 5571 } else { 5572 rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)buf_p); 5573 } 5574 5575 /* Increment number of ipmc routes. */ 5576 if (BCM_SUCCESS(rv) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) { 5577 (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)++ : \ 5578 BCM_XGS3_L3_IP4_IPMC_CNT(unit)++; 5579 } 5580 /* coverity[overrun-local : FALSE] */ 5581 MEM_UNLOCK(unit, mem); 5582 return rv; 5583 } 5584 5585 /* 5586 * Function: 5587 * _bcm_tr3_l3_ipmc_del 5588 * Purpose: 5589 * Delete TR3 L3 multicast entry. 5590 * Parameters: 5591 * unit - (IN)SOC unit number. 5592 * l3cfg - (IN)Group/Source deletion key. 5593 * Returns: 5594 * BCM_E_XXX 5595 */ 5596 int 5597 _bcm_tr3_l3_ipmc_del(int unit, _bcm_l3_cfg_t *l3cfg) 5598 { 5599 l3_entry_4_entry_t l3x_entry; /* Delete buffer. */ 5600 soc_mem_t mem; /* IPMC table memory. */ 5601 int ipv6; /* IPv6 entry indicator. */ 5602 int rv; /* Operation return value. */ 5603 5604 /* Get entry type. */ 5605 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 5606 5607 /* Get table memory. */ 5608 mem = (ipv6) ? L3_ENTRY_4m : L3_ENTRY_2m; 5609 5610 /* Zero entry buffer. */ 5611 sal_memcpy(&l3x_entry, soc_mem_entry_null(unit, mem), 5612 soc_mem_entry_words(unit,mem) * 4); 5613 5614 5615 /* Key preparation. */ 5616 _bcm_tr3_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg); 5617 5618 /* Delete the entry from hw. */ 5619 MEM_LOCK(unit, mem); 5620 5621 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry); 5622 5623 /* Decrement number of ipmc routes. */ 5624 if (BCM_SUCCESS(rv)) { 5625 (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)-- : \ 5626 BCM_XGS3_L3_IP4_IPMC_CNT(unit)--; 5627 } 5628 MEM_UNLOCK(unit, mem); 5629 return rv; 5630 } 5631 5632 /*----- ECMP DLB FUNCS ----- */ 5633 5634 /* 5635 * Function: 5636 * _bcm_tr3_ecmp_dlb_member_id_alloc 5637 * Purpose: 5638 * Get a free ECMP DLB Member ID and mark it used. 5639 * Parameters: 5640 * unit - (IN) SOC unit number. 5641 * member_id - (OUT) Allocated Member ID. 5642 * Returns: 5643 * BCM_E_xxx 5644 */ 5645 STATIC int 5646 _bcm_tr3_ecmp_dlb_member_id_alloc(int unit, int *member_id) 5647 { 5648 int vla; 5649 int i; 5650 int max_members; 5651 5652 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 5653 bcmSwitchEcmpDynamicAccountingSelect, &vla)); 5654 if (vla) { 5655 max_members = soc_mem_index_count(unit, DLB_ECMP_MEMBER_ATTRIBUTEm); 5656 } else { 5657 /* In physical link accounting, the number of members is limited to 5658 * the number of physical ports. 5659 */ 5660 max_members = soc_reg_field_length(unit, DLB_ECMP_MEMBER_HW_STATE_64r, 5661 BITMAPf); 5662 } 5663 5664 for (i = 0; i < max_members; i++) { 5665 if (!_BCM_ECMP_DLB_MEMBER_ID_USED_GET(unit, i)) { 5666 _BCM_ECMP_DLB_MEMBER_ID_USED_SET(unit, i); 5667 *member_id = i; 5668 return BCM_E_NONE; 5669 } 5670 } 5671 5672 return BCM_E_RESOURCE; 5673 } 5674 5675 /* 5676 * Function: 5677 * _bcm_tr3_ecmp_dlb_member_id_free 5678 * Purpose: 5679 * Free an ECMP DLB Member ID. 5680 * Parameters: 5681 * unit - (IN) SOC unit number. 5682 * member_id - (IN) Member ID to be freed. 5683 * Returns: 5684 * BCM_E_xxx 5685 */ 5686 STATIC int 5687 _bcm_tr3_ecmp_dlb_member_id_free(int unit, int member_id) 5688 { 5689 if (member_id < 0 || member_id > soc_mem_index_max(unit, 5690 DLB_ECMP_MEMBER_ATTRIBUTEm)) { 5691 return BCM_E_PARAM; 5692 } 5693 5694 _BCM_ECMP_DLB_MEMBER_ID_USED_CLR(unit, member_id); 5695 5696 return BCM_E_NONE; 5697 } 5698 5699 /* 5700 * Function: 5701 * _bcm_tr3_ecmp_dlb_quality_assign 5702 * Purpose: 5703 * Assign quality based on loading and queue size. 5704 * Parameters: 5705 * unit - (IN)SOC unit number. 5706 * tx_load_percent - (IN) Percent weight of loading in determing quality. 5707 * The remaining percentage is the weight of queue 5708 * size. 5709 * entry_arr - (IN) Array of 64 quality map table entries. 5710 * Returns: 5711 * BCM_X_XXX 5712 */ 5713 STATIC int 5714 _bcm_tr3_ecmp_dlb_quality_assign(int unit, int tx_load_percent, 5715 uint32 *entry_arr) 5716 { 5717 int quantized_tx_load; 5718 int quantized_qsize; 5719 int quality; 5720 int entry_index; 5721 5722 if (entry_arr == NULL) { 5723 return BCM_E_PARAM; 5724 } 5725 5726 for (quantized_tx_load = 0; quantized_tx_load < 8; quantized_tx_load++) { 5727 for (quantized_qsize = 0; quantized_qsize < 8; quantized_qsize++) { 5728 quality = (quantized_tx_load * tx_load_percent + 5729 quantized_qsize * (100 - tx_load_percent)) / 100; 5730 entry_index = (quantized_tx_load << 3) + quantized_qsize; 5731 soc_DLB_ECMP_QUALITY_MAPPINGm_field32_set(unit, 5732 &entry_arr[entry_index], QUALITYf, quality); 5733 } 5734 } 5735 5736 return BCM_E_NONE; 5737 } 5738 5739 /* 5740 * Function: 5741 * _bcm_tr3_ecmp_dlb_member_quality_map_set 5742 * Purpose: 5743 * Set per-member ECMP DLB quality mapping table. 5744 * Parameters: 5745 * unit - (IN) SOC unit number. 5746 * member_id - (IN) Member ID. 5747 * tx_load_percent - (IN) Percent weight of loading in determing quality. 5748 * The remaining percentage is the weight of queue 5749 * size. 5750 * Returns: 5751 * BCM_E_xxx 5752 */ 5753 STATIC int 5754 _bcm_tr3_ecmp_dlb_member_quality_map_set(int unit, int member_id, 5755 int tx_load_percent) 5756 { 5757 soc_profile_mem_t *profile; 5758 soc_mem_t mem; 5759 int entry_bytes; 5760 int entries_per_profile; 5761 int alloc_size; 5762 uint32 *entry_arr; 5763 int rv = BCM_E_NONE; 5764 void *entries; 5765 uint32 base_index; 5766 uint32 old_base_index; 5767 dlb_ecmp_quality_control_entry_t quality_control_entry; 5768 5769 profile = ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile; 5770 5771 entries_per_profile = 64; 5772 entry_bytes = sizeof(dlb_ecmp_quality_mapping_entry_t); 5773 alloc_size = entries_per_profile * entry_bytes; 5774 entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries"); 5775 if (entry_arr == NULL) { 5776 return BCM_E_MEMORY; 5777 } 5778 sal_memset(entry_arr, 0, alloc_size); 5779 5780 /* Assign quality in the entry array */ 5781 rv = _bcm_tr3_ecmp_dlb_quality_assign(unit, tx_load_percent, entry_arr); 5782 if (BCM_FAILURE(rv)) { 5783 sal_free(entry_arr); 5784 return rv; 5785 } 5786 5787 mem = DLB_ECMP_QUALITY_MAPPINGm; 5788 soc_mem_lock(unit, mem); 5789 5790 /* Add profile */ 5791 entries = entry_arr; 5792 rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile, 5793 &base_index); 5794 sal_free(entry_arr); 5795 if (SOC_FAILURE(rv)) { 5796 soc_mem_unlock(unit, mem); 5797 return rv; 5798 } 5799 5800 /* Update member profile pointer */ 5801 rv = READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, member_id, 5802 &quality_control_entry); 5803 if (SOC_FAILURE(rv)) { 5804 soc_mem_unlock(unit, mem); 5805 return rv; 5806 } 5807 old_base_index = entries_per_profile * soc_mem_field32_get(unit, 5808 DLB_ECMP_QUALITY_CONTROLm, &quality_control_entry, 5809 PROFILE_PTRf); 5810 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, &quality_control_entry, 5811 PROFILE_PTRf, base_index / entries_per_profile); 5812 rv = WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL, member_id, 5813 &quality_control_entry); 5814 if (SOC_FAILURE(rv)) { 5815 soc_mem_unlock(unit, mem); 5816 return rv; 5817 } 5818 5819 /* Delete old profile */ 5820 rv = soc_profile_mem_delete(unit, profile, old_base_index); 5821 soc_mem_unlock(unit, mem); 5822 5823 ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[base_index/entries_per_profile] = 5824 tx_load_percent; 5825 5826 return rv; 5827 } 5828 5829 /* 5830 * Function: 5831 * _bcm_tr3_ecmp_dlb_member_attr_set 5832 * Purpose: 5833 * Set ECMP dynamic load balancing attributes for a member. 5834 * Parameters: 5835 * unit - (IN) SOC unit number. 5836 * member_id - (IN) Member ID. 5837 * nh_index - (IN) Next hop index. 5838 * scaling_factor - (IN) Threshold scaling factor. 5839 * load_weight - (IN) Weighting of load in determining member quality. 5840 * Returns: 5841 * BCM_E_XXX 5842 */ 5843 STATIC int 5844 _bcm_tr3_ecmp_dlb_member_attr_set(int unit, int member_id, int nh_index, 5845 int scaling_factor, int load_weight) 5846 { 5847 dlb_ecmp_quality_control_entry_t dlb_ecmp_quality_control_entry; 5848 dlb_ecmp_member_attribute_entry_t dlb_ecmp_member_attr_entry; 5849 5850 /* Set load weight */ 5851 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_quality_map_set(unit, 5852 member_id, load_weight)); 5853 5854 /* Set scaling factor */ 5855 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, 5856 member_id, &dlb_ecmp_quality_control_entry)); 5857 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 5858 &dlb_ecmp_quality_control_entry, LOADING_SCALING_FACTORf, 5859 scaling_factor); 5860 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 5861 &dlb_ecmp_quality_control_entry, QSIZE_SCALING_FACTORf, 5862 scaling_factor); 5863 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL, 5864 member_id, &dlb_ecmp_quality_control_entry)); 5865 5866 /* Set next hop index */ 5867 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ANY, 5868 member_id, &dlb_ecmp_member_attr_entry)); 5869 soc_DLB_ECMP_MEMBER_ATTRIBUTEm_field32_set(unit, 5870 &dlb_ecmp_member_attr_entry, NEXT_HOP_INDEXf, nh_index); 5871 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ALL, 5872 member_id, &dlb_ecmp_member_attr_entry)); 5873 5874 return BCM_E_NONE; 5875 } 5876 5877 /* 5878 * Function: 5879 * _bcm_tr3_ecmp_dlb_member_attr_get 5880 * Purpose: 5881 * Get ECMP dynamic load balancing attributes for a member. 5882 * Parameters: 5883 * unit - (IN) SOC unit number. 5884 * member_id - (IN) Member ID. 5885 * scaling_factor - (OUT) Threshold scaling factor. 5886 * load_weight - (OUT) Weighting of load in determining member quality. 5887 * Returns: 5888 * BCM_E_XXX 5889 */ 5890 STATIC int 5891 _bcm_tr3_ecmp_dlb_member_attr_get(int unit, int member_id, int *scaling_factor, 5892 int *load_weight) 5893 { 5894 dlb_ecmp_quality_control_entry_t dlb_ecmp_quality_control_entry; 5895 int profile_ptr; 5896 5897 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, 5898 member_id, &dlb_ecmp_quality_control_entry)); 5899 5900 /* Get load weight */ 5901 profile_ptr = soc_DLB_ECMP_QUALITY_CONTROLm_field32_get(unit, 5902 &dlb_ecmp_quality_control_entry, PROFILE_PTRf); 5903 *load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr]; 5904 5905 /* Get scaling factor */ 5906 *scaling_factor = soc_DLB_ECMP_QUALITY_CONTROLm_field32_get(unit, 5907 &dlb_ecmp_quality_control_entry, LOADING_SCALING_FACTORf); 5908 5909 return BCM_E_NONE; 5910 } 5911 5912 /* 5913 * Function: 5914 * bcm_tr3_l3_egress_dlb_attr_set 5915 * Purpose: 5916 * Set ECMP dynamic load balancing attributes for a next hop index. 5917 * Parameters: 5918 * unit - (IN) SOC unit number. 5919 * nh_index - (IN) Next hop index. 5920 * egr - (IN) L3 egress info. 5921 * Returns: 5922 * BCM_E_XXX 5923 */ 5924 int 5925 bcm_tr3_l3_egress_dlb_attr_set(int unit, int nh_index, bcm_l3_egress_t *egr) 5926 { 5927 int rv = BCM_E_NONE; 5928 int match, match_index; 5929 int free_index_found, free_index; 5930 int i; 5931 _tr3_ecmp_dlb_nh_membership_t *membership, *current_ptr, *next_ptr; 5932 int scaling_factor_invalid, load_weight_invalid; 5933 5934 if (egr->dynamic_scaling_factor == 5935 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) { 5936 scaling_factor_invalid = TRUE; 5937 } else { 5938 scaling_factor_invalid = FALSE; 5939 } 5940 if (egr->dynamic_load_weight == 5941 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID) { 5942 load_weight_invalid = TRUE; 5943 } else { 5944 load_weight_invalid = FALSE; 5945 } 5946 if (scaling_factor_invalid != load_weight_invalid) { 5947 /* The scaling factor and the load weight must be both invalid, 5948 * or both valid. 5949 */ 5950 return BCM_E_PARAM; 5951 } 5952 5953 /* Traverse ecmp_dlb_nh_info array to find the given nh_index */ 5954 match = FALSE; 5955 match_index = 0; 5956 free_index_found = FALSE; 5957 free_index = 0; 5958 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 5959 if (ECMP_DLB_NH_INFO(unit, i).valid) { 5960 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 5961 match = TRUE; 5962 match_index = i; 5963 } 5964 } else { 5965 if (!free_index_found) { 5966 free_index_found = TRUE; 5967 free_index = i; 5968 } 5969 } 5970 } 5971 5972 if (match) { 5973 5974 if ((egr->dynamic_scaling_factor == 5975 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) && 5976 (egr->dynamic_load_weight == 5977 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID)) { 5978 /* Check that the given next hop index is currently not a member of 5979 * any ECMP DLB group. 5980 */ 5981 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 5982 while (NULL != current_ptr) { 5983 if (current_ptr->group != -1) { 5984 return BCM_E_BUSY; 5985 } 5986 current_ptr = current_ptr->next; 5987 } 5988 5989 /* Reset the DLB attributes, free member ID, free linked list */ 5990 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 5991 while (NULL != current_ptr) { 5992 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_set(unit, 5993 current_ptr->member_id, 0, 0, 100)); 5994 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_id_free(unit, 5995 current_ptr->member_id)); 5996 next_ptr = current_ptr->next; 5997 sal_free(current_ptr); 5998 current_ptr = next_ptr; 5999 } 6000 ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list = NULL; 6001 ECMP_DLB_NH_INFO(unit, free_index).nh_index = 0; 6002 ECMP_DLB_NH_INFO(unit, free_index).valid = 0; 6003 6004 } else { 6005 /* Traverse next hop index's linked list of DLB member IDs and 6006 * update their DLB attributes. 6007 */ 6008 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6009 while (NULL != current_ptr) { 6010 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_set(unit, 6011 current_ptr->member_id, nh_index, 6012 egr->dynamic_scaling_factor, 6013 egr->dynamic_load_weight)); 6014 current_ptr = current_ptr->next; 6015 } 6016 } 6017 6018 } else { /* No match */ 6019 6020 if ((egr->dynamic_scaling_factor == 6021 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) && 6022 (egr->dynamic_load_weight == 6023 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID)) { 6024 /* Nothing to do */ 6025 return BCM_E_NONE; 6026 } 6027 6028 if (!free_index_found) { 6029 /* ecmp_dlb_nh_info array is full */ 6030 return BCM_E_FULL; 6031 } 6032 6033 /* Allocate a DLB member ID and set DLB attributes */ 6034 membership = sal_alloc(sizeof(_tr3_ecmp_dlb_nh_membership_t), 6035 "ecmp dlb nh membership"); 6036 if (NULL == membership) { 6037 return BCM_E_MEMORY; 6038 } 6039 rv = _bcm_tr3_ecmp_dlb_member_id_alloc(unit, &membership->member_id); 6040 if (BCM_FAILURE(rv)) { 6041 sal_free(membership); 6042 return rv; 6043 } 6044 rv = _bcm_tr3_ecmp_dlb_member_attr_set(unit, membership->member_id, 6045 nh_index, egr->dynamic_scaling_factor, 6046 egr->dynamic_load_weight); 6047 if (BCM_FAILURE(rv)) { 6048 sal_free(membership); 6049 return rv; 6050 } 6051 membership->group = -1; 6052 membership->next = 6053 ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list; 6054 ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list = membership; 6055 ECMP_DLB_NH_INFO(unit, free_index).nh_index = nh_index; 6056 ECMP_DLB_NH_INFO(unit, free_index).valid = 1; 6057 } 6058 6059 return rv; 6060 } 6061 6062 /* 6063 * Function: 6064 * bcm_tr3_l3_egress_dlb_attr_destroy 6065 * Purpose: 6066 * Destroy ECMP dynamic load balancing attributes for a next hop index. 6067 * Parameters: 6068 * unit - (IN) SOC unit number. 6069 * nh_index - (IN) Next hop index. 6070 * Returns: 6071 * BCM_E_XXX 6072 */ 6073 int 6074 bcm_tr3_l3_egress_dlb_attr_destroy(int unit, int nh_index) 6075 { 6076 int rv = BCM_E_NONE; 6077 int match, match_index; 6078 int i; 6079 _tr3_ecmp_dlb_nh_membership_t *current_ptr, *next_ptr; 6080 6081 /* Traverse ecmp_dlb_nh_info array to find the given nh_index */ 6082 match = FALSE; 6083 match_index = 0; 6084 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 6085 if (ECMP_DLB_NH_INFO(unit, i).valid) { 6086 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 6087 match = TRUE; 6088 match_index = i; 6089 break; 6090 } 6091 } 6092 } 6093 6094 if (match) { 6095 /* Check that the given next hop index is currently not a member of 6096 * any ECMP DLB group. 6097 */ 6098 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6099 while (NULL != current_ptr) { 6100 if (current_ptr->group != -1) { 6101 return BCM_E_BUSY; 6102 } 6103 current_ptr = current_ptr->next; 6104 } 6105 6106 /* Reset the DLB attributes, free member ID, free linked list */ 6107 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6108 while (NULL != current_ptr) { 6109 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_set(unit, 6110 current_ptr->member_id, 0, 0, 100)); 6111 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_id_free(unit, 6112 current_ptr->member_id)); 6113 next_ptr = current_ptr->next; 6114 sal_free(current_ptr); 6115 current_ptr = next_ptr; 6116 } 6117 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = NULL; 6118 ECMP_DLB_NH_INFO(unit, match_index).nh_index = 0; 6119 ECMP_DLB_NH_INFO(unit, match_index).valid = 0; 6120 } 6121 6122 return rv; 6123 } 6124 6125 /* 6126 * Function: 6127 * bcm_tr3_l3_egress_dlb_attr_get 6128 * Purpose: 6129 * Get ECMP dynamic load balancing attributes for a next hop index. 6130 * Parameters: 6131 * unit - (IN) SOC unit number. 6132 * nh_index - (IN) Next hop index. 6133 * egr - (OUT) L3 egress info. 6134 * Returns: 6135 * BCM_E_XXX 6136 */ 6137 int 6138 bcm_tr3_l3_egress_dlb_attr_get(int unit, int nh_index, bcm_l3_egress_t *egr) 6139 { 6140 int rv = BCM_E_NONE; 6141 int match, match_index; 6142 int i; 6143 _tr3_ecmp_dlb_nh_membership_t *current_ptr; 6144 6145 /* Traverse ecmp_dlb_nh_info array to find the given nh_index */ 6146 match = FALSE; 6147 match_index = 0; 6148 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 6149 if (ECMP_DLB_NH_INFO(unit, i).valid) { 6150 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 6151 match = TRUE; 6152 match_index = i; 6153 break; 6154 } 6155 } 6156 } 6157 6158 if (match) { 6159 /* Get the DLB attributes */ 6160 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6161 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_get(unit, 6162 current_ptr->member_id, &egr->dynamic_scaling_factor, 6163 &egr->dynamic_load_weight)); 6164 } else { 6165 egr->dynamic_scaling_factor = BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID; 6166 egr->dynamic_load_weight = BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID; 6167 } 6168 6169 return rv; 6170 } 6171 6172 /* 6173 * Function: 6174 * _bcm_tr3_ecmp_dlb_id_alloc 6175 * Purpose: 6176 * Get a free ECMP DLB ID and mark it used. 6177 * Parameters: 6178 * unit - (IN) SOC unit number. 6179 * dlb_id - (OUT) Allocated DLB ID. 6180 * Returns: 6181 * BCM_E_xxx 6182 */ 6183 STATIC int 6184 _bcm_tr3_ecmp_dlb_id_alloc(int unit, int *dlb_id) 6185 { 6186 int i; 6187 6188 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) { 6189 if (!_BCM_ECMP_DLB_ID_USED_GET(unit, i)) { 6190 _BCM_ECMP_DLB_ID_USED_SET(unit, i); 6191 *dlb_id = i; 6192 return BCM_E_NONE; 6193 } 6194 } 6195 6196 return BCM_E_RESOURCE; 6197 } 6198 6199 /* 6200 * Function: 6201 * _bcm_tr3_ecmp_dlb_id_free 6202 * Purpose: 6203 * Free an ECMP DLB ID. 6204 * Parameters: 6205 * unit - (IN) SOC unit number. 6206 * dlb_id - (IN) DLB ID to be freed. 6207 * Returns: 6208 * BCM_E_xxx 6209 */ 6210 STATIC int 6211 _bcm_tr3_ecmp_dlb_id_free(int unit, int dlb_id) 6212 { 6213 if (dlb_id < 0 || 6214 dlb_id > soc_mem_index_max(unit, DLB_ECMP_GROUP_CONTROLm)) { 6215 return BCM_E_PARAM; 6216 } 6217 6218 _BCM_ECMP_DLB_ID_USED_CLR(unit, dlb_id); 6219 6220 return BCM_E_NONE; 6221 } 6222 6223 /* 6224 * Function: 6225 * _bcm_tr3_ecmp_dlb_dynamic_size_encode 6226 * Purpose: 6227 * Encode ECMP dynamic load balancing flow set size. 6228 * Parameters: 6229 * dynamic_size - (IN) Number of flow sets. 6230 * encoded_value - (OUT) Encoded value. 6231 * Returns: 6232 * BCM_E_xxx 6233 */ 6234 STATIC int 6235 _bcm_tr3_ecmp_dlb_dynamic_size_encode(int dynamic_size, 6236 int *encoded_value) 6237 { 6238 switch (dynamic_size) { 6239 case 512: 6240 *encoded_value = 1; 6241 break; 6242 case 1024: 6243 *encoded_value = 2; 6244 break; 6245 case 2048: 6246 *encoded_value = 3; 6247 break; 6248 case 4096: 6249 *encoded_value = 4; 6250 break; 6251 case 8192: 6252 *encoded_value = 5; 6253 break; 6254 case 16384: 6255 *encoded_value = 6; 6256 break; 6257 case 32768: 6258 *encoded_value = 7; 6259 break; 6260 default: 6261 return BCM_E_PARAM; 6262 } 6263 6264 return BCM_E_NONE; 6265 } 6266 6267 /* 6268 * Function: 6269 * _bcm_tr3_ecmp_dlb_dynamic_size_decode 6270 * Purpose: 6271 * Decode ECMP dynamic load balancing flow set size. 6272 * Parameters: 6273 * encoded_value - (IN) Encoded value. 6274 * dynamic_size - (OUT) Number of flow sets. 6275 * Returns: 6276 * BCM_E_xxx 6277 */ 6278 STATIC int 6279 _bcm_tr3_ecmp_dlb_dynamic_size_decode(int encoded_value, 6280 int *dynamic_size) 6281 { 6282 switch (encoded_value) { 6283 case 1: 6284 *dynamic_size = 512; 6285 break; 6286 case 2: 6287 *dynamic_size = 1024; 6288 break; 6289 case 3: 6290 *dynamic_size = 2048; 6291 break; 6292 case 4: 6293 *dynamic_size = 4096; 6294 break; 6295 case 5: 6296 *dynamic_size = 8192; 6297 break; 6298 case 6: 6299 *dynamic_size = 16384; 6300 break; 6301 case 7: 6302 *dynamic_size = 32768; 6303 break; 6304 default: 6305 return BCM_E_INTERNAL; 6306 } 6307 6308 return BCM_E_NONE; 6309 } 6310 6311 /* 6312 * Function: 6313 * _bcm_tr3_ecmp_dlb_nh_membership_free_resource 6314 * Purpose: 6315 * Free resources in ECMP DLB next hop membership. 6316 * Parameters: 6317 * unit - (IN) SOC unit number. 6318 * nh_index - (IN) Next hop index. 6319 * member_id - (IN) ECMP DLB member ID. 6320 * dlb_id - (IN) ECMP DLB group ID. 6321 * Returns: 6322 * BCM_E_xxx 6323 */ 6324 STATIC int 6325 _bcm_tr3_ecmp_dlb_nh_membership_free_resource(int unit, int nh_index, 6326 int member_id, int dlb_id) 6327 { 6328 int match, match_index; 6329 int i; 6330 int member_id_count; 6331 _tr3_ecmp_dlb_nh_membership_t *current_ptr, *prev_ptr; 6332 int member_match; 6333 6334 /* Traverse ecmp_dlb_nh_info array to find the given nh_index */ 6335 match = FALSE; 6336 match_index = 0; 6337 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 6338 if (ECMP_DLB_NH_INFO(unit, i).valid) { 6339 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 6340 match = TRUE; 6341 match_index = i; 6342 break; 6343 } 6344 } 6345 } 6346 if (!match) { 6347 return BCM_E_INTERNAL; 6348 } 6349 6350 /* Count the number of member IDs assigned to this next hop */ 6351 member_id_count = 0; 6352 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6353 while (NULL != current_ptr) { 6354 member_id_count++; 6355 current_ptr = current_ptr->next; 6356 } 6357 6358 if (0 == member_id_count) { 6359 return BCM_E_INTERNAL; 6360 } 6361 6362 /* If there is only one member ID assigned to the next hop index, 6363 * do not free the member ID, merely invalidate the group. 6364 */ 6365 if (1 == member_id_count) { 6366 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6367 if ((current_ptr->member_id != member_id) || 6368 (current_ptr->group != dlb_id)) { 6369 return BCM_E_INTERNAL; 6370 } 6371 current_ptr->group = -1; 6372 return BCM_E_NONE; 6373 } 6374 6375 /* If there are more than 1 member IDs assigned to the next hop index, 6376 * free the given member ID. 6377 */ 6378 prev_ptr = NULL; 6379 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6380 member_match = FALSE; 6381 while (NULL != current_ptr) { 6382 if ((current_ptr->member_id == member_id) && 6383 (current_ptr->group == dlb_id)) { 6384 if (NULL == prev_ptr) { 6385 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = 6386 current_ptr->next; 6387 } else { 6388 prev_ptr->next = current_ptr->next; 6389 } 6390 sal_free(current_ptr); 6391 6392 /* Reset member DLB attributes */ 6393 BCM_IF_ERROR_RETURN 6394 (_bcm_tr3_ecmp_dlb_member_attr_set(unit, member_id, 0, 0, 100)); 6395 6396 /* Free member ID */ 6397 BCM_IF_ERROR_RETURN 6398 (_bcm_tr3_ecmp_dlb_member_id_free(unit, member_id)); 6399 6400 member_match = TRUE; 6401 break; 6402 } 6403 prev_ptr = current_ptr; 6404 current_ptr = current_ptr->next; 6405 } 6406 if (!member_match) { 6407 return BCM_E_INTERNAL; 6408 } 6409 6410 return BCM_E_NONE; 6411 } 6412 6413 /* 6414 * Function: 6415 * _bcm_tr3_ecmp_dlb_free_resource 6416 * Purpose: 6417 * Free resources for an ECMP dynamic load balancing group. 6418 * Parameters: 6419 * unit - (IN) SOC unit number. 6420 * ecmp_group_idx - (IN) ECMP group index. 6421 * Returns: 6422 * BCM_E_xxx 6423 */ 6424 STATIC int 6425 _bcm_tr3_ecmp_dlb_free_resource(int unit, int ecmp_group_idx) 6426 { 6427 int rv = BCM_E_NONE; 6428 ecmp_count_entry_t ecmp_group_entry; 6429 int dlb_enable; 6430 int dlb_id; 6431 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 6432 int entry_base_ptr; 6433 int flow_set_size; 6434 int num_entries; 6435 int block_base_ptr; 6436 int num_blocks; 6437 int vla; 6438 dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry; 6439 int member_bitmap_width; 6440 int alloc_size; 6441 SHR_BITDCL *member_bitmap = NULL; 6442 SHR_BITDCL *status_bitmap = NULL; 6443 SHR_BITDCL *override_bitmap = NULL; 6444 int i; 6445 int reverse_map_index; 6446 dlb_ecmp_member_attribute_entry_t dlb_ecmp_member_attribute_entry; 6447 ing_l3_next_hop_entry_t ing_nh_entry; 6448 int nh_index; 6449 bcm_module_t mod; 6450 bcm_port_t port; 6451 int is_local; 6452 dlb_ecmp_member_sw_state_entry_t dlb_ecmp_member_sw_state_entry; 6453 6454 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, 6455 ecmp_group_idx, &ecmp_group_entry)); 6456 dlb_enable = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 6457 GROUP_ENABLEf); 6458 dlb_id = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 6459 DLB_IDf); 6460 if (!dlb_enable) { 6461 return BCM_E_NONE; 6462 } 6463 6464 /* Clear DLB fields in ECMP group table */ 6465 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, GROUP_ENABLEf, 0); 6466 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, DLB_IDf, 0); 6467 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, 6468 ecmp_group_idx, &ecmp_group_entry)); 6469 6470 /* Clear VLA quality measure control */ 6471 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm(unit, 6472 MEM_BLOCK_ALL, dlb_id, 6473 soc_mem_entry_null(unit, 6474 DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm))); 6475 6476 /* Free flow set table resources */ 6477 SOC_IF_ERROR_RETURN 6478 (READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, dlb_id, 6479 &dlb_ecmp_group_control_entry)); 6480 entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 6481 &dlb_ecmp_group_control_entry, FLOW_SET_BASEf); 6482 flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 6483 &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf); 6484 BCM_IF_ERROR_RETURN 6485 (_bcm_tr3_ecmp_dlb_dynamic_size_decode(flow_set_size, &num_entries)); 6486 block_base_ptr = entry_base_ptr >> 9; 6487 num_blocks = num_entries >> 9; 6488 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks); 6489 6490 /* Clear ECMP DLB group control */ 6491 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_GROUP_CONTROLm(unit, 6492 MEM_BLOCK_ALL, dlb_id, 6493 soc_mem_entry_null(unit, DLB_ECMP_GROUP_CONTROLm))); 6494 6495 /* Get member bitmap */ 6496 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 6497 bcmSwitchEcmpDynamicAccountingSelect, &vla)); 6498 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY, 6499 dlb_id, &dlb_ecmp_group_membership_entry)); 6500 member_bitmap_width = soc_mem_field_length(unit, 6501 DLB_ECMP_GROUP_MEMBERSHIPm, MEMBER_BITMAPf); 6502 alloc_size = SHR_BITALLOCSIZE(member_bitmap_width); 6503 member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 6504 if (NULL == member_bitmap) { 6505 return BCM_E_MEMORY; 6506 } 6507 sal_memset(member_bitmap, 0, alloc_size); 6508 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit, 6509 &dlb_ecmp_group_membership_entry, MEMBER_BITMAPf, member_bitmap); 6510 6511 /* Free Member IDs */ 6512 for (i = 0; i < member_bitmap_width; i++) { 6513 if (SHR_BITGET(member_bitmap, i)) { 6514 6515 /* Clear membership reverse map */ 6516 rv = READ_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ANY, i, 6517 &dlb_ecmp_member_attribute_entry); 6518 if (BCM_FAILURE(rv)) { 6519 goto error; 6520 } 6521 nh_index = soc_DLB_ECMP_MEMBER_ATTRIBUTEm_field32_get(unit, 6522 &dlb_ecmp_member_attribute_entry, NEXT_HOP_INDEXf); 6523 if (vla) { 6524 reverse_map_index = i; 6525 } else { 6526 rv = READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_index, 6527 &ing_nh_entry); 6528 if (BCM_FAILURE(rv)) { 6529 goto error; 6530 } 6531 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 6532 MODULE_IDf); 6533 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 6534 PORT_NUMf); 6535 rv = _bcm_esw_modid_is_local(unit, mod, &is_local); 6536 if (BCM_FAILURE(rv)) { 6537 goto error; 6538 } 6539 if (!is_local) { 6540 rv = BCM_E_INTERNAL; 6541 goto error; 6542 } 6543 reverse_map_index = port; 6544 } 6545 rv = WRITE_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm(unit, MEM_BLOCK_ALL, 6546 reverse_map_index, soc_mem_entry_null(unit, 6547 DLB_ECMP_MEMBERSHIP_REVERSE_MAPm)); 6548 if (BCM_FAILURE(rv)) { 6549 goto error; 6550 } 6551 6552 /* Free next hop membership resource */ 6553 rv = _bcm_tr3_ecmp_dlb_nh_membership_free_resource(unit, nh_index, 6554 i, dlb_id); 6555 if (BCM_FAILURE(rv)) { 6556 goto error; 6557 } 6558 } 6559 } 6560 6561 rv = READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0, 6562 &dlb_ecmp_member_sw_state_entry); 6563 if (BCM_FAILURE(rv)) { 6564 goto error; 6565 } 6566 6567 /* Clear software status bitmap */ 6568 status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 6569 if (NULL == status_bitmap) { 6570 rv = BCM_E_MEMORY; 6571 goto error; 6572 } 6573 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, 6574 &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap); 6575 SHR_BITREMOVE_RANGE(status_bitmap, member_bitmap, 0, member_bitmap_width, 6576 status_bitmap); 6577 soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, 6578 &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap); 6579 6580 /* Clear software override bitmap */ 6581 override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 6582 if (NULL == override_bitmap) { 6583 rv = BCM_E_MEMORY; 6584 goto error; 6585 } 6586 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, 6587 &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf, 6588 override_bitmap); 6589 SHR_BITREMOVE_RANGE(override_bitmap, member_bitmap, 0, member_bitmap_width, 6590 override_bitmap); 6591 soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, 6592 &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf, 6593 override_bitmap); 6594 rv = WRITE_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ALL, 0, 6595 &dlb_ecmp_member_sw_state_entry); 6596 if (BCM_FAILURE(rv)) { 6597 goto error; 6598 } 6599 6600 sal_free(member_bitmap); 6601 sal_free(status_bitmap); 6602 sal_free(override_bitmap); 6603 6604 /* Clear group membership */ 6605 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit, 6606 MEM_BLOCK_ALL, dlb_id, 6607 soc_mem_entry_null(unit, DLB_ECMP_GROUP_MEMBERSHIPm))); 6608 6609 /* Free DLB ID */ 6610 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_id_free(unit, dlb_id)); 6611 6612 return rv; 6613 6614 error: 6615 if (NULL != member_bitmap) { 6616 sal_free(member_bitmap); 6617 } 6618 if (NULL != status_bitmap) { 6619 sal_free(status_bitmap); 6620 } 6621 if (NULL != override_bitmap) { 6622 sal_free(override_bitmap); 6623 } 6624 return rv; 6625 } 6626 6627 /* 6628 * Function: 6629 * _bcm_tr3_ecmp_dlb_member_id_array_get 6630 * Purpose: 6631 * Get member IDs for each ECMP member. 6632 * Parameters: 6633 * unit - (IN) SOC unit number. 6634 * dlb_id - (IN) DLB group ID. 6635 * intf_count - (IN) Number of elements in intf_array. 6636 * intf_array - (IN) Array of Egress forwarding objects. 6637 * member_id_array - (OUT) Array of member IDs. 6638 * Returns: 6639 * BCM_E_xxx 6640 */ 6641 STATIC int 6642 _bcm_tr3_ecmp_dlb_member_id_array_get(int unit, int dlb_id, int intf_count, 6643 bcm_if_t *intf_array, int *member_id_array) 6644 { 6645 int rv = BCM_E_NONE; 6646 int vla; 6647 int i, j; 6648 int nh_index; 6649 int match, match_index; 6650 _tr3_ecmp_dlb_nh_membership_t *current_ptr, *membership; 6651 int existing_member_id; 6652 dlb_ecmp_membership_reverse_map_entry_t member_reverse_map_entry; 6653 ing_l3_next_hop_entry_t ing_nh_entry; 6654 int mod, port; 6655 int is_local; 6656 port_tab_entry_t ptab; 6657 int scaling_factor, load_weight; 6658 6659 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 6660 bcmSwitchEcmpDynamicAccountingSelect, &vla)); 6661 6662 for (i = 0; i < intf_count; i++) { 6663 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) { 6664 nh_index = intf_array[i] - BCM_XGS3_EGRESS_IDX_MIN(unit); 6665 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) { 6666 nh_index = intf_array[i] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 6667 } else { 6668 return BCM_E_PARAM; 6669 } 6670 6671 /* Check if DLB attributes have been set for next hop index */ 6672 match = FALSE; 6673 match_index = 0; 6674 for (j = 0; j < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; j++) { 6675 if (ECMP_DLB_NH_INFO(unit, j).valid) { 6676 if (nh_index == ECMP_DLB_NH_INFO(unit, j).nh_index) { 6677 match = TRUE; 6678 match_index = j; 6679 } 6680 } 6681 } 6682 if (!match) { 6683 /* User did not configure DLB attributes for this next hop index */ 6684 return BCM_E_CONFIG; 6685 } 6686 6687 /* Look into next hop membership to see if a member ID has already 6688 * been assigned that does not yet belong to any group. 6689 */ 6690 current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6691 existing_member_id = -1; 6692 while (NULL != current_ptr) { 6693 if (-1 == current_ptr->group) { 6694 member_id_array[i] = current_ptr->member_id; 6695 current_ptr->group = dlb_id; 6696 break; 6697 } else { 6698 if (-1 == existing_member_id) { 6699 existing_member_id = current_ptr->member_id; 6700 } 6701 } 6702 current_ptr = current_ptr->next; 6703 } 6704 6705 /* If no available member ID was found, allocate a new DLB member ID, 6706 * set its DLB attributes, and insert it into next hop's linked list 6707 * of member IDs. 6708 */ 6709 if (NULL == current_ptr) { 6710 membership = sal_alloc(sizeof(_tr3_ecmp_dlb_nh_membership_t), 6711 "ecmp dlb nh membership"); 6712 if (NULL == membership) { 6713 return BCM_E_MEMORY; 6714 } 6715 rv = _bcm_tr3_ecmp_dlb_member_id_alloc(unit, &membership->member_id); 6716 if (BCM_FAILURE(rv)) { 6717 sal_free(membership); 6718 return rv; 6719 } 6720 rv = _bcm_tr3_ecmp_dlb_member_attr_get(unit, existing_member_id, 6721 &scaling_factor, &load_weight); 6722 if (BCM_FAILURE(rv)) { 6723 sal_free(membership); 6724 return rv; 6725 } 6726 rv = _bcm_tr3_ecmp_dlb_member_attr_set(unit, membership->member_id, 6727 nh_index, scaling_factor, load_weight); 6728 if (BCM_FAILURE(rv)) { 6729 sal_free(membership); 6730 return rv; 6731 } 6732 membership->group = dlb_id; 6733 membership->next = 6734 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 6735 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = membership; 6736 ECMP_DLB_NH_INFO(unit, match_index).nh_index = nh_index; 6737 ECMP_DLB_NH_INFO(unit, match_index).valid = 1; 6738 6739 member_id_array[i] = membership->member_id; 6740 } 6741 6742 /* Set member reverse map */ 6743 sal_memset(&member_reverse_map_entry, 0, 6744 sizeof(dlb_ecmp_membership_reverse_map_entry_t)); 6745 if (vla) { /* Virtual link accounting */ 6746 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit, 6747 &member_reverse_map_entry, VALIDf, 1); 6748 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit, 6749 &member_reverse_map_entry, GROUP_IDf, dlb_id); 6750 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit, 6751 &member_reverse_map_entry, MEMBER_COUNTf, 6752 intf_count - 1); 6753 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm(unit, 6754 MEM_BLOCK_ALL, member_id_array[i], 6755 &member_reverse_map_entry)); 6756 } else { /* Physical link accounting */ 6757 SOC_IF_ERROR_RETURN(READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 6758 nh_index, &ing_nh_entry)); 6759 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) { 6760 /* In physical link accounting mode, each next hop should 6761 * correspond to a single physical port. 6762 */ 6763 return BCM_E_CONFIG; 6764 } 6765 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 6766 MODULE_IDf); 6767 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 6768 PORT_NUMf); 6769 BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, mod, &is_local)); 6770 if (!is_local) { 6771 /* In physical link accounting mode, ECMP members should be 6772 * local. 6773 */ 6774 return BCM_E_PARAM; 6775 } 6776 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit, 6777 &member_reverse_map_entry, VALIDf, 1); 6778 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit, 6779 &member_reverse_map_entry, 6780 MEMBER_IDf, member_id_array[i]); 6781 SOC_IF_ERROR_RETURN 6782 (READ_PORT_TABm(unit, MEM_BLOCK_ANY, port, &ptab)); 6783 if (soc_PORT_TABm_field32_get(unit, &ptab, PORT_TYPEf) == 3) { 6784 /* Port is an embedded Higig port */ 6785 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit, 6786 &member_reverse_map_entry, EMBEDDED_HGf, 1); 6787 } 6788 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm(unit, 6789 MEM_BLOCK_ALL, port, &member_reverse_map_entry)); 6790 } 6791 } 6792 6793 return rv; 6794 } 6795 6796 /* 6797 * Function: 6798 * _bcm_tr3_ecmp_dlb_set 6799 * Purpose: 6800 * Configure an ECMP dynamic load balancing group. 6801 * Parameters: 6802 * unit - (IN) bcm device. 6803 * ecmp - (IN) ECMP group info. 6804 * intf_count - (IN) Number of elements in intf_array. 6805 * intf_array - (IN) Array of Egress forwarding objects. 6806 * Returns: 6807 * BCM_E_xxx 6808 */ 6809 STATIC int 6810 _bcm_tr3_ecmp_dlb_set(int unit, bcm_l3_egress_ecmp_t *ecmp, 6811 int intf_count, bcm_if_t *intf_array) 6812 { 6813 int rv = BCM_E_NONE; 6814 int dlb_id; 6815 int *member_id_array = NULL; 6816 soc_mem_t flowset_mem; 6817 int flowset_entry_size; 6818 dlb_ecmp_flowset_entry_t *flowset_entry; 6819 int num_blocks; 6820 int total_blocks; 6821 int max_block_base_ptr; 6822 int block_base_ptr; 6823 SHR_BITDCL occupied; 6824 int entry_base_ptr; 6825 int num_entries_per_block; 6826 int member_bitmap_width; 6827 int alloc_size; 6828 uint32 *block_ptr = NULL; 6829 int i, k; 6830 int index_min, index_max; 6831 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 6832 int flow_set_size; 6833 int dlb_mode; 6834 dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry; 6835 SHR_BITDCL *member_bitmap = NULL; 6836 SHR_BITDCL *status_bitmap = NULL; 6837 SHR_BITDCL *override_bitmap = NULL; 6838 dlb_ecmp_member_sw_state_entry_t dlb_ecmp_member_sw_state_entry; 6839 int vla; 6840 dlb_ecmp_vla_quality_measure_control_entry_t vla_quality_measure_control_entry; 6841 int ecmp_group_idx; 6842 ecmp_count_entry_t ecmp_group_entry; 6843 6844 /* Allocate a DLB ID */ 6845 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_id_alloc(unit, &dlb_id)); 6846 6847 /* Allocate member IDs */ 6848 member_id_array = sal_alloc(sizeof(int) * intf_count, 6849 "ECMP DLB Member IDs"); 6850 if (NULL == member_id_array) { 6851 rv = BCM_E_MEMORY; 6852 goto error; 6853 } 6854 rv = _bcm_tr3_ecmp_dlb_member_id_array_get(unit, dlb_id, intf_count, 6855 intf_array, member_id_array); 6856 if (BCM_FAILURE(rv)) { 6857 goto error; 6858 } 6859 6860 /* Set group membership table */ 6861 member_bitmap_width = soc_mem_field_length(unit, 6862 DLB_ECMP_GROUP_MEMBERSHIPm, MEMBER_BITMAPf); 6863 alloc_size = SHR_BITALLOCSIZE(member_bitmap_width); 6864 member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 6865 if (NULL == member_bitmap) { 6866 rv = BCM_E_MEMORY; 6867 goto error; 6868 } 6869 sal_memset(member_bitmap, 0, alloc_size); 6870 for (i = 0; i < intf_count; i++) { 6871 SHR_BITSET(member_bitmap, member_id_array[i]); 6872 } 6873 sal_memset(&dlb_ecmp_group_membership_entry, 0, 6874 sizeof(dlb_ecmp_group_membership_entry_t)); 6875 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_set(unit, 6876 &dlb_ecmp_group_membership_entry, MEMBER_BITMAPf, member_bitmap); 6877 rv = WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ALL, dlb_id, 6878 &dlb_ecmp_group_membership_entry); 6879 if (SOC_FAILURE(rv)) { 6880 goto error; 6881 } 6882 6883 /* Get software status bitmap */ 6884 rv = READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0, 6885 &dlb_ecmp_member_sw_state_entry); 6886 if (BCM_FAILURE(rv)) { 6887 goto error; 6888 } 6889 status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 6890 if (NULL == status_bitmap) { 6891 rv = BCM_E_MEMORY; 6892 goto error; 6893 } 6894 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, 6895 &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap); 6896 6897 /* Set software status bitmap */ 6898 rv = bcm_esw_switch_control_get(unit, 6899 bcmSwitchEcmpDynamicAccountingSelect, &vla); 6900 if (SOC_FAILURE(rv)) { 6901 goto error; 6902 } 6903 if (vla) { 6904 SHR_BITOR_RANGE(status_bitmap, member_bitmap, 0, member_bitmap_width, 6905 status_bitmap); 6906 } else { 6907 SHR_BITREMOVE_RANGE(status_bitmap, member_bitmap, 0, member_bitmap_width, 6908 status_bitmap); 6909 } 6910 soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, 6911 &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap); 6912 6913 /* Set software override bitmap */ 6914 override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 6915 if (NULL == override_bitmap) { 6916 rv = BCM_E_MEMORY; 6917 goto error; 6918 } 6919 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, 6920 &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf, 6921 override_bitmap); 6922 if (vla) { 6923 SHR_BITOR_RANGE(override_bitmap, member_bitmap, 0, member_bitmap_width, 6924 override_bitmap); 6925 } else { 6926 SHR_BITREMOVE_RANGE(override_bitmap, member_bitmap, 0, member_bitmap_width, 6927 override_bitmap); 6928 } 6929 soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, 6930 &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf, 6931 override_bitmap); 6932 rv = WRITE_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ALL, 0, 6933 &dlb_ecmp_member_sw_state_entry); 6934 if (BCM_FAILURE(rv)) { 6935 goto error; 6936 } 6937 6938 /* Find a contiguous region in flow set table */ 6939 flowset_mem = DLB_ECMP_FLOWSETm; 6940 flowset_entry_size = sizeof(dlb_ecmp_flowset_entry_t); 6941 num_blocks = ecmp->dynamic_size >> 9; 6942 total_blocks = soc_mem_index_count(unit, flowset_mem) >> 9; 6943 max_block_base_ptr = total_blocks - num_blocks; 6944 for (block_base_ptr = 0; 6945 block_base_ptr <= max_block_base_ptr; 6946 block_base_ptr++) { 6947 /* Check if the contiguous region of flow set table from 6948 * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 6949 */ 6950 _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks, 6951 occupied); 6952 if (!occupied) { 6953 break; 6954 } 6955 } 6956 if (block_base_ptr > max_block_base_ptr) { 6957 /* A contiguous region of the desired size could not be found in 6958 * flow set table. 6959 */ 6960 rv = BCM_E_RESOURCE; 6961 goto error; 6962 } 6963 6964 /* Set DLB flow set table */ 6965 entry_base_ptr = block_base_ptr << 9; 6966 num_entries_per_block = 512; 6967 alloc_size = num_entries_per_block * flowset_entry_size; 6968 block_ptr = soc_cm_salloc(unit, alloc_size, 6969 "Block of DLB_ECMP_FLOWSET entries"); 6970 if (NULL == block_ptr) { 6971 rv = BCM_E_MEMORY; 6972 goto error; 6973 } 6974 sal_memset(block_ptr, 0, alloc_size); 6975 for (i = 0; i < num_blocks; i++) { 6976 for (k = 0; k < num_entries_per_block; k++) { 6977 flowset_entry = soc_mem_table_idx_to_pointer(unit, 6978 DLB_ECMP_FLOWSETm, dlb_ecmp_flowset_entry_t *, 6979 block_ptr, k); 6980 if (intf_count > 0) { 6981 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry, 6982 VALIDf, 1); 6983 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry, 6984 MEMBER_IDf, 6985 member_id_array[(i * num_entries_per_block + k) % 6986 intf_count]); 6987 } else { 6988 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry, 6989 VALIDf, 0); 6990 } 6991 } 6992 index_min = entry_base_ptr + i * num_entries_per_block; 6993 index_max = index_min + num_entries_per_block - 1; 6994 rv = soc_mem_write_range(unit, flowset_mem, MEM_BLOCK_ALL, 6995 index_min, index_max, block_ptr); 6996 if (SOC_FAILURE(rv)) { 6997 goto error; 6998 } 6999 } 7000 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 7001 7002 /* Set ECMP DLB group control table */ 7003 sal_memset(&dlb_ecmp_group_control_entry, 0, 7004 sizeof(dlb_ecmp_group_control_entry_t)); 7005 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 7006 ENABLE_OPTIMAL_CANDIDATE_UPDATEf, 1); 7007 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 7008 FLOW_SET_BASEf, entry_base_ptr); 7009 rv = _bcm_tr3_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size, 7010 &flow_set_size); 7011 if (SOC_FAILURE(rv)) { 7012 goto error; 7013 } 7014 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 7015 FLOW_SET_SIZEf, flow_set_size); 7016 switch (ecmp->dynamic_mode) { 7017 case BCM_L3_ECMP_DYNAMIC_MODE_NORMAL: 7018 dlb_mode = 0; 7019 break; 7020 case BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED: 7021 dlb_mode = 1; 7022 break; 7023 case BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL: 7024 dlb_mode = 2; 7025 break; 7026 default: 7027 rv = BCM_E_PARAM; 7028 goto error; 7029 } 7030 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 7031 MEMBER_ASSIGNMENT_MODEf, dlb_mode); 7032 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 7033 INACTIVITY_DURATIONf, ecmp->dynamic_age); 7034 rv = WRITE_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, dlb_id, 7035 &dlb_ecmp_group_control_entry); 7036 if (SOC_FAILURE(rv)) { 7037 goto error; 7038 } 7039 7040 /* Set VLA quality measure control */ 7041 if (vla) { 7042 sal_memset(&vla_quality_measure_control_entry, 0, 7043 sizeof(dlb_ecmp_vla_quality_measure_control_entry_t)); 7044 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit, 7045 &vla_quality_measure_control_entry, 7046 ENABLE_GROUP_AVG_CALCf, 1); 7047 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit, 7048 &vla_quality_measure_control_entry, 7049 VLA_WEIGHT_LOADINGf, ecmp->dynamic_load_exponent); 7050 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit, 7051 &vla_quality_measure_control_entry, 7052 VLA_WEIGHT_EXPECTED_LOADINGf, 7053 ecmp->dynamic_expected_load_exponent); 7054 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit, 7055 &vla_quality_measure_control_entry, 7056 VLA_CAP_LOADING_AVGf, (ecmp->ecmp_group_flags & 7057 BCM_L3_ECMP_DYNAMIC_LOAD_DECREASE_RESET) ? 1 : 0); 7058 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit, 7059 &vla_quality_measure_control_entry, 7060 VLA_CAP_EXPECTED_LOADINGf, (ecmp->ecmp_group_flags & 7061 BCM_L3_ECMP_DYNAMIC_EXPECTED_LOAD_DECREASE_RESET) ? 7062 1 : 0); 7063 rv = WRITE_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm(unit, MEM_BLOCK_ALL, 7064 dlb_id, &vla_quality_measure_control_entry); 7065 if (SOC_FAILURE(rv)) { 7066 goto error; 7067 } 7068 } 7069 7070 /* Update ECMP group table */ 7071 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 7072 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, 7073 &ecmp_group_entry); 7074 if (SOC_FAILURE(rv)) { 7075 goto error; 7076 } 7077 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, GROUP_ENABLEf, 1); 7078 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, DLB_IDf, dlb_id); 7079 rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_group_idx, 7080 &ecmp_group_entry); 7081 if (SOC_FAILURE(rv)) { 7082 goto error; 7083 } 7084 7085 sal_free(member_id_array); 7086 soc_cm_sfree(unit, block_ptr); 7087 sal_free(member_bitmap); 7088 sal_free(status_bitmap); 7089 sal_free(override_bitmap); 7090 7091 return rv; 7092 7093 error: 7094 if (NULL != member_id_array) { 7095 sal_free(member_id_array); 7096 } 7097 if (NULL != block_ptr) { 7098 soc_cm_sfree(unit, block_ptr); 7099 } 7100 if (NULL != member_bitmap) { 7101 sal_free(member_bitmap); 7102 } 7103 if (NULL != status_bitmap) { 7104 sal_free(status_bitmap); 7105 } 7106 if (NULL != override_bitmap) { 7107 sal_free(override_bitmap); 7108 } 7109 return rv; 7110 } 7111 7112 /* 7113 * Function: 7114 * bcm_tr3_l3_egress_ecmp_dlb_create 7115 * Purpose: 7116 * Create ECMP DLB group. 7117 * Parameters: 7118 * unit - (IN) bcm device. 7119 * ecmp - (IN) ECMP group info. 7120 * intf_count - (IN) Number of elements in intf_array. 7121 * intf_array - (IN) Array of Egress forwarding objects. 7122 * Returns: 7123 * BCM_E_XXX 7124 */ 7125 int 7126 bcm_tr3_l3_egress_ecmp_dlb_create(int unit, bcm_l3_egress_ecmp_t *ecmp, 7127 int intf_count, bcm_if_t *intf_array) 7128 { 7129 int dlb_enable; 7130 int dynamic_size_encode; 7131 int ecmp_group_idx; 7132 7133 if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_NORMAL) || 7134 (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED) || 7135 (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL)) { 7136 dlb_enable = 1; 7137 } else { 7138 dlb_enable = 0; 7139 } 7140 7141 if (dlb_enable) { 7142 /* Verify dynamic_size */ 7143 BCM_IF_ERROR_RETURN 7144 (_bcm_tr3_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size, 7145 &dynamic_size_encode)); 7146 7147 /* Verify dynamic_age */ 7148 /* Error rate in calculating INACTIVITY_DURATION is higher 7149 if it is allowed to be configured too low. 7150 Minimum limit of 16 microseconds is required to reduce 7151 the error rate in time duration calculation.*/ 7152 if ((ecmp->dynamic_age < 16) || 7153 (ecmp->dynamic_age > 0x3ffff)) { 7154 return BCM_E_PARAM; 7155 } 7156 7157 /* Verify dynamic exponents */ 7158 if (ecmp->dynamic_load_exponent > 0xf) { 7159 return BCM_E_PARAM; 7160 } 7161 if (ecmp->dynamic_expected_load_exponent > 0xf) { 7162 return BCM_E_PARAM; 7163 } 7164 } 7165 7166 /* Free resources associated with old DLB group, if exists */ 7167 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 7168 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_free_resource(unit, ecmp_group_idx)); 7169 7170 /* Set new DLB group */ 7171 if (dlb_enable) { 7172 BCM_IF_ERROR_RETURN 7173 (_bcm_tr3_ecmp_dlb_set(unit, ecmp, intf_count, intf_array)); 7174 } 7175 7176 return BCM_E_NONE; 7177 } 7178 7179 /* 7180 * Function: 7181 * bcm_tr3_l3_egress_ecmp_dlb_destroy 7182 * Purpose: 7183 * Destroy an ECMP DLB group. 7184 * Parameters: 7185 * unit - (IN) bcm device. 7186 * mpintf - (IN) ECMP group info. 7187 * Returns: 7188 * BCM_E_XXX 7189 */ 7190 int 7191 bcm_tr3_l3_egress_ecmp_dlb_destroy(int unit, bcm_if_t mpintf) 7192 { 7193 int ecmp_group; 7194 7195 /* Free resources associated with old DLB group, if exists */ 7196 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) { 7197 ecmp_group = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 7198 } else { 7199 return BCM_E_PARAM; 7200 } 7201 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_free_resource(unit, ecmp_group)); 7202 7203 return BCM_E_NONE; 7204 } 7205 7206 /* 7207 * Function: 7208 * bcm_tr3_l3_egress_ecmp_dlb_get 7209 * Purpose: 7210 * Get info about an ECMP DLB group. 7211 * Parameters: 7212 * unit - (IN) bcm device. 7213 * ecmp - (INOUT) ECMP group info. 7214 * Returns: 7215 * BCM_E_XXX 7216 */ 7217 int 7218 bcm_tr3_l3_egress_ecmp_dlb_get(int unit, bcm_l3_egress_ecmp_t *ecmp) 7219 { 7220 int ecmp_group_idx; 7221 ecmp_count_entry_t ecmp_group_entry; 7222 int group_enable, dlb_id; 7223 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 7224 int dlb_mode; 7225 int flow_set_size; 7226 dlb_ecmp_vla_quality_measure_control_entry_t vla_quality_measure_control_entry; 7227 7228 /* Get DLB ID */ 7229 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 7230 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, 7231 ecmp_group_idx, &ecmp_group_entry)); 7232 group_enable = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 7233 GROUP_ENABLEf); 7234 if (!group_enable) { 7235 ecmp->dynamic_mode = 0; 7236 ecmp->dynamic_size = 0; 7237 ecmp->dynamic_age = 0; 7238 ecmp->dynamic_load_exponent = 0; 7239 ecmp->dynamic_expected_load_exponent = 0; 7240 return BCM_E_NONE; 7241 } 7242 dlb_id = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, DLB_IDf); 7243 7244 /* Get dynamic_mode */ 7245 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, 7246 dlb_id, &dlb_ecmp_group_control_entry)); 7247 dlb_mode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7248 &dlb_ecmp_group_control_entry, MEMBER_ASSIGNMENT_MODEf); 7249 switch (dlb_mode) { 7250 case 0: 7251 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_NORMAL; 7252 break; 7253 case 1: 7254 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED; 7255 break; 7256 case 2: 7257 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL; 7258 break; 7259 default: 7260 return BCM_E_INTERNAL; 7261 } 7262 7263 /* Get dynamic_size */ 7264 flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7265 &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf); 7266 BCM_IF_ERROR_RETURN 7267 (_bcm_tr3_ecmp_dlb_dynamic_size_decode(flow_set_size, 7268 (int *)&ecmp->dynamic_size)); 7269 7270 /* Get dynamic_age */ 7271 ecmp->dynamic_age = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7272 &dlb_ecmp_group_control_entry, INACTIVITY_DURATIONf); 7273 7274 /* Get dynamic exponents and ecmp_group_flags */ 7275 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm(unit, 7276 MEM_BLOCK_ANY, dlb_id, &vla_quality_measure_control_entry)); 7277 ecmp->dynamic_load_exponent = 7278 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit, 7279 &vla_quality_measure_control_entry, VLA_WEIGHT_LOADINGf); 7280 ecmp->dynamic_expected_load_exponent = 7281 soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit, 7282 &vla_quality_measure_control_entry, VLA_WEIGHT_EXPECTED_LOADINGf); 7283 if (soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit, 7284 &vla_quality_measure_control_entry, VLA_CAP_LOADING_AVGf)) { 7285 ecmp->ecmp_group_flags |= BCM_L3_ECMP_DYNAMIC_LOAD_DECREASE_RESET; 7286 } 7287 if (soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit, 7288 &vla_quality_measure_control_entry, 7289 VLA_CAP_EXPECTED_LOADINGf)) { 7290 ecmp->ecmp_group_flags |= 7291 BCM_L3_ECMP_DYNAMIC_EXPECTED_LOAD_DECREASE_RESET; 7292 } 7293 7294 return BCM_E_NONE; 7295 } 7296 7297 /* 7298 * Function: 7299 * bcm_tr3_l3_egress_ecmp_member_status_set 7300 * Purpose: 7301 * Set ECMP DLB member status. 7302 * Parameters: 7303 * unit - (IN) SOC unit number. 7304 * intf - (IN) L3 Interface ID pointing to an Egress forwarding object. 7305 * status - (IN) ECMP member status. 7306 * Returns: 7307 * BCM_E_xxx 7308 */ 7309 int 7310 bcm_tr3_l3_egress_ecmp_member_status_set(int unit, bcm_if_t intf, int status) 7311 { 7312 int nh_index; 7313 dlb_ecmp_member_sw_state_entry_t sw_state_entry; 7314 int member_bitmap_width, alloc_size; 7315 SHR_BITDCL *status_bitmap = NULL; 7316 SHR_BITDCL *override_bitmap = NULL; 7317 int dlb_group_valid; 7318 int i; 7319 _tr3_ecmp_dlb_nh_membership_t *current_ptr; 7320 7321 /* Derive next hop index */ 7322 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 7323 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 7324 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 7325 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 7326 } else { 7327 return BCM_E_PARAM; 7328 } 7329 7330 /* Get status bitmap */ 7331 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0, 7332 &sw_state_entry)); 7333 member_bitmap_width = soc_mem_field_length(unit, DLB_ECMP_MEMBER_SW_STATEm, 7334 MEMBER_BITMAPf); 7335 alloc_size = SHR_BITALLOCSIZE(member_bitmap_width); 7336 status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 7337 if (NULL == status_bitmap) { 7338 return BCM_E_MEMORY; 7339 } 7340 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry, 7341 MEMBER_BITMAPf, status_bitmap); 7342 7343 /* Get override bitmap */ 7344 override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 7345 if (NULL == override_bitmap) { 7346 sal_free(status_bitmap); 7347 return BCM_E_MEMORY; 7348 } 7349 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry, 7350 OVERRIDE_MEMBER_BITMAPf, override_bitmap); 7351 7352 /* Update status and override bitmaps for any of the next hop's DLB 7353 * member IDs that belong to an ECMP DLB group. 7354 */ 7355 dlb_group_valid = FALSE; 7356 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 7357 if (ECMP_DLB_NH_INFO(unit, i).valid) { 7358 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 7359 current_ptr = ECMP_DLB_NH_INFO(unit, i).nh_membership_list; 7360 while (NULL != current_ptr) { 7361 if (current_ptr->group != -1) { 7362 dlb_group_valid = TRUE; 7363 switch (status) { 7364 case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN: 7365 SHR_BITSET(override_bitmap, 7366 current_ptr->member_id); 7367 SHR_BITCLR(status_bitmap, 7368 current_ptr->member_id); 7369 break; 7370 case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP: 7371 SHR_BITSET(override_bitmap, 7372 current_ptr->member_id); 7373 SHR_BITSET(status_bitmap, 7374 current_ptr->member_id); 7375 break; 7376 case BCM_L3_ECMP_DYNAMIC_MEMBER_HW: 7377 SHR_BITCLR(override_bitmap, 7378 current_ptr->member_id); 7379 SHR_BITCLR(status_bitmap, 7380 current_ptr->member_id); 7381 break; 7382 default: 7383 sal_free(status_bitmap); 7384 sal_free(override_bitmap); 7385 return BCM_E_PARAM; 7386 } 7387 } 7388 current_ptr = current_ptr->next; 7389 } 7390 break; 7391 } 7392 } 7393 } 7394 if (!dlb_group_valid) { 7395 /* The given intf was not a member of any DLB group */ 7396 sal_free(status_bitmap); 7397 sal_free(override_bitmap); 7398 return BCM_E_NOT_FOUND; 7399 } 7400 7401 /* Write status and override bitmaps to hardware */ 7402 soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, &sw_state_entry, 7403 MEMBER_BITMAPf, status_bitmap); 7404 soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, &sw_state_entry, 7405 OVERRIDE_MEMBER_BITMAPf, override_bitmap); 7406 sal_free(status_bitmap); 7407 sal_free(override_bitmap); 7408 SOC_IF_ERROR_RETURN 7409 (WRITE_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ALL, 0, 7410 &sw_state_entry)); 7411 7412 return BCM_E_NONE; 7413 } 7414 7415 /* 7416 * Function: 7417 * bcm_tr3_l3_egress_ecmp_member_status_get 7418 * Purpose: 7419 * Get ECMP DLB member status. 7420 * Parameters: 7421 * unit - (IN) SOC unit number. 7422 * intf - (IN) L3 Interface ID pointing to an Egress forwarding object. 7423 * status - (OUT) ECMP member status. 7424 * Returns: 7425 * BCM_E_xxx 7426 */ 7427 int 7428 bcm_tr3_l3_egress_ecmp_member_status_get(int unit, bcm_if_t intf, int *status) 7429 { 7430 int rv = BCM_E_NONE; 7431 int nh_index; 7432 int member_id; 7433 int i; 7434 _tr3_ecmp_dlb_nh_membership_t *current_ptr; 7435 dlb_ecmp_member_sw_state_entry_t sw_state_entry; 7436 int member_bitmap_width, alloc_size; 7437 SHR_BITDCL *status_bitmap = NULL; 7438 SHR_BITDCL *override_bitmap = NULL; 7439 uint64 hw_state, hw_status_bitmap; 7440 uint32 bitmap32; 7441 7442 if (NULL == status) { 7443 return BCM_E_PARAM; 7444 } 7445 7446 /* Derive next hop index */ 7447 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 7448 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 7449 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 7450 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 7451 } else { 7452 return BCM_E_PARAM; 7453 } 7454 7455 /* Find next hop's DLB member ID */ 7456 member_id = -1; 7457 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 7458 if (ECMP_DLB_NH_INFO(unit, i).valid) { 7459 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 7460 current_ptr = ECMP_DLB_NH_INFO(unit, i).nh_membership_list; 7461 while (NULL != current_ptr) { 7462 if (current_ptr->group != -1) { 7463 member_id = current_ptr->member_id; 7464 break; 7465 } 7466 current_ptr = current_ptr->next; 7467 } 7468 break; 7469 } 7470 } 7471 } 7472 if (-1 == member_id) { 7473 /* The given intf was not a member of any DLB group */ 7474 return BCM_E_NOT_FOUND; 7475 } 7476 7477 /* Get status bitmap */ 7478 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0, 7479 &sw_state_entry)); 7480 member_bitmap_width = soc_mem_field_length(unit, DLB_ECMP_MEMBER_SW_STATEm, 7481 MEMBER_BITMAPf); 7482 alloc_size = SHR_BITALLOCSIZE(member_bitmap_width); 7483 status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 7484 if (NULL == status_bitmap) { 7485 return BCM_E_MEMORY; 7486 } 7487 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry, 7488 MEMBER_BITMAPf, status_bitmap); 7489 7490 /* Get override bitmap */ 7491 override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 7492 if (NULL == override_bitmap) { 7493 sal_free(status_bitmap); 7494 return BCM_E_MEMORY; 7495 } 7496 soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry, 7497 OVERRIDE_MEMBER_BITMAPf, override_bitmap); 7498 7499 /* Derive status from software override and status bitmaps or 7500 * hardware state bitmap. 7501 */ 7502 if (SHR_BITGET(override_bitmap, member_id)) { 7503 if (SHR_BITGET(status_bitmap, member_id)) { 7504 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP; 7505 } else { 7506 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN; 7507 } 7508 } else { 7509 rv = READ_DLB_ECMP_MEMBER_HW_STATE_64r(unit, &hw_state); 7510 if (SOC_FAILURE(rv)) { 7511 sal_free(status_bitmap); 7512 sal_free(override_bitmap); 7513 return rv; 7514 } 7515 hw_status_bitmap = soc_reg64_field_get(unit, 7516 DLB_ECMP_MEMBER_HW_STATE_64r, hw_state, BITMAPf); 7517 if (member_id < 32) { 7518 bitmap32 = COMPILER_64_LO(hw_status_bitmap); 7519 } else { 7520 bitmap32 = COMPILER_64_HI(hw_status_bitmap); 7521 member_id -= 32; 7522 } 7523 if ((1 << member_id) & bitmap32) { 7524 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_UP; 7525 } else { 7526 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_DOWN; 7527 } 7528 } 7529 7530 /* Cleanup */ 7531 if (status_bitmap) { 7532 sal_free(status_bitmap); 7533 } 7534 7535 if (override_bitmap) { 7536 sal_free(override_bitmap); 7537 } 7538 7539 return rv; 7540 } 7541 /* 7542 * Function: 7543 * bcm_tr3_l3_egress_ecmp_dlb_ethertype_set 7544 * Purpose: 7545 * Set the Ethertypes that are eligible or ineligible for 7546 * ECMP dynamic load balancing. 7547 * Parameters: 7548 * unit - (IN) Unit number. 7549 * flags - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags. 7550 * ethertype_count - (IN) Number of elements in ethertype_array. 7551 * ethertype_array - (IN) Array of Ethertypes. 7552 * Returns: 7553 * BCM_E_XXX 7554 */ 7555 int 7556 bcm_tr3_l3_egress_ecmp_dlb_ethertype_set( 7557 int unit, 7558 uint32 flags, 7559 int ethertype_count, 7560 int *ethertype_array) 7561 { 7562 uint32 measure_control_reg; 7563 int i, j; 7564 dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry; 7565 7566 /* Input check */ 7567 if ((ethertype_count > 0) && (NULL == ethertype_array)) { 7568 return BCM_E_PARAM; 7569 } 7570 if (ethertype_count > soc_mem_index_count(unit, 7571 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)) { 7572 return BCM_E_RESOURCE; 7573 } 7574 7575 /* Update quality measure control register */ 7576 SOC_IF_ERROR_RETURN 7577 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 7578 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7579 &measure_control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf, 7580 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0); 7581 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7582 &measure_control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf, 7583 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0); 7584 SOC_IF_ERROR_RETURN 7585 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 7586 7587 /* Update Ethertype eligibility map table */ 7588 for (i = 0; i < ethertype_count; i++) { 7589 sal_memset(ðertype_entry, 0, 7590 sizeof(dlb_ecmp_ethertype_eligibility_map_entry_t)); 7591 soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 7592 ðertype_entry, VALIDf, 1); 7593 soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 7594 ðertype_entry, ETHERTYPEf, ethertype_array[i]); 7595 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 7596 MEM_BLOCK_ALL, i, ðertype_entry)); 7597 } 7598 7599 /* Zero out remaining entries of Ethertype eligibility map table */ 7600 for (j = i; j < soc_mem_index_count(unit, 7601 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); j++) { 7602 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 7603 MEM_BLOCK_ALL, j, soc_mem_entry_null(unit, 7604 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm))); 7605 } 7606 7607 return BCM_E_NONE; 7608 } 7609 7610 /* 7611 * Function: 7612 * bcm_tr3_l3_egress_ecmp_dlb_ethertype_get 7613 * Purpose: 7614 * Get the Ethertypes that are eligible or ineligible for 7615 * ECMP dynamic load balancing. 7616 * Parameters: 7617 * unit - (IN) Unit number. 7618 * flags - (INOUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags. 7619 * ethertype_max - (IN) Number of elements in ethertype_array. 7620 * ethertype_array - (OUT) Array of Ethertypes. 7621 * ethertype_count - (OUT) Number of elements returned in ethertype_array. 7622 * Returns: 7623 * BCM_E_XXX 7624 */ 7625 int 7626 bcm_tr3_l3_egress_ecmp_dlb_ethertype_get( 7627 int unit, 7628 uint32 *flags, 7629 int ethertype_max, 7630 int *ethertype_array, 7631 int *ethertype_count) 7632 { 7633 uint32 measure_control_reg; 7634 int i; 7635 int ethertype; 7636 dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry; 7637 7638 /* Input check */ 7639 if (NULL == flags) { 7640 return BCM_E_PARAM; 7641 } 7642 if ((ethertype_max > 0) && (NULL == ethertype_array)) { 7643 return BCM_E_PARAM; 7644 } 7645 if (NULL == ethertype_count) { 7646 return BCM_E_PARAM; 7647 } 7648 7649 *ethertype_count = 0; 7650 7651 /* Get flags */ 7652 SOC_IF_ERROR_RETURN 7653 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 7654 if (soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7655 measure_control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) { 7656 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE; 7657 } 7658 if (soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7659 measure_control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) { 7660 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER; 7661 } 7662 7663 /* Get Ethertypes */ 7664 for (i = 0; i < soc_mem_index_count(unit, 7665 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); i++) { 7666 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 7667 MEM_BLOCK_ANY, i, ðertype_entry)); 7668 if (soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 7669 ðertype_entry, VALIDf)) { 7670 ethertype = soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 7671 ðertype_entry, ETHERTYPEf); 7672 if (NULL != ethertype_array) { 7673 ethertype_array[*ethertype_count] = ethertype; 7674 } 7675 (*ethertype_count)++; 7676 if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) { 7677 break; 7678 } 7679 } 7680 } 7681 7682 return BCM_E_NONE; 7683 } 7684 7685 /* 7686 * Function: 7687 * _bcm_tr3_ecmp_dlb_accounting_set 7688 * Purpose: 7689 * Set ECMP DLB accounting mode. 7690 * Parameters: 7691 * unit - (IN) SOC unit number. 7692 * accounting_mode - (IN) Accounting mode. 7693 * Returns: 7694 * BCM_E_xxx 7695 */ 7696 STATIC int 7697 _bcm_tr3_ecmp_dlb_accounting_set(int unit, int accounting_mode) 7698 { 7699 uint32 measure_control_reg; 7700 int old_accounting_mode; 7701 SHR_BITDCL active; 7702 7703 SOC_IF_ERROR_RETURN 7704 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 7705 old_accounting_mode = soc_reg_field_get(unit, 7706 DLB_ECMP_QUALITY_MEASURE_CONTROLr, measure_control_reg, 7707 ACCOUNTING_SELf); 7708 if (old_accounting_mode == accounting_mode) { 7709 return BCM_E_NONE; 7710 } 7711 7712 SHR_BITTEST_RANGE(ECMP_DLB_INFO(unit)->ecmp_dlb_id_used_bitmap, 7713 0, soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm), active); 7714 if (active) { 7715 /* Accounting mode cannot be changed while there are active 7716 * DLB groups. 7717 */ 7718 return BCM_E_BUSY; 7719 } 7720 7721 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7722 &measure_control_reg, ACCOUNTING_SELf, accounting_mode); 7723 if (accounting_mode) { /* virtual link accounting */ 7724 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7725 &measure_control_reg, INST_METRIC_UPDATE_INTERVALf, 1); 7726 } else { /* physical link accounting */ 7727 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7728 &measure_control_reg, INST_METRIC_UPDATE_INTERVALf, 0); 7729 } 7730 SOC_IF_ERROR_RETURN 7731 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 7732 7733 return BCM_E_NONE; 7734 } 7735 7736 /* 7737 * Function: 7738 * _bcm_tr3_ecmp_dlb_accounting_get 7739 * Purpose: 7740 * Get ECMP DLB accounting mode. 7741 * Parameters: 7742 * unit - (IN) SOC unit number. 7743 * accounting_mode - (OUT) Accounting mode. 7744 * Returns: 7745 * BCM_E_xxx 7746 */ 7747 STATIC int 7748 _bcm_tr3_ecmp_dlb_accounting_get(int unit, int *accounting_mode) 7749 { 7750 uint32 measure_control_reg; 7751 7752 SOC_IF_ERROR_RETURN 7753 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 7754 *accounting_mode = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7755 measure_control_reg, ACCOUNTING_SELf); 7756 7757 return BCM_E_NONE; 7758 } 7759 7760 /* 7761 * Function: 7762 * _bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set 7763 * Purpose: 7764 * Set ECMP DLB sample period and physical link accounting thresholds. 7765 * Parameters: 7766 * unit - (IN) SOC unit number. 7767 * sample_rate - (IN) Number of samplings per second. 7768 * min_th - (IN) Minimum port load threshold, in mbps. 7769 * max_th - (IN) Maximum port load threshold, in mbps. 7770 * Returns: 7771 * BCM_E_xxx 7772 */ 7773 STATIC int 7774 _bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(int unit, int sample_rate, 7775 int min_th, int max_th) 7776 { 7777 int num_time_units; 7778 uint32 measure_control_reg; 7779 int max_th_bytes; 7780 int th_increment; 7781 dlb_ecmp_pla_quantize_threshold_entry_t quantize_threshold_entry; 7782 int i; 7783 int th_bytes[7]; 7784 7785 if (sample_rate <= 0 || min_th < 0 || max_th < 0) { 7786 return BCM_E_PARAM; 7787 } 7788 7789 if (min_th > max_th) { 7790 max_th = min_th; 7791 } 7792 7793 /* Compute sampling period in units of 1us: 7794 * number of 1us time units = 10^6 / sample_rate 7795 */ 7796 num_time_units = 1000000 / sample_rate; 7797 if (num_time_units < 1 || num_time_units > 0x3fff) { 7798 /* Hardware limits the sampling period to 14 bits */ 7799 return BCM_E_PARAM; 7800 } 7801 SOC_IF_ERROR_RETURN 7802 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 7803 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7804 &measure_control_reg, HISTORICAL_SAMPLING_PERIODf, num_time_units); 7805 SOC_IF_ERROR_RETURN 7806 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 7807 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = sample_rate; 7808 7809 /* Compute threshold in bytes per sampling period: 7810 * bytes per 1us = (million bits per sec) * 10^6 / 8 * 10^(-6), 7811 * bytes per sampling period = (bytes per 1us) * (number of 1us 7812 * time units in sampling period) 7813 * = mbps * num_time_units / 8 7814 */ 7815 max_th_bytes = max_th * num_time_units / 8; 7816 7817 if (max_th_bytes > 0x3fffffff) { 7818 /* Hardware limits port load threshold to 30 bits */ 7819 return BCM_E_PARAM; 7820 } 7821 7822 /* Use min threshold as threshold 0, and max threshold as threshold 6. 7823 * Thresholds 1 to 5 will be evenly spread out between min and max 7824 * thresholds. 7825 */ 7826 th_increment = (max_th - min_th) / 6; 7827 for (i = 0; i < 7; i++) { 7828 SOC_IF_ERROR_RETURN 7829 (READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i, 7830 &quantize_threshold_entry)); 7831 th_bytes[i] = (min_th + i * th_increment) * num_time_units / 8; 7832 soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_set 7833 (unit, &quantize_threshold_entry, THRESHOLD_HIST_LOADf, 7834 th_bytes[i]); 7835 SOC_IF_ERROR_RETURN 7836 (WRITE_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i, 7837 &quantize_threshold_entry)); 7838 } 7839 7840 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = min_th; 7841 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = max_th; 7842 7843 return BCM_E_NONE; 7844 } 7845 7846 /* 7847 * Function: 7848 * _bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set 7849 * Purpose: 7850 * Set ECMP DLB sample period and virtual link accounting thresholds. 7851 * Parameters: 7852 * unit - (IN) SOC unit number. 7853 * sample_rate - (IN) Number of samplings per second. 7854 * exp_load_min_th - (IN) Minimum expected load threshold, in mbps. 7855 * exp_load_max_th - (IN) Maximum expected load threshold, in mbps. 7856 * imbalance_min_th - (IN) Minimum member imbalance threshold, 7857 * in percentage. 7858 * imbalance_max_th - (IN) Maximum member imbalance threshold. 7859 * in percentage. 7860 * Returns: 7861 * BCM_E_xxx 7862 */ 7863 STATIC int 7864 _bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(int unit, int sample_rate, 7865 int exp_load_min_th, int exp_load_max_th, 7866 int imbalance_min_th, int imbalance_max_th) 7867 { 7868 int num_time_units; 7869 uint32 measure_control_reg; 7870 int exp_load_max_th_kbytes; 7871 int num_exp_load_th; 7872 int exp_load_th_increment; 7873 dlb_ecmp_vla_expected_loading_threshold_entry_t exp_load_threshold_entry; 7874 int exp_load_th_kbytes; 7875 int num_imbalance_th; 7876 int imbalance_th_increment; 7877 int imbalance_max_th_kbytes; 7878 int imbalance_th_kbytes; 7879 dlb_ecmp_vla_member_imbalance_threshold_entry_t imbalance_threshold_entry; 7880 int i, j; 7881 int imbalance_th_fields[7] = {THRESHOLD_0f, THRESHOLD_1f, THRESHOLD_2f, 7882 THRESHOLD_3f, THRESHOLD_4f, THRESHOLD_5f, 7883 THRESHOLD_6f}; 7884 7885 if (sample_rate <= 0 || exp_load_min_th < 0 || exp_load_max_th < 0) { 7886 return BCM_E_PARAM; 7887 } 7888 7889 if (exp_load_min_th > exp_load_max_th) { 7890 exp_load_max_th = exp_load_min_th; 7891 } 7892 7893 if (imbalance_min_th > imbalance_max_th) { 7894 imbalance_max_th = imbalance_min_th; 7895 } 7896 7897 /* Compute sampling period in units of 1us: 7898 * number of 1us time units = 10^6 / sample_rate 7899 */ 7900 num_time_units = 1000000 / sample_rate; 7901 if (num_time_units < 1 || num_time_units > 0x3fff) { 7902 /* Hardware limits the sampling period to 14 bits */ 7903 return BCM_E_PARAM; 7904 } 7905 SOC_IF_ERROR_RETURN 7906 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 7907 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7908 &measure_control_reg, HISTORICAL_SAMPLING_PERIODf, num_time_units); 7909 SOC_IF_ERROR_RETURN 7910 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 7911 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = sample_rate; 7912 7913 /* Compute expected loading threshold in kbytes per sampling period: 7914 * bytes per 1us = (million bits per sec) * 10^6 / 8 * 10^(-6) 7915 * = mbps / 8. 7916 * bytes per sampling period = (bytes per 1us) * (number of 1us 7917 * time units in sampling period) 7918 * = mbps * num_time_units / 8. 7919 * kbytes per sampling period = mbps * num_times_units / 8000. 7920 */ 7921 exp_load_max_th_kbytes = exp_load_max_th * num_time_units / 8000; 7922 if (exp_load_max_th_kbytes > 0xfffff) { 7923 /* Hardware limits expected loading threshold in kbytes to 20 bits */ 7924 return BCM_E_PARAM; 7925 } 7926 7927 /* Use expected load min threshold as threshold 0, and max threshold as 7928 * threshold 14. Thresholds 1 to 13 will be evenly spread out between them. 7929 */ 7930 num_exp_load_th = soc_mem_index_count(unit, 7931 DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm); 7932 exp_load_th_increment = (exp_load_max_th - exp_load_min_th) / 7933 (num_exp_load_th - 1); 7934 for (i = 0; i < num_exp_load_th; i++) { 7935 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit, 7936 MEM_BLOCK_ANY, i, &exp_load_threshold_entry)); 7937 exp_load_th_kbytes = (exp_load_min_th + i * exp_load_th_increment) * 7938 num_time_units / 8000; 7939 soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_set 7940 (unit, &exp_load_threshold_entry, THRESHOLDf, exp_load_th_kbytes); 7941 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit, 7942 MEM_BLOCK_ALL, i, &exp_load_threshold_entry)); 7943 } 7944 7945 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th = exp_load_min_th; 7946 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th = exp_load_max_th; 7947 7948 /* Use member imbalance min threshold as threshold 0, and max threshold as 7949 * threshold 6. Thresholds 1 to 5 will be evenly spread out between them. 7950 */ 7951 num_imbalance_th = 7; 7952 imbalance_th_increment = (imbalance_max_th - imbalance_min_th) / 7953 (num_imbalance_th - 1); 7954 for (i = 0; 7955 i < soc_mem_index_count(unit, 7956 DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm); 7957 i++) { 7958 /* There are 16 sets of member imbalance thresholds. 7959 * For sets 0 to 14, use expected loading thresholds 0 to 14 from 7960 * DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLD table as the 7961 * expected load. For set 15, extrapolate the expected load. 7962 */ 7963 if (i < num_exp_load_th) { 7964 SOC_IF_ERROR_RETURN 7965 (READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit, 7966 MEM_BLOCK_ANY, i, &exp_load_threshold_entry)); 7967 exp_load_th_kbytes = 7968 soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_get(unit, 7969 &exp_load_threshold_entry, THRESHOLDf); 7970 } else { 7971 exp_load_th_kbytes = 7972 (exp_load_min_th + num_exp_load_th * exp_load_th_increment) * 7973 num_time_units / 8000; 7974 } 7975 7976 /* Compute member imbalance thresholds */ 7977 imbalance_max_th_kbytes = exp_load_th_kbytes * imbalance_max_th / 100; 7978 if (imbalance_max_th_kbytes > 0xfffff) { 7979 /* Hardware limits imbalance threshold in kbytes to 1 sign bit 7980 * plus 20 bits. 7981 */ 7982 return BCM_E_PARAM; 7983 } 7984 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm(unit, 7985 MEM_BLOCK_ANY, i, &imbalance_threshold_entry)); 7986 for (j = 0; j < num_imbalance_th; j++) { 7987 imbalance_th_kbytes = exp_load_th_kbytes * 7988 (imbalance_min_th + j * imbalance_th_increment) / 100; 7989 if (imbalance_th_kbytes < 0) { 7990 /* Convert to two's complement representation */ 7991 imbalance_th_kbytes = -1 * imbalance_th_kbytes; 7992 imbalance_th_kbytes = (~imbalance_th_kbytes) + 1; 7993 } 7994 soc_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm_field32_set(unit, 7995 &imbalance_threshold_entry, imbalance_th_fields[j], 7996 imbalance_th_kbytes & 0x1fffff); 7997 } 7998 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm(unit, 7999 MEM_BLOCK_ALL, i, &imbalance_threshold_entry)); 8000 } 8001 8002 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th = imbalance_min_th; 8003 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th = imbalance_max_th; 8004 8005 return BCM_E_NONE; 8006 } 8007 8008 /* 8009 * Function: 8010 * _bcm_tr3_ecmp_dlb_sample_rate_set 8011 * Purpose: 8012 * Set ECMP dynamic load balancing sample rate. 8013 * Parameters: 8014 * unit - (IN) SOC unit number. 8015 * sample_rate - (IN) Number of samplings per second. 8016 * Returns: 8017 * BCM_E_xxx 8018 */ 8019 STATIC int 8020 _bcm_tr3_ecmp_dlb_sample_rate_set(int unit, int sample_rate) 8021 { 8022 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit, 8023 sample_rate, ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th, 8024 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th)); 8025 8026 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, 8027 sample_rate, ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th, 8028 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th, 8029 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th, 8030 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th)); 8031 8032 return BCM_E_NONE; 8033 } 8034 8035 /* 8036 * Function: 8037 * _bcm_tr3_ecmp_dlb_tx_load_min_th_set 8038 * Purpose: 8039 * Set ECMP DLB port load minimum threshold. 8040 * Parameters: 8041 * unit - (IN) SOC unit number. 8042 * min_th - (IN) Minimum port loading threshold. 8043 * Returns: 8044 * BCM_E_xxx 8045 */ 8046 STATIC int 8047 _bcm_tr3_ecmp_dlb_tx_load_min_th_set(int unit, int min_th) 8048 { 8049 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit, 8050 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, min_th, 8051 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th)); 8052 return BCM_E_NONE; 8053 } 8054 8055 /* 8056 * Function: 8057 * _bcm_trident_ecmp_dlb_tx_load_max_th_set 8058 * Purpose: 8059 * Set LAG DLB port load maximum threshold. 8060 * Parameters: 8061 * unit - (IN) SOC unit number. 8062 * max_th - (IN) Maximum port loading threshold. 8063 * Returns: 8064 * BCM_E_xxx 8065 */ 8066 STATIC int 8067 _bcm_tr3_ecmp_dlb_tx_load_max_th_set(int unit, int max_th) 8068 { 8069 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit, 8070 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, 8071 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th, 8072 max_th)); 8073 return BCM_E_NONE; 8074 } 8075 8076 /* 8077 * Function: 8078 * _bcm_tr3_ecmp_dlb_exp_load_min_th_set 8079 * Purpose: 8080 * Set ECMP DLB expected load minimum threshold. 8081 * Parameters: 8082 * unit - (IN) SOC unit number. 8083 * min_th - (IN) Minimum expected load threshold. 8084 * Returns: 8085 * BCM_E_xxx 8086 */ 8087 STATIC int 8088 _bcm_tr3_ecmp_dlb_exp_load_min_th_set(int unit, int min_th) 8089 { 8090 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, 8091 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, 8092 min_th, 8093 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th, 8094 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th, 8095 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th)); 8096 return BCM_E_NONE; 8097 } 8098 8099 /* 8100 * Function: 8101 * _bcm_tr3_ecmp_dlb_exp_load_max_th_set 8102 * Purpose: 8103 * Set ECMP DLB expected load maximum threshold. 8104 * Parameters: 8105 * unit - (IN) SOC unit number. 8106 * max_th - (IN) Maximum expected load threshold. 8107 * Returns: 8108 * BCM_E_xxx 8109 */ 8110 STATIC int 8111 _bcm_tr3_ecmp_dlb_exp_load_max_th_set(int unit, int max_th) 8112 { 8113 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, 8114 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, 8115 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th, 8116 max_th, 8117 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th, 8118 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th)); 8119 return BCM_E_NONE; 8120 } 8121 8122 /* 8123 * Function: 8124 * _bcm_tr3_ecmp_dlb_imbalance_min_th_set 8125 * Purpose: 8126 * Set ECMP DLB member imbalance minimum threshold. 8127 * Parameters: 8128 * unit - (IN) SOC unit number. 8129 * min_th - (IN) Minimum member imbalance threshold. 8130 * Returns: 8131 * BCM_E_xxx 8132 */ 8133 STATIC int 8134 _bcm_tr3_ecmp_dlb_imbalance_min_th_set(int unit, int min_th) 8135 { 8136 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, 8137 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, 8138 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th, 8139 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th, 8140 min_th, 8141 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th)); 8142 return BCM_E_NONE; 8143 } 8144 8145 /* 8146 * Function: 8147 * _bcm_tr3_ecmp_dlb_imbalance_max_th_set 8148 * Purpose: 8149 * Set ECMP DLB member imbalance maximum threshold. 8150 * Parameters: 8151 * unit - (IN) SOC unit number. 8152 * max_th - (IN) Maximum member imbalance threshold. 8153 * Returns: 8154 * BCM_E_xxx 8155 */ 8156 STATIC int 8157 _bcm_tr3_ecmp_dlb_imbalance_max_th_set(int unit, int max_th) 8158 { 8159 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, 8160 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, 8161 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th, 8162 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th, 8163 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th, 8164 max_th)); 8165 return BCM_E_NONE; 8166 } 8167 8168 /* 8169 * Function: 8170 * _bcm_tr3_ecmp_dlb_qsize_thresholds_set 8171 * Purpose: 8172 * Set LAG DLB queue size thresholds. 8173 * Parameters: 8174 * unit - (IN) SOC unit number. 8175 * min_th - (IN) Minimum queue size threshold, in bytes. 8176 * max_th - (IN) Maximum queue size threshold, in bytes. 8177 * Returns: 8178 * BCM_E_xxx 8179 */ 8180 STATIC int 8181 _bcm_tr3_ecmp_dlb_qsize_thresholds_set(int unit, int min_th, int max_th) 8182 { 8183 int max_th_cells; 8184 int th_increment; 8185 dlb_ecmp_pla_quantize_threshold_entry_t quantize_threshold_entry; 8186 int i; 8187 int th_cells[7]; 8188 8189 if (min_th < 0 || max_th < 0) { 8190 return BCM_E_PARAM; 8191 } 8192 8193 if (min_th > max_th) { 8194 max_th = min_th; 8195 } 8196 8197 /* Convert threshold to number of cells */ 8198 max_th_cells = max_th / 208; 8199 if (max_th_cells > 0xffff) { 8200 /* Hardware limits queue size threshold to 16 bits */ 8201 return BCM_E_PARAM; 8202 } 8203 8204 /* Use min threshold as threshold 0, and max threshold as threshold 6. 8205 * Thresholds 1 to 5 will be evenly spread out between min and max 8206 * thresholds. 8207 */ 8208 th_increment = (max_th - min_th) / 6; 8209 for (i = 0; i < 7; i++) { 8210 SOC_IF_ERROR_RETURN 8211 (READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i, 8212 &quantize_threshold_entry)); 8213 th_cells[i] = (min_th + i * th_increment) / 208; 8214 soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_set 8215 (unit, &quantize_threshold_entry, THRESHOLD_HIST_QSIZEf, 8216 th_cells[i]); 8217 SOC_IF_ERROR_RETURN 8218 (WRITE_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i, 8219 &quantize_threshold_entry)); 8220 } 8221 8222 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = min_th; 8223 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = max_th; 8224 8225 return BCM_E_NONE; 8226 } 8227 8228 /* 8229 * Function: 8230 * _bcm_tr3_ecmp_dlb_qsize_min_th_set 8231 * Purpose: 8232 * Set LAG DLB queue size minimum threshold. 8233 * Parameters: 8234 * unit - (IN) SOC unit number. 8235 * min_th - (IN) Minimum queue size threshold, in bytes. 8236 * Returns: 8237 * BCM_E_xxx 8238 */ 8239 STATIC int 8240 _bcm_tr3_ecmp_dlb_qsize_min_th_set(int unit, int min_th) 8241 { 8242 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_qsize_thresholds_set(unit, 8243 min_th, ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th)); 8244 8245 return BCM_E_NONE; 8246 } 8247 8248 /* 8249 * Function: 8250 * _bcm_tr3_ecmp_dlb_qsize_max_th_set 8251 * Purpose: 8252 * Set LAG DLB queue size maximum threshold. 8253 * Parameters: 8254 * unit - (IN) SOC unit number. 8255 * max_th - (IN) Maximum queue size threshold, in bytes. 8256 * Returns: 8257 * BCM_E_xxx 8258 */ 8259 STATIC int 8260 _bcm_tr3_ecmp_dlb_qsize_max_th_set(int unit, int max_th) 8261 { 8262 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_qsize_thresholds_set(unit, 8263 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th, max_th)); 8264 8265 return BCM_E_NONE; 8266 } 8267 8268 /* 8269 * Function: 8270 * _bcm_tr3_ecmp_dlb_tx_load_weight_set 8271 * Purpose: 8272 * Set LAG DLB port load weight. 8273 * Parameters: 8274 * unit - (IN) SOC unit number. 8275 * weight - (IN) Port load weight. 8276 * Returns: 8277 * BCM_E_xxx 8278 */ 8279 STATIC int 8280 _bcm_tr3_ecmp_dlb_tx_load_weight_set(int unit, int weight) 8281 { 8282 uint32 measure_control_reg; 8283 8284 if (weight < 0 || 8285 weight > 0xf) { 8286 /* Hardware limits port load weight to 4 bits */ 8287 return BCM_E_PARAM; 8288 } 8289 8290 SOC_IF_ERROR_RETURN 8291 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8292 soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8293 &measure_control_reg, PLA_WEIGHT_LOADINGf, weight); 8294 SOC_IF_ERROR_RETURN 8295 (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 8296 return BCM_E_NONE; 8297 } 8298 8299 /* 8300 * Function: 8301 * _bcm_tr3_ecmp_dlb_tx_load_weight_get 8302 * Purpose: 8303 * Get LAG DLB port load weight. 8304 * Parameters: 8305 * unit - (IN) SOC unit number. 8306 * weight - (OUT) Port load weight. 8307 * Returns: 8308 * BCM_E_xxx 8309 */ 8310 STATIC int 8311 _bcm_tr3_ecmp_dlb_tx_load_weight_get(int unit, int *weight) 8312 { 8313 uint32 measure_control_reg; 8314 8315 SOC_IF_ERROR_RETURN 8316 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8317 *weight = soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8318 measure_control_reg, PLA_WEIGHT_LOADINGf); 8319 8320 return BCM_E_NONE; 8321 } 8322 8323 /* 8324 * Function: 8325 * _bcm_tr3_ecmp_dlb_qsize_weight_set 8326 * Purpose: 8327 * Set LAG DLB qsize weight. 8328 * Parameters: 8329 * unit - (IN) SOC unit number. 8330 * weight - (IN) Qsize weight. 8331 * Returns: 8332 * BCM_E_xxx 8333 */ 8334 STATIC int 8335 _bcm_tr3_ecmp_dlb_qsize_weight_set(int unit, int weight) 8336 { 8337 uint32 measure_control_reg; 8338 8339 if (weight < 0 || 8340 weight > 0xf) { 8341 /* Hardware limits qsize weight to 4 bits */ 8342 return BCM_E_PARAM; 8343 } 8344 8345 SOC_IF_ERROR_RETURN 8346 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8347 soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8348 &measure_control_reg, PLA_WEIGHT_QSIZEf, weight); 8349 SOC_IF_ERROR_RETURN 8350 (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 8351 return BCM_E_NONE; 8352 } 8353 8354 /* 8355 * Function: 8356 * _bcm_tr3_ecmp_dlb_qsize_weight_get 8357 * Purpose: 8358 * Get LAG DLB qsize weight. 8359 * Parameters: 8360 * unit - (IN) SOC unit number. 8361 * weight - (OUT) Qsize weight. 8362 * Returns: 8363 * BCM_E_xxx 8364 */ 8365 STATIC int 8366 _bcm_tr3_ecmp_dlb_qsize_weight_get(int unit, int *weight) 8367 { 8368 uint32 measure_control_reg; 8369 8370 SOC_IF_ERROR_RETURN 8371 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8372 *weight = soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8373 measure_control_reg, PLA_WEIGHT_QSIZEf); 8374 8375 return BCM_E_NONE; 8376 } 8377 8378 /* 8379 * Function: 8380 * _bcm_tr3_ecmp_dlb_tx_load_cap_set 8381 * Purpose: 8382 * Set LAG DLB port load cap control. 8383 * Parameters: 8384 * unit - (IN) SOC unit number. 8385 * cap - (IN) Port load cap control. 8386 * Returns: 8387 * BCM_E_xxx 8388 */ 8389 STATIC int 8390 _bcm_tr3_ecmp_dlb_tx_load_cap_set(int unit, int cap) 8391 { 8392 uint32 measure_control_reg; 8393 8394 if (cap < 0 || 8395 cap > 1) { 8396 /* Hardware limits port load cap control to 1 bit */ 8397 return BCM_E_PARAM; 8398 } 8399 8400 SOC_IF_ERROR_RETURN 8401 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8402 soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8403 &measure_control_reg, PLA_CAP_LOADING_AVGf, cap); 8404 SOC_IF_ERROR_RETURN 8405 (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 8406 return BCM_E_NONE; 8407 } 8408 8409 /* 8410 * Function: 8411 * _bcm_tr3_ecmp_dlb_tx_load_cap_get 8412 * Purpose: 8413 * Get LAG DLB port load cap control. 8414 * Parameters: 8415 * unit - (IN) SOC unit number. 8416 * cap - (OUT) Cap control. 8417 * Returns: 8418 * BCM_E_xxx 8419 */ 8420 STATIC int 8421 _bcm_tr3_ecmp_dlb_tx_load_cap_get(int unit, int *cap) 8422 { 8423 uint32 measure_control_reg; 8424 8425 SOC_IF_ERROR_RETURN 8426 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8427 *cap= soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8428 measure_control_reg, PLA_CAP_LOADING_AVGf); 8429 8430 return BCM_E_NONE; 8431 } 8432 /* 8433 * Function: 8434 * _bcm_tr3_ecmp_dlb_qsize_cap_set 8435 * Purpose: 8436 * Set LAG DLB queue size cap control. 8437 * Parameters: 8438 * unit - (IN) SOC unit number. 8439 * cap - (IN) Queue size cap control. 8440 * Returns: 8441 * BCM_E_xxx 8442 */ 8443 STATIC int 8444 _bcm_tr3_ecmp_dlb_qsize_cap_set(int unit, int cap) 8445 { 8446 uint32 measure_control_reg; 8447 8448 if (cap < 0 || 8449 cap > 1) { 8450 /* Hardware limits port load cap control to 1 bit */ 8451 return BCM_E_PARAM; 8452 } 8453 8454 SOC_IF_ERROR_RETURN 8455 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8456 soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8457 &measure_control_reg, PLA_CAP_QSIZE_AVGf, cap); 8458 SOC_IF_ERROR_RETURN 8459 (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 8460 return BCM_E_NONE; 8461 } 8462 8463 /* 8464 * Function: 8465 * _bcm_tr3_ecmp_dlb_qsize_cap_get 8466 * Purpose: 8467 * Get LAG DLB queue size cap control. 8468 * Parameters: 8469 * unit - (IN) SOC unit number. 8470 * cap - (OUT) Cap control. 8471 * Returns: 8472 * BCM_E_xxx 8473 */ 8474 STATIC int 8475 _bcm_tr3_ecmp_dlb_qsize_cap_get(int unit, int *cap) 8476 { 8477 uint32 measure_control_reg; 8478 8479 SOC_IF_ERROR_RETURN 8480 (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 8481 *cap= soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr, 8482 measure_control_reg, PLA_CAP_QSIZE_AVGf); 8483 8484 return BCM_E_NONE; 8485 } 8486 8487 /* 8488 * Function: 8489 * _bcm_tr3_ecmp_dlb_config_set 8490 * Purpose: 8491 * Set per-chip LAG dynamic load balancing configuration parameters. 8492 * Parameters: 8493 * unit - (IN) SOC unit number. 8494 * type - (IN) Configuration parameter type. 8495 * arg - (IN) Configuration paramter value. 8496 * Returns: 8497 * BCM_E_xxx 8498 */ 8499 int 8500 _bcm_tr3_ecmp_dlb_config_set(int unit, bcm_switch_control_t type, int arg) 8501 { 8502 switch (type) { 8503 case bcmSwitchEcmpDynamicSampleRate: 8504 return _bcm_tr3_ecmp_dlb_sample_rate_set(unit, arg); 8505 8506 case bcmSwitchEcmpDynamicAccountingSelect: 8507 return _bcm_tr3_ecmp_dlb_accounting_set(unit, arg); 8508 8509 case bcmSwitchEcmpDynamicEgressBytesExponent: 8510 return _bcm_tr3_ecmp_dlb_tx_load_weight_set(unit, arg); 8511 8512 case bcmSwitchEcmpDynamicQueuedBytesExponent: 8513 return _bcm_tr3_ecmp_dlb_qsize_weight_set(unit, arg); 8514 8515 case bcmSwitchEcmpDynamicEgressBytesDecreaseReset: 8516 return _bcm_tr3_ecmp_dlb_tx_load_cap_set(unit, arg); 8517 8518 case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset: 8519 return _bcm_tr3_ecmp_dlb_qsize_cap_set(unit, arg); 8520 8521 case bcmSwitchEcmpDynamicEgressBytesMinThreshold: 8522 return _bcm_tr3_ecmp_dlb_tx_load_min_th_set(unit, arg); 8523 8524 case bcmSwitchEcmpDynamicEgressBytesMaxThreshold: 8525 return _bcm_tr3_ecmp_dlb_tx_load_max_th_set(unit, arg); 8526 8527 case bcmSwitchEcmpDynamicQueuedBytesMinThreshold: 8528 return _bcm_tr3_ecmp_dlb_qsize_min_th_set(unit, arg); 8529 8530 case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold: 8531 return _bcm_tr3_ecmp_dlb_qsize_max_th_set(unit, arg); 8532 8533 case bcmSwitchEcmpDynamicExpectedLoadMinThreshold: 8534 return _bcm_tr3_ecmp_dlb_exp_load_min_th_set(unit, arg); 8535 8536 case bcmSwitchEcmpDynamicExpectedLoadMaxThreshold: 8537 return _bcm_tr3_ecmp_dlb_exp_load_max_th_set(unit, arg); 8538 8539 case bcmSwitchEcmpDynamicImbalanceMinThreshold: 8540 return _bcm_tr3_ecmp_dlb_imbalance_min_th_set(unit, arg); 8541 8542 case bcmSwitchEcmpDynamicImbalanceMaxThreshold: 8543 return _bcm_tr3_ecmp_dlb_imbalance_max_th_set(unit, arg); 8544 8545 default: 8546 return BCM_E_PARAM; 8547 } 8548 } 8549 8550 /* 8551 * Function: 8552 * _bcm_tr3_ecmp_dlb_config_get 8553 * Purpose: 8554 * Get per-chip LAG dynamic load balancing configuration parameters. 8555 * Parameters: 8556 * unit - (IN) SOC unit number. 8557 * type - (IN) Configuration parameter type. 8558 * arg - (OUT) Configuration paramter value. 8559 * Returns: 8560 * BCM_E_xxx 8561 */ 8562 int 8563 _bcm_tr3_ecmp_dlb_config_get(int unit, bcm_switch_control_t type, int *arg) 8564 { 8565 switch (type) { 8566 case bcmSwitchEcmpDynamicSampleRate: 8567 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate; 8568 break; 8569 8570 case bcmSwitchEcmpDynamicAccountingSelect: 8571 return _bcm_tr3_ecmp_dlb_accounting_get(unit, arg); 8572 break; 8573 8574 case bcmSwitchEcmpDynamicEgressBytesExponent: 8575 return _bcm_tr3_ecmp_dlb_tx_load_weight_get(unit, arg); 8576 8577 case bcmSwitchEcmpDynamicQueuedBytesExponent: 8578 return _bcm_tr3_ecmp_dlb_qsize_weight_get(unit, arg); 8579 8580 case bcmSwitchEcmpDynamicEgressBytesDecreaseReset: 8581 return _bcm_tr3_ecmp_dlb_tx_load_cap_get(unit, arg); 8582 8583 case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset: 8584 return _bcm_tr3_ecmp_dlb_qsize_cap_get(unit, arg); 8585 8586 case bcmSwitchEcmpDynamicEgressBytesMinThreshold: 8587 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th; 8588 break; 8589 8590 case bcmSwitchEcmpDynamicEgressBytesMaxThreshold: 8591 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th; 8592 break; 8593 8594 case bcmSwitchEcmpDynamicQueuedBytesMinThreshold: 8595 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th; 8596 break; 8597 8598 case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold: 8599 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th; 8600 break; 8601 8602 case bcmSwitchEcmpDynamicExpectedLoadMinThreshold: 8603 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th; 8604 break; 8605 8606 case bcmSwitchEcmpDynamicExpectedLoadMaxThreshold: 8607 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th; 8608 break; 8609 8610 case bcmSwitchEcmpDynamicImbalanceMinThreshold: 8611 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th; 8612 break; 8613 8614 case bcmSwitchEcmpDynamicImbalanceMaxThreshold: 8615 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th; 8616 break; 8617 8618 default: 8619 return BCM_E_PARAM; 8620 } 8621 8622 return BCM_E_NONE; 8623 } 8624 8625 /* 8626 * Function: 8627 * _bcm_tr3_ecmp_dlb_quality_map_profile_init 8628 * Purpose: 8629 * Initialize ECMP DLB quality mapping profile. 8630 * Parameters: 8631 * unit - (IN)SOC unit number. 8632 * Returns: 8633 * BCM_X_XXX 8634 */ 8635 STATIC int 8636 _bcm_tr3_ecmp_dlb_quality_map_profile_init(int unit) 8637 { 8638 soc_profile_mem_t *profile; 8639 soc_mem_t mem; 8640 int entry_words; 8641 int entries_per_profile; 8642 int tx_load_percent; 8643 int alloc_size; 8644 uint32 *entry_arr; 8645 int rv = BCM_E_NONE; 8646 void *entries; 8647 uint32 base_index; 8648 int i; 8649 int member_id; 8650 dlb_ecmp_quality_control_entry_t quality_control_entry; 8651 8652 if (NULL == _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) { 8653 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile = 8654 sal_alloc(sizeof(soc_profile_mem_t), 8655 "ECMP DLB Quality Map Profile Mem"); 8656 if (NULL == _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) { 8657 return BCM_E_MEMORY; 8658 } 8659 } else { 8660 soc_profile_mem_destroy(unit, 8661 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile); 8662 } 8663 profile = _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile; 8664 soc_profile_mem_t_init(profile); 8665 8666 mem = DLB_ECMP_QUALITY_MAPPINGm; 8667 entry_words = sizeof(dlb_ecmp_quality_mapping_entry_t) / sizeof(uint32); 8668 SOC_IF_ERROR_RETURN 8669 (soc_profile_mem_create(unit, &mem, &entry_words, 1, profile)); 8670 8671 entries_per_profile = 64; 8672 if (!SOC_WARM_BOOT(unit)) { 8673 alloc_size = entries_per_profile * entry_words * sizeof(uint32); 8674 entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries"); 8675 if (entry_arr == NULL) { 8676 return BCM_E_MEMORY; 8677 } 8678 sal_memset(entry_arr, 0, alloc_size); 8679 8680 /* Assign quality in the entry array, with 100% weight for port load, 8681 * 0% for queue size. 8682 */ 8683 tx_load_percent = 100; 8684 rv = _bcm_tr3_ecmp_dlb_quality_assign(unit, tx_load_percent, 8685 entry_arr); 8686 if (BCM_FAILURE(rv)) { 8687 sal_free(entry_arr); 8688 return rv; 8689 } 8690 8691 entries = entry_arr; 8692 rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile, 8693 &base_index); 8694 sal_free(entry_arr); 8695 if (SOC_FAILURE(rv)) { 8696 return rv; 8697 } 8698 8699 for (member_id = 0; 8700 member_id < soc_mem_index_count(unit, 8701 DLB_ECMP_QUALITY_CONTROLm); 8702 member_id++) { 8703 BCM_IF_ERROR_RETURN 8704 (READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, 8705 member_id, 8706 &quality_control_entry)); 8707 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 8708 &quality_control_entry, PROFILE_PTRf, 8709 base_index / entries_per_profile); 8710 BCM_IF_ERROR_RETURN 8711 (WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL, 8712 member_id, 8713 &quality_control_entry)); 8714 } 8715 8716 for (i = 0; i < entries_per_profile; i++) { 8717 SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i, 8718 member_id - 1); 8719 } 8720 8721 ECMP_DLB_INFO(unit)-> 8722 ecmp_dlb_load_weight[base_index/entries_per_profile] = 8723 tx_load_percent; 8724 8725 } else { /* Warm boot, recover reference counts and entries_per_set */ 8726 8727 for (member_id = 0; 8728 member_id < soc_mem_index_count(unit, 8729 DLB_ECMP_QUALITY_CONTROLm); 8730 member_id++) { 8731 BCM_IF_ERROR_RETURN 8732 (READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, 8733 member_id, 8734 &quality_control_entry)); 8735 base_index = soc_DLB_ECMP_QUALITY_CONTROLm_field32_get(unit, 8736 &quality_control_entry, PROFILE_PTRf); 8737 base_index *= entries_per_profile; 8738 for (i = 0; i < entries_per_profile; i++) { 8739 SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i, 1); 8740 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, profile, 8741 base_index + i, entries_per_profile); 8742 } 8743 } 8744 } 8745 8746 return BCM_E_NONE; 8747 } 8748 8749 /* 8750 * Function: 8751 * _bcm_tr3_ecmp_dlb_deinit 8752 * Purpose: 8753 * Deallocate _tr3_ecmp_dlb_bk 8754 * Parameters: 8755 * unit - (IN)SOC unit number. 8756 * Returns: 8757 * None 8758 */ 8759 void 8760 _bcm_tr3_ecmp_dlb_deinit(int unit) 8761 { 8762 int rv; 8763 uint32 rsel2_hw_control_reg; 8764 8765 if (_tr3_ecmp_dlb_bk[unit]) { 8766 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info) { 8767 sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info); 8768 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info = NULL; 8769 } 8770 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap) { 8771 sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap); 8772 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = NULL; 8773 } 8774 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap) { 8775 sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap); 8776 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = NULL; 8777 } 8778 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap) { 8779 sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap); 8780 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap = NULL; 8781 } 8782 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight) { 8783 sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight); 8784 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = NULL; 8785 } 8786 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) { 8787 soc_profile_mem_destroy(unit, 8788 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile); 8789 sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile); 8790 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile = NULL; 8791 } 8792 8793 sal_free(_tr3_ecmp_dlb_bk[unit]); 8794 _tr3_ecmp_dlb_bk[unit] = NULL; 8795 } 8796 8797 rv = READ_RSEL2_HW_CONTROLr(unit, &rsel2_hw_control_reg); 8798 if (SOC_SUCCESS(rv)) { 8799 soc_reg_field_set(unit, RSEL2_HW_CONTROLr, &rsel2_hw_control_reg, 8800 ENABLE_ECMP_DLBf, 0); 8801 (void)WRITE_RSEL2_HW_CONTROLr(unit, rsel2_hw_control_reg); 8802 } 8803 } 8804 8805 /* 8806 * Function: 8807 * _bcm_tr3_ecmp_dlb_init 8808 * Purpose: 8809 * Allocate and initialize _tr3_ecmp_dlb_bk 8810 * Parameters: 8811 * unit - (IN)SOC unit number. 8812 * Returns: 8813 * BCM_X_XXX 8814 */ 8815 int 8816 _bcm_tr3_ecmp_dlb_init(int unit) 8817 { 8818 int rv = BCM_E_NONE; 8819 int num_ecmp_dlb_id; 8820 int flowset_tbl_size; 8821 int total_num_blocks; 8822 int num_ecmp_dlb_member_id; 8823 int num_quality_map_profiles; 8824 int member_id; 8825 dlb_ecmp_quality_control_entry_t quality_control_entry; 8826 uint32 rsel2_hw_control_reg; 8827 uint32 measure_control_reg; 8828 int max_ecmp_dlb_next_hops; 8829 int sample_rate; 8830 8831 _bcm_tr3_ecmp_dlb_deinit(unit); 8832 8833 if (_tr3_ecmp_dlb_bk[unit] == NULL) { 8834 _tr3_ecmp_dlb_bk[unit] = sal_alloc( 8835 sizeof(_tr3_ecmp_dlb_bookkeeping_t), "_tr3_ecmp_dlb_bk"); 8836 if (_tr3_ecmp_dlb_bk[unit] == NULL) { 8837 return BCM_E_MEMORY; 8838 } 8839 } 8840 sal_memset(_tr3_ecmp_dlb_bk[unit], 0, sizeof(_tr3_ecmp_dlb_bookkeeping_t)); 8841 8842 max_ecmp_dlb_next_hops = soc_mem_index_count(unit, 8843 DLB_ECMP_MEMBER_ATTRIBUTEm); 8844 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info == NULL) { 8845 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info = 8846 sal_alloc(sizeof(_tr3_ecmp_dlb_nh_info_t) * max_ecmp_dlb_next_hops, 8847 "ecmp_dlb_nh_info"); 8848 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info == NULL) { 8849 _bcm_tr3_ecmp_dlb_deinit(unit); 8850 return BCM_E_MEMORY; 8851 } 8852 } 8853 sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info, 0, 8854 sizeof(_tr3_ecmp_dlb_nh_info_t) * max_ecmp_dlb_next_hops); 8855 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info_size = max_ecmp_dlb_next_hops; 8856 8857 num_ecmp_dlb_id = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); 8858 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) { 8859 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = 8860 sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_id), 8861 "ecmp_dlb_id_used_bitmap"); 8862 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) { 8863 _bcm_tr3_ecmp_dlb_deinit(unit); 8864 return BCM_E_MEMORY; 8865 } 8866 } 8867 sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap, 0, 8868 SHR_BITALLOCSIZE(num_ecmp_dlb_id)); 8869 8870 flowset_tbl_size = soc_mem_index_count(unit, DLB_ECMP_FLOWSETm); 8871 /* Each bit in ecmp_dlb_flowset_block_bitmap corresponds to a block of 512 8872 * flow set table entries. 8873 */ 8874 total_num_blocks = flowset_tbl_size / 512; 8875 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) { 8876 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = 8877 sal_alloc(SHR_BITALLOCSIZE(total_num_blocks), 8878 "ecmp_dlb_flowset_block_bitmap"); 8879 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) { 8880 _bcm_tr3_ecmp_dlb_deinit(unit); 8881 return BCM_E_MEMORY; 8882 } 8883 } 8884 sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap, 0, 8885 SHR_BITALLOCSIZE(total_num_blocks)); 8886 8887 num_ecmp_dlb_member_id = soc_mem_index_count(unit, 8888 DLB_ECMP_MEMBER_ATTRIBUTEm); 8889 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap == NULL) { 8890 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap = 8891 sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_member_id), 8892 "ecmp_dlb_member_id_used_bitmap"); 8893 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap == NULL) { 8894 _bcm_tr3_ecmp_dlb_deinit(unit); 8895 return BCM_E_MEMORY; 8896 } 8897 } 8898 sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap, 0, 8899 SHR_BITALLOCSIZE(num_ecmp_dlb_member_id)); 8900 8901 num_quality_map_profiles = 1 << soc_mem_field_length(unit, 8902 DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf); 8903 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) { 8904 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = 8905 sal_alloc(num_quality_map_profiles * sizeof(uint8), 8906 "ecmp_dlb_load_weight"); 8907 if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) { 8908 _bcm_tr3_ecmp_dlb_deinit(unit); 8909 return BCM_E_MEMORY; 8910 } 8911 } 8912 sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight, 0, 8913 num_quality_map_profiles * sizeof(uint8)); 8914 8915 /* Initialize port quality mapping profile */ 8916 rv = _bcm_tr3_ecmp_dlb_quality_map_profile_init(unit); 8917 if (BCM_FAILURE(rv)) { 8918 _bcm_tr3_ecmp_dlb_deinit(unit); 8919 return rv; 8920 } 8921 8922 if (!SOC_WARM_BOOT(unit)) { 8923 8924 /* Configure accounting mode to physical link accounting */ 8925 rv = _bcm_tr3_ecmp_dlb_config_set(unit, 8926 bcmSwitchEcmpDynamicAccountingSelect, 0); 8927 if (BCM_FAILURE(rv)) { 8928 _bcm_tr3_ecmp_dlb_deinit(unit); 8929 return rv; 8930 } 8931 8932 /* Set DLB sampling period and thresholds */ 8933 sample_rate = 1000; 8934 rv = _bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit, sample_rate, 8935 125, 875); 8936 if (BCM_FAILURE(rv)) { 8937 _bcm_tr3_ecmp_dlb_deinit(unit); 8938 return rv; 8939 } 8940 rv = _bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, sample_rate, 8941 125, 875, -75, 75); 8942 if (BCM_FAILURE(rv)) { 8943 _bcm_tr3_ecmp_dlb_deinit(unit); 8944 return rv; 8945 } 8946 8947 /* Configure LAG DLB load EWMA weight */ 8948 rv = _bcm_tr3_ecmp_dlb_config_set(unit, 8949 bcmSwitchEcmpDynamicEgressBytesExponent, 0); 8950 if (BCM_FAILURE(rv)) { 8951 _bcm_tr3_ecmp_dlb_deinit(unit); 8952 return rv; 8953 } 8954 8955 /* Configure LAG DLB queue size EWMA weight */ 8956 rv = _bcm_tr3_ecmp_dlb_config_set(unit, 8957 bcmSwitchEcmpDynamicQueuedBytesExponent, 0); 8958 if (BCM_FAILURE(rv)) { 8959 _bcm_tr3_ecmp_dlb_deinit(unit); 8960 return rv; 8961 } 8962 8963 /* Configure LAG DLB load cap control */ 8964 rv = _bcm_tr3_ecmp_dlb_config_set(unit, 8965 bcmSwitchEcmpDynamicEgressBytesDecreaseReset, 0); 8966 if (BCM_FAILURE(rv)) { 8967 _bcm_tr3_ecmp_dlb_deinit(unit); 8968 return rv; 8969 } 8970 8971 /* Configure LAG DLB queue size cap control */ 8972 rv = _bcm_tr3_ecmp_dlb_config_set(unit, 8973 bcmSwitchEcmpDynamicQueuedBytesDecreaseReset, 0); 8974 if (BCM_FAILURE(rv)) { 8975 _bcm_tr3_ecmp_dlb_deinit(unit); 8976 return rv; 8977 } 8978 8979 /* Configure LAG DLB queue size thresholds */ 8980 rv = _bcm_tr3_ecmp_dlb_qsize_thresholds_set(unit, 0, 0); 8981 if (BCM_FAILURE(rv)) { 8982 _bcm_tr3_ecmp_dlb_deinit(unit); 8983 return rv; 8984 } 8985 8986 /* Disable link status override by software */ 8987 rv = soc_mem_clear(unit, DLB_ECMP_MEMBER_SW_STATEm, MEM_BLOCK_ALL, 0); 8988 if (BCM_FAILURE(rv)) { 8989 _bcm_tr3_ecmp_dlb_deinit(unit); 8990 return rv; 8991 } 8992 8993 /* Clear group membership */ 8994 rv = soc_mem_clear(unit, DLB_ECMP_GROUP_MEMBERSHIPm, MEM_BLOCK_ALL, 0); 8995 if (BCM_FAILURE(rv)) { 8996 _bcm_tr3_ecmp_dlb_deinit(unit); 8997 return rv; 8998 } 8999 9000 /* Clear port<->member mapping tables */ 9001 rv = soc_mem_clear(unit, DLB_ECMP_MEMBERSHIP_REVERSE_MAPm, 9002 MEM_BLOCK_ALL, 0); 9003 if (BCM_FAILURE(rv)) { 9004 _bcm_tr3_ecmp_dlb_deinit(unit); 9005 return rv; 9006 } 9007 rv = soc_mem_clear(unit, DLB_ECMP_MEMBER_ATTRIBUTEm, MEM_BLOCK_ALL, 0); 9008 if (BCM_FAILURE(rv)) { 9009 _bcm_tr3_ecmp_dlb_deinit(unit); 9010 return rv; 9011 } 9012 9013 /* Configure per member threshold scaling factor and 9014 * quality measure update control. 9015 */ 9016 for (member_id = 0; 9017 member_id < soc_mem_index_count(unit, 9018 DLB_ECMP_QUALITY_CONTROLm); 9019 member_id++) { 9020 rv = READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, 9021 member_id, &quality_control_entry); 9022 if (SOC_FAILURE(rv)) { 9023 _bcm_tr3_ecmp_dlb_deinit(unit); 9024 return rv; 9025 } 9026 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 9027 &quality_control_entry, ENABLE_AVG_CALCf, 1); 9028 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 9029 &quality_control_entry, ENABLE_QUALITY_UPDATEf, 1); 9030 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 9031 &quality_control_entry, ENABLE_CREDIT_COLLECTIONf, 1); 9032 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 9033 &quality_control_entry, LOADING_SCALING_FACTORf, 1); 9034 soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, 9035 &quality_control_entry, QSIZE_SCALING_FACTORf, 1); 9036 rv = WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL, 9037 member_id, &quality_control_entry); 9038 if (SOC_FAILURE(rv)) { 9039 _bcm_tr3_ecmp_dlb_deinit(unit); 9040 return rv; 9041 } 9042 } 9043 9044 /* Enable DLB HGT refresh */ 9045 rv = READ_RSEL2_HW_CONTROLr(unit, &rsel2_hw_control_reg); 9046 if (BCM_SUCCESS(rv)) { 9047 soc_reg_field_set(unit, RSEL2_HW_CONTROLr, &rsel2_hw_control_reg, 9048 ENABLE_ECMP_DLBf, 1); 9049 rv = WRITE_RSEL2_HW_CONTROLr(unit, rsel2_hw_control_reg); 9050 } 9051 if (BCM_FAILURE(rv)) { 9052 _bcm_tr3_ecmp_dlb_deinit(unit); 9053 return rv; 9054 } 9055 9056 /* Configure Ethertype eligibility */ 9057 rv = soc_mem_clear(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm, 9058 MEM_BLOCK_ALL, 0); 9059 if (BCM_FAILURE(rv)) { 9060 _bcm_tr3_ecmp_dlb_deinit(unit); 9061 return rv; 9062 } 9063 rv = READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, 9064 &measure_control_reg); 9065 if (SOC_SUCCESS(rv)) { 9066 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 9067 &measure_control_reg, 9068 ETHERTYPE_ELIGIBILITY_CONFIGf, 0); 9069 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 9070 &measure_control_reg, 9071 INNER_OUTER_ETHERTYPE_SELECTIONf, 0); 9072 rv = WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, 9073 measure_control_reg); 9074 } 9075 if (BCM_FAILURE(rv)) { 9076 _bcm_tr3_ecmp_dlb_deinit(unit); 9077 return rv; 9078 } 9079 9080 } 9081 9082 return rv; 9083 } 9084 9085 /* 9086 * Function: 9087 * _bcm_tr3_l3_host_stat_attach 9088 * Description: 9089 * Attach counters entries to the given L3 host entry 9090 * 9091 * Parameters: 9092 * unit - (IN) unit number 9093 * info - (IN) L3 host description 9094 * stat_counter_id - (IN) Stat Counter ID. 9095 * 9096 * Return Value: 9097 * BCM_E_XXX 9098 * Notes: 9099 * On BCM56640, the L3 host tables (ISM tables L3_ENTRY_2 and L3_ENTRY_4, 9100 * ESM table EXT_L3_UCAST_DATA_WIDE) may contain a flex stat pointer when 9101 * entry has a dereference next hop (no NEXT_HOP pointer, but the NH info 9102 * instead). This counter is analogous to what would be in the egress 9103 * object, but is implemented in the ingress and so requires an ingress 9104 * counter pool allocated. 9105 */ 9106 bcm_error_t 9107 _bcm_tr3_l3_host_stat_attach( 9108 int unit, 9109 bcm_l3_host_t *info, 9110 uint32 stat_counter_id) 9111 { 9112 soc_mem_t table[4]={0}; 9113 uint32 flex_table_index=0; 9114 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 9115 uint32 pool_number=0; 9116 uint32 base_index=0; 9117 bcm_stat_flex_mode_t offset_mode=0; 9118 bcm_stat_object_t object=bcmStatObjectIngPort; 9119 bcm_stat_group_mode_t group_mode= bcmStatGroupModeSingle; 9120 uint32 count=0; 9121 uint32 actual_num_tables=0; 9122 uint32 num_of_tables=0; 9123 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 9124 9125 _bcm_esw_stat_get_counter_id_info( 9126 unit, stat_counter_id, 9127 &group_mode,&object,&offset_mode,&pool_number,&base_index); 9128 9129 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction)); 9130 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode)); 9131 9132 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info( 9133 unit,object,4,&actual_num_tables,&table[0],&direction)); 9134 9135 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info( 9136 unit, info,&num_of_tables,&table_info[0])); 9137 for (count=0; count < num_of_tables ; count++) { 9138 for (flex_table_index=0; 9139 flex_table_index < actual_num_tables ; 9140 flex_table_index++) { 9141 if ((table_info[count].direction == direction) && 9142 (table_info[count].table == table[flex_table_index]) ) { 9143 if (direction == bcmStatFlexDirectionIngress) { 9144 return _bcm_esw_stat_flex_attach_ingress_table_counters( 9145 unit, 9146 table_info[count].table, 9147 table_info[count].index, 9148 offset_mode, 9149 base_index, 9150 pool_number); 9151 } else { 9152 return _bcm_esw_stat_flex_attach_egress_table_counters( 9153 unit, 9154 table_info[count].table, 9155 table_info[count].index, 9156 0, 9157 offset_mode, 9158 base_index, 9159 pool_number); 9160 } 9161 } 9162 } 9163 } 9164 return BCM_E_NOT_FOUND; 9165 } 9166 9167 /* 9168 * Function: 9169 * _bcm_tr3_l3_host_stat_detach 9170 * Description: 9171 * Detach counters entries to the given L3 host entry 9172 * 9173 * Parameters: 9174 * unit - (IN) unit number 9175 * info - (IN) L3 host description 9176 * 9177 * Return Value: 9178 * BCM_E_XXX 9179 * Notes: 9180 */ 9181 bcm_error_t 9182 _bcm_tr3_l3_host_stat_detach( 9183 int unit, 9184 bcm_l3_host_t *info) 9185 { 9186 uint32 count=0; 9187 uint32 num_of_tables=0; 9188 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 9189 bcm_error_t rv = BCM_E_NONE; 9190 bcm_error_t err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE}; 9191 9192 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info( 9193 unit, info,&num_of_tables,&table_info[0])); 9194 9195 for (count=0; count < num_of_tables ; count++) { 9196 if (table_info[count].direction == bcmStatFlexDirectionIngress) { 9197 rv = _bcm_esw_stat_flex_detach_ingress_table_counters( 9198 unit, 9199 table_info[count].table, 9200 table_info[count].index); 9201 if (BCM_E_NONE != rv && 9202 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) { 9203 err_code[bcmStatFlexDirectionIngress] = rv; 9204 } 9205 } else { 9206 rv = _bcm_esw_stat_flex_detach_egress_table_counters( 9207 unit, 9208 0, 9209 table_info[count].table, 9210 table_info[count].index); 9211 if (BCM_E_NONE != rv && 9212 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) { 9213 err_code[bcmStatFlexDirectionEgress] = rv; 9214 } 9215 } 9216 } 9217 9218 BCM_STAT_FLEX_DETACH_RETURN(err_code) 9219 } 9220 9221 /* 9222 * Function: 9223 * _bcm_tr3_l3_host_stat_counter_get 9224 * Description: 9225 * Get counter statistic values for specific L3 host entry 9226 * if sync_mode is set, sync the sw accumulated count 9227 * with hw count value first, else return sw count. 9228 * 9229 * Parameters: 9230 * unit - (IN) unit number 9231 * sync_mode - (IN) hwcount is to be synced to sw count 9232 * info - (IN) L3 host description 9233 * stat - (IN) Type of the counter to retrieve 9234 * I.e. ingress/egress byte/packet) 9235 * num_entries - (IN) Number of counter Entries 9236 * counter_indexes - (IN) Pointer to Counter indexes entries 9237 * counter_values - (OUT) Pointer to counter values 9238 * 9239 * Return Value: 9240 * BCM_E_XXX 9241 * Notes: 9242 */ 9243 bcm_error_t 9244 _bcm_tr3_l3_host_stat_counter_get(int unit, 9245 int sync_mode, 9246 bcm_l3_host_t *info, 9247 bcm_l3_stat_t stat, 9248 uint32 num_entries, 9249 uint32 *counter_indexes, 9250 bcm_stat_value_t *counter_values) 9251 { 9252 uint32 table_count=0; 9253 uint32 index_count=0; 9254 uint32 num_of_tables=0; 9255 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 9256 uint32 byte_flag=0; 9257 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 9258 9259 if ((stat == bcmL3StatInPackets) || 9260 (stat == bcmL3StatInBytes)) { 9261 direction = bcmStatFlexDirectionIngress; 9262 } else { 9263 /* direction = bcmStatFlexDirectionEgress; */ 9264 return BCM_E_PARAM; 9265 } 9266 if (stat == bcmL3StatInPackets) { 9267 byte_flag=0; 9268 } else { 9269 byte_flag=1; 9270 } 9271 9272 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info( 9273 unit, info,&num_of_tables,&table_info[0])); 9274 9275 for (table_count=0; table_count < num_of_tables ; table_count++) { 9276 if (table_info[table_count].direction == direction) { 9277 for (index_count=0; index_count < num_entries ; index_count++) { 9278 /*ctr_offset_info.offset_index = counter_indexes[index_count];*/ 9279 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get( 9280 unit, sync_mode, 9281 table_info[table_count].index, 9282 table_info[table_count].table, 9283 0, 9284 byte_flag, 9285 counter_indexes[index_count], 9286 &counter_values[index_count])); 9287 } 9288 } 9289 } 9290 return BCM_E_NONE; 9291 } 9292 9293 /* 9294 * Function: 9295 * _bcm_tr3_l3_host_stat_counter_set 9296 * Description: 9297 * Set counter statistic values for specific L3 host entry 9298 * 9299 * Parameters: 9300 * unit - (IN) unit number 9301 * info - (IN) L3 host description 9302 * stat - (IN) Type of the counter to retrieve 9303 * I.e. ingress/egress byte/packet) 9304 * num_entries - (IN) Number of counter Entries 9305 * counter_indexes - (IN) Pointer to Counter indexes entries 9306 * counter_values - (IN) Pointer to counter values 9307 * 9308 * Return Value: 9309 * BCM_E_XXX 9310 * Notes: 9311 */ 9312 bcm_error_t 9313 _bcm_tr3_l3_host_stat_counter_set( 9314 int unit, 9315 bcm_l3_host_t *info, 9316 bcm_l3_stat_t stat, 9317 uint32 num_entries, 9318 uint32 *counter_indexes, 9319 bcm_stat_value_t *counter_values) 9320 { 9321 uint32 table_count=0; 9322 uint32 index_count=0; 9323 uint32 num_of_tables=0; 9324 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 9325 uint32 byte_flag=0; 9326 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 9327 if ((stat == bcmL3StatInPackets) || 9328 (stat == bcmL3StatInBytes)) { 9329 direction = bcmStatFlexDirectionIngress; 9330 } else { 9331 /* direction = bcmStatFlexDirectionEgress; */ 9332 return BCM_E_PARAM; 9333 } 9334 if (stat == bcmL3StatInPackets) { 9335 byte_flag=0; 9336 } else { 9337 byte_flag=1; 9338 } 9339 9340 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info( 9341 unit, info,&num_of_tables,&table_info[0])); 9342 9343 for (table_count=0; table_count < num_of_tables ; table_count++) { 9344 if (table_info[table_count].direction == direction) { 9345 for (index_count=0; index_count < num_entries ; index_count++) { 9346 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set( 9347 unit, 9348 table_info[table_count].index, 9349 table_info[table_count].table, 9350 0, 9351 byte_flag, 9352 counter_indexes[index_count], 9353 &counter_values[index_count])); 9354 } 9355 } 9356 } 9357 return BCM_E_NONE; 9358 } 9359 9360 /* 9361 * Function: 9362 * _bcm_tr3_l3_host_stat_id_get 9363 * Description: 9364 * Get stat counter id associated with given L3 host entry 9365 * 9366 * Parameters: 9367 * unit - (IN) unit number 9368 * info - (IN) L3 host description 9369 * stat - (IN) Type of the counter to retrieve 9370 * I.e. ingress/egress byte/packet) 9371 * Stat_counter_id - (OUT) Stat Counter ID 9372 * Return Value: 9373 * BCM_E_XXX 9374 * Notes: 9375 */ 9376 bcm_error_t 9377 _bcm_tr3_l3_host_stat_id_get( 9378 int unit, 9379 bcm_l3_host_t *info, 9380 bcm_l3_stat_t stat, 9381 uint32 *stat_counter_id) 9382 { 9383 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 9384 uint32 num_of_tables=0; 9385 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 9386 uint32 index=0; 9387 uint32 num_stat_counter_ids=0; 9388 9389 if ((stat == bcmL3StatInPackets) || 9390 (stat == bcmL3StatInBytes)) { 9391 direction = bcmStatFlexDirectionIngress; 9392 } else { 9393 /* direction = bcmStatFlexDirectionEgress; */ 9394 return BCM_E_PARAM; 9395 } 9396 9397 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info( 9398 unit,info,&num_of_tables,&table_info[0])); 9399 for (index=0; index < num_of_tables ; index++) { 9400 if (table_info[index].direction == direction) 9401 return _bcm_esw_stat_flex_get_counter_id( 9402 unit, 1, &table_info[index], 9403 &num_stat_counter_ids,stat_counter_id); 9404 } 9405 return BCM_E_NOT_FOUND; 9406 } 9407 9408 /* 9409 * Function: 9410 * _bcm_tr3_l3_multicast_nh_add 9411 * Purpose: 9412 * Set L3 multicast next hop entry. 9413 * Parameters: 9414 * unit - (IN) SOC unit number. 9415 * nh_index - (IN) Next hop index. 9416 * l3_egress - (IN) L3 egress structure. 9417 * Returns: 9418 * BCM_X_XXX 9419 */ 9420 int 9421 _bcm_tr3_l3_ipmc_nh_add(int unit, int nh_index, 9422 bcm_l3_egress_t *l3_egress) 9423 { 9424 int rv = BCM_E_NONE; 9425 int nh_index_out; 9426 ing_l3_next_hop_entry_t ing_nh; 9427 initial_ing_l3_next_hop_entry_t initial_ing_nh; 9428 egr_l3_next_hop_entry_t egr_nh; 9429 #ifdef BCM_TOMAHAWK3_SUPPORT 9430 egr_l3_next_hop_2_entry_t egr_nh_2; 9431 #endif 9432 #if defined(BCM_TRIDENT3_SUPPORT) 9433 int large_scale_nat_profile_mac = 0; 9434 #endif 9435 int i; 9436 int flag_set; 9437 int macda_index = -1, use_configured_mac = 0; 9438 #ifdef BCM_RIOT_SUPPORT 9439 uint32 nh_dest = 0; 9440 int vp; 9441 #endif 9442 uint32 flag_array[] = { 9443 BCM_L3_MULTICAST_L2_DEST_PRESERVE, 9444 BCM_L3_MULTICAST_L2_SRC_PRESERVE, 9445 BCM_L3_MULTICAST_L2_VLAN_PRESERVE, 9446 BCM_L3_MULTICAST_TTL_PRESERVE, 9447 BCM_L3_MULTICAST_DEST_PRESERVE, 9448 BCM_L3_MULTICAST_SRC_PRESERVE, 9449 BCM_L3_MULTICAST_VLAN_PRESERVE, 9450 BCM_L3_MULTICAST_L3_DROP, 9451 BCM_L3_MULTICAST_L2_DROP 9452 }; 9453 soc_field_t field_array[] = { 9454 L3MC__L2_MC_DA_DISABLEf, 9455 L3MC__L2_MC_SA_DISABLEf, 9456 L3MC__L2_MC_VLAN_DISABLEf, 9457 L3MC__L3_MC_TTL_DISABLEf, 9458 L3MC__L3_MC_DA_DISABLEf, 9459 L3MC__L3_MC_SA_DISABLEf, 9460 L3MC__L3_MC_VLAN_DISABLEf, 9461 L3MC__L3_DROPf, 9462 L3MC__L2_DROPf 9463 }; 9464 #if defined(INCLUDE_XFLOW_MACSEC) 9465 soc_field_t field = INVALIDf, field2 = INVALIDf; 9466 #endif 9467 9468 if (l3_egress->encap_id == 0) { 9469 /* encap_id does not contain a VP or a L2 egress object ID. Hence, 9470 * a L3 egress object is being created on a physical port. 9471 */ 9472 #if defined(BCM_TOMAHAWK_SUPPORT) 9473 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 9474 rv = _bcm_th_ipmc_l3_intf_next_hop_get(unit, l3_egress->intf, 9475 &nh_index_out); 9476 } else 9477 #endif /* BCM_TOMAHAWK_SUPPORT */ 9478 { 9479 rv = bcm_tr3_ipmc_l3_intf_next_hop_get(unit, l3_egress->intf, 9480 &nh_index_out); 9481 } 9482 if (rv == BCM_E_NONE) { 9483 /* IPMC module had already silently allocated a next hop index for the 9484 * L3 interface, as a result of user adding the L3 interface to an IPMC 9485 * group directly. Creating a L3 egress object based on such an L3 9486 * interface is not allowed. 9487 */ 9488 return BCM_E_CONFIG; 9489 } else if (rv == BCM_E_NOT_FOUND) { 9490 /* IPMC module has not silently allocated a next hop index for the L3 9491 * interface. Inform the IPMC module that a next hop index has been 9492 * allocated for the L3 interface by the bcm_l3_egress_create API. 9493 * This is to prevent IPMC module from silently allocating another 9494 * next hop index when user attempts to add the same L3 interface 9495 * directly to an IPMC group. Such an attempt will result in BCM_E_CONFIG. 9496 */ 9497 #if defined(BCM_TOMAHAWK_SUPPORT) 9498 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 9499 BCM_IF_ERROR_RETURN 9500 (_bcm_th_ipmc_l3_intf_next_hop_l3_egress_set(unit, 9501 l3_egress->intf)); 9502 } else 9503 #endif /* BCM_TOMAHAWK_SUPPORT */ 9504 { 9505 BCM_IF_ERROR_RETURN 9506 (bcm_tr3_ipmc_l3_intf_next_hop_l3_egress_set(unit, 9507 l3_egress->intf)); 9508 } 9509 } else { 9510 return rv; 9511 } 9512 } 9513 9514 /* Configure the ingress next hop entry. Although ingress next hop entry 9515 * is not used by IPMC packet flow, storing port and vlan info in it 9516 * allows retrieval by bcm_l3_egress_get function. 9517 */ 9518 SOC_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm, 9519 MEM_BLOCK_ANY, nh_index, &ing_nh)); 9520 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, 9521 VLAN_IDf, l3_egress->vlan); 9522 9523 #ifdef BCM_RIOT_SUPPORT 9524 /* 9525 * TD2+ has a separate encoding values for different destinations. 9526 * If Riot in not enabled then we may need to change this to 9527 * modid + port combination. 9528 */ 9529 if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 9530 BCM_IF_ERROR_RETURN( 9531 bcmi_l3_nh_dest_set(unit, l3_egress, &nh_dest)); 9532 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf, 9533 nh_dest); 9534 } else 9535 #ifdef BCM_TRIDENT3_SUPPORT 9536 if (soc_feature(unit, soc_feature_generic_dest)) { 9537 /* This can handle non-RIOT cases as well */ 9538 bcmi_td3_l3_nh_dest_set(unit, l3_egress, &nh_dest); 9539 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf, 9540 nh_dest); 9541 } else 9542 #endif /* BCM_TRIDENT3_SUPPORT */ 9543 #endif /* BCM_RIOT_SUPPORT */ 9544 { 9545 /* Set module id. */ 9546 if (l3_egress->flags & BCM_L3_TGID) { 9547 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 1); 9548 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, TGIDf, 9549 l3_egress->port); 9550 } else { 9551 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 0); 9552 if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, MODULE_IDf)) { 9553 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf, 9554 l3_egress->module); 9555 } 9556 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, PORT_NUMf, 9557 l3_egress->port); 9558 } 9559 } 9560 9561 SOC_IF_ERROR_RETURN(soc_mem_write(unit, ING_L3_NEXT_HOPm, 9562 MEM_BLOCK_ALL, nh_index, &ing_nh)); 9563 9564 /* Keep initial ingress next hop entry consistent with 9565 * ingress next hop entry */ 9566 if (SOC_MEM_IS_VALID(unit, INITIAL_ING_L3_NEXT_HOPm)) { 9567 SOC_IF_ERROR_RETURN(soc_mem_read(unit, INITIAL_ING_L3_NEXT_HOPm, 9568 MEM_BLOCK_ANY, nh_index, &initial_ing_nh)); 9569 } 9570 9571 #ifdef BCM_RIOT_SUPPORT 9572 /* 9573 * TD2+ has a separate encoding values for different destinations. 9574 * If Riot in not enabled then we may need to change this to 9575 * modid + port combination. 9576 */ 9577 if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 9578 BCM_IF_ERROR_RETURN( 9579 bcmi_l3_nh_dest_set(unit, l3_egress, &nh_dest)); 9580 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf, 9581 nh_dest); 9582 } else 9583 #ifdef BCM_TRIDENT3_SUPPORT 9584 if (soc_feature(unit, soc_feature_generic_dest)) { 9585 bcmi_td3_l3_nh_dest_set(unit, l3_egress, &nh_dest); 9586 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf, 9587 nh_dest); 9588 } else 9589 #endif /* BCM_TRIDENT3_SUPPORT */ 9590 #endif /* BCM_RIOT_SUPPORT */ 9591 if (SOC_MEM_IS_VALID(unit, INITIAL_ING_L3_NEXT_HOPm)) { 9592 if (l3_egress->flags & BCM_L3_TGID) { 9593 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh, 9594 Tf, 1); 9595 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh, 9596 TGIDf, l3_egress->port); 9597 } else { 9598 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh, 9599 Tf, 0); 9600 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh, 9601 MODULE_IDf, l3_egress->module); 9602 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh, 9603 PORT_NUMf, l3_egress->port); 9604 } 9605 } 9606 9607 if (SOC_MEM_IS_VALID(unit, INITIAL_ING_L3_NEXT_HOPm)) { 9608 SOC_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm, 9609 MEM_BLOCK_ALL, nh_index, &initial_ing_nh)); 9610 } 9611 9612 #ifdef BCM_TRIDENT3_SUPPORT 9613 if (soc_feature(unit, soc_feature_flex_flow) && 9614 (l3_egress->flow_handle != 0)) { 9615 9616 return _bcm_td3_l3_flex_nh_add(unit, nh_index, l3_egress, (uint32 *)&egr_nh, 1); 9617 } 9618 #endif 9619 /* Configure the egress next hop entry */ 9620 SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 9621 MEM_BLOCK_ANY, nh_index, &egr_nh)); 9622 #if defined(BCM_TRIDENT3_SUPPORT) 9623 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 9624 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, DATA_TYPEf, 7); 9625 } else 9626 #endif 9627 { 9628 #ifdef BCM_TOMAHAWK3_SUPPORT 9629 if (SOC_IS_TOMAHAWK3(unit)) { 9630 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, ENTRY_TYPEf, 3); 9631 SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOP_2m, 9632 MEM_BLOCK_ANY, nh_index, &egr_nh_2)); 9633 } else 9634 #endif 9635 { 9636 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, ENTRY_TYPEf, 7); 9637 } 9638 } 9639 #ifdef BCM_TOMAHAWK3_SUPPORT 9640 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 9641 soc_mem_field32_set(unit, EGR_L3_NEXT_HOP_2m, &egr_nh_2, 9642 INTF_NUMf, l3_egress->intf); 9643 } else 9644 #endif 9645 { 9646 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9647 L3MC__INTF_NUMf, l3_egress->intf); 9648 } 9649 9650 for (i = 0; i < COUNTOF(flag_array); i++) { 9651 if (l3_egress->multicast_flags & flag_array[i]) { 9652 flag_set = 1; 9653 } else { 9654 flag_set = 0; 9655 } 9656 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, field_array[i])) { 9657 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9658 field_array[i], flag_set); 9659 } else { 9660 if (flag_set) { 9661 return BCM_E_PARAM; 9662 } 9663 } 9664 } 9665 9666 #ifdef BCM_TRIDENT2_SUPPORT 9667 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 9668 int vp; 9669 bcm_niv_port_t niv_port; 9670 int count; 9671 bcm_niv_egress_t niv_egress; 9672 int multicast_flag; 9673 int virtual_interface_id; 9674 bcm_extender_port_t eport; 9675 int l2_egr_nh_index; 9676 egr_l3_next_hop_entry_t l2_egr_nh; 9677 int etag_dot1p_mapping_ptr = 0; 9678 bcm_extender_egress_t extender_egress; 9679 uint16 extended_port_vid; 9680 uint8 pcp, de; 9681 uint32 pcp_de_select; 9682 int qos_map_id; 9683 9684 if (l3_egress->encap_id > 0 && 9685 l3_egress->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) { 9686 vp = l3_egress->encap_id; 9687 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 9688 if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) { 9689 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9690 L3MC__NEXT_PTR_TYPEf, 1); 9691 } else 9692 #endif 9693 { 9694 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9695 L3MC__DVP_VALIDf, 1); 9696 } 9697 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9698 L3MC__DVPf, vp); 9699 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 9700 bcm_niv_port_t_init(&niv_port); 9701 BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, vp); 9702 BCM_IF_ERROR_RETURN 9703 (bcm_esw_niv_port_get(unit, &niv_port)); 9704 if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) { 9705 BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit, 9706 niv_port.niv_port_id, 1, &niv_egress, &count)); 9707 if (count == 0) { 9708 /* No NIV egress object has been added to VP yet. */ 9709 return BCM_E_CONFIG; 9710 } 9711 multicast_flag = (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) ? 1 : 0; 9712 if (multicast_flag) { 9713 /* Multiple multicast NIV egress object can be 9714 * overloaded onto the same VP. In such cases, 9715 * L3 egress object should be created on individual 9716 * NIV egress object, not the overloaded NIV VP. 9717 */ 9718 return BCM_E_PARAM; 9719 } 9720 virtual_interface_id = niv_egress.virtual_interface_id; 9721 } else { 9722 multicast_flag = (niv_port.flags & BCM_NIV_PORT_MULTICAST) ? 1 : 0; 9723 virtual_interface_id = niv_port.virtual_interface_id; 9724 } 9725 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9726 L3MC__VNTAG_ACTIONSf, 1); /* Add or replace VNTAG */ 9727 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9728 L3MC__VNTAG_DST_VIFf, virtual_interface_id); 9729 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9730 L3MC__VNTAG_Pf, multicast_flag); 9731 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9732 L3MC__VNTAG_FORCE_Lf, 0); 9733 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) { 9734 bcm_extender_port_t_init(&eport); 9735 BCM_GPORT_EXTENDER_PORT_ID_SET(eport.extender_port_id, vp); 9736 BCM_IF_ERROR_RETURN 9737 (bcm_esw_extender_port_get(unit, &eport)); 9738 if (eport.flags & BCM_EXTENDER_PORT_MATCH_NONE) { 9739 bcm_extender_egress_t_init(&extender_egress); 9740 BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit, 9741 eport.extender_port_id, 1, &extender_egress, &count)); 9742 if (count == 0) { 9743 /* No Extender egress object has been added to VP yet. */ 9744 return BCM_E_CONFIG; 9745 } 9746 if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) { 9747 return BCM_E_PARAM; 9748 } 9749 qos_map_id = extender_egress.qos_map_id; 9750 extended_port_vid = extender_egress.extended_port_vid; 9751 pcp_de_select = extender_egress.pcp_de_select; 9752 pcp = extender_egress.pcp; 9753 de = extender_egress.de; 9754 } else { 9755 qos_map_id = eport.qos_map_id; 9756 extended_port_vid = eport.extended_port_vid; 9757 pcp_de_select = eport.pcp_de_select; 9758 pcp = eport.pcp; 9759 de = eport.de; 9760 } 9761 9762 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9763 L3MC__VNTAG_ACTIONSf, 2); /* Add or replace ETAG */ 9764 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9765 L3MC__VNTAG_DST_VIFf, extended_port_vid); 9766 if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_DEFAULT) { 9767 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9768 L3MC__ETAG_PCP_DE_SOURCEf, 2); 9769 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9770 L3MC__ETAG_PCPf, pcp); 9771 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9772 L3MC__ETAG_DEf, de); 9773 } else if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_PHB) { 9774 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9775 L3MC__ETAG_PCP_DE_SOURCEf, 3); 9776 bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id, 9777 &etag_dot1p_mapping_ptr); 9778 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9779 L3MC__ETAG_DOT1P_MAPPING_PTRf, etag_dot1p_mapping_ptr); 9780 } 9781 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) { 9782 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9783 L3MC__VNTAG_ACTIONSf, 0); /* NOOP */ 9784 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) { 9785 } else { 9786 return BCM_E_PARAM; 9787 } 9788 } else if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, l3_egress->encap_id)) { 9789 uint32 entry_type; 9790 /* Creating a L3 egress objet on a L2 egress objet */ 9791 l2_egr_nh_index = l3_egress->encap_id - BCM_XGS3_EGRESS_IDX_MIN(unit); 9792 SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 9793 MEM_BLOCK_ANY, l2_egr_nh_index, &l2_egr_nh)); 9794 #if defined(BCM_TRIDENT3_SUPPORT) 9795 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 9796 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &l2_egr_nh, 9797 DATA_TYPEf); 9798 } else 9799 #endif 9800 { 9801 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &l2_egr_nh, 9802 ENTRY_TYPEf); 9803 } 9804 if (2 != entry_type) { 9805 return BCM_E_PARAM; 9806 } 9807 vp = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &l2_egr_nh, 9808 SD_TAG__DVPf); 9809 if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 9810 return BCM_E_PARAM; 9811 } 9812 multicast_flag = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 9813 &l2_egr_nh, SD_TAG__VNTAG_Pf); 9814 if (!multicast_flag) { 9815 return BCM_E_PARAM; 9816 } 9817 virtual_interface_id = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 9818 &l2_egr_nh, SD_TAG__VNTAG_DST_VIFf); 9819 9820 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 9821 if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) { 9822 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9823 L3MC__NEXT_PTR_TYPEf, 1); 9824 } else 9825 #endif 9826 { 9827 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9828 L3MC__DVP_VALIDf, 1); 9829 } 9830 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9831 L3MC__DVPf, vp); 9832 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9833 L3MC__VNTAG_ACTIONSf, 1); /* Add or replace VNTAG */ 9834 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9835 L3MC__VNTAG_DST_VIFf, virtual_interface_id); 9836 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9837 L3MC__VNTAG_Pf, multicast_flag); 9838 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9839 L3MC__VNTAG_FORCE_Lf, 0); 9840 } else { 9841 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 9842 if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) { 9843 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9844 L3MC__NEXT_PTR_TYPEf, 0); 9845 } else 9846 #endif 9847 { 9848 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9849 L3MC__DVP_VALIDf, 0); 9850 } 9851 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9852 L3MC__VNTAG_ACTIONSf, 0); /* NOOP */ 9853 } 9854 } 9855 #endif /* BCM_TRIDENT2_SUPPORT */ 9856 9857 #ifdef BCM_RIOT_SUPPORT 9858 /* 9859 * TD2Plus and TD3 have multi layer routing. 9860 * The multicast packet can be routed in the overlay 9861 * layer and then underlay encapsulation is performed. 9862 * To achieve this, there will be overlay egr nexthop association 9863 * with undelray egress next hop. 9864 * the overlay egr nexthop will point to underlay next hop. 9865 */ 9866 if (BCMI_RIOT_IS_ENABLED(unit) && 9867 _bcm_vp_vfi_type_vp_get(unit, l3_egress->port, &vp)) { 9868 /* This is a overlay NH case */ 9869 ing_dvp_table_entry_t dvp; 9870 int vp_nh_index; 9871 /* Get the vp */ 9872 SOC_IF_ERROR_RETURN 9873 (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp)); 9874 9875 /* read vp to get next hop */ 9876 vp_nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 9877 NEXT_HOP_INDEXf); 9878 9879 /* 9880 * check if nh-nh association is needed. 9881 * else set up nh-dvp association 9882 * NH-NH association will be done for all the 9883 * nhs other than SDTAG which does not modify any packets field. 9884 * e.g. on access ports, it may be needed to change a vlan/tpid, 9885 * in that case, we may have to set nh-nh association else we may 9886 * setup vlan/tpid from DVP. 9887 */ 9888 if (bcmi_l3_nh_assoc_ol_ul_link_is_required(unit, vp_nh_index)) { 9889 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9890 L3MC__NEXT_PTR_TYPEf, BCMI_L3_NH_EGR_NEXT_PTR_TYPE_NH); 9891 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9892 L3MC__NEXT_PTRf, vp_nh_index); 9893 /* Set up the association of NHs in sw */ 9894 BCM_IF_ERROR_RETURN( 9895 bcmi_l3_nh_assoc_ol_ul_link_sw_add(unit, nh_index, 9896 vp_nh_index)); 9897 } else { 9898 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9899 L3MC__NEXT_PTR_TYPEf, BCMI_L3_NH_EGR_NEXT_PTR_TYPE_DVP); 9900 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9901 L3MC__NEXT_PTRf, vp); 9902 } 9903 } 9904 #endif 9905 9906 #if defined(BCM_TRIDENT3_SUPPORT) 9907 if (soc_feature(unit, soc_feature_large_scale_nat) && 9908 l3_egress->replication_id != 0 && 9909 soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__EH_QUEUE_TAGf) && 9910 soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_DA_PROFILE_INDEXf) && 9911 soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__USE_MAC_DA_PROFILEf)) { 9912 /* large scale MC nat uses EH_QUEUE_TAGf with MAC_DA_PROFILE_INDEXf */ 9913 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9914 L3MC__EH_QUEUE_TAGf, l3_egress->replication_id); 9915 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9916 L3MC__EH_TAG_TYPEf, 0x1); 9917 large_scale_nat_profile_mac = 1; 9918 } 9919 #endif /* BCM_TRIDENT3_SUPPORT */ 9920 9921 #if defined(INCLUDE_XFLOW_MACSEC) 9922 if (soc_feature(unit, soc_feature_xflow_macsec) && 9923 ((l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) || 9924 (l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) { 9925 uint32 entry_type; 9926 egr_mac_da_profile_entry_t macda; 9927 void *entries[1] = { NULL }; 9928 9929 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 9930 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, 9931 DATA_TYPEf); 9932 } else 9933 { 9934 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, 9935 ENTRY_TYPEf); 9936 } 9937 switch (entry_type) { 9938 case 7: 9939 field = L3MC__MACSEC_ENCRYPTf; 9940 field2 = L3MC__MACSEC_DECRYPTf; 9941 break; 9942 default: 9943 break; 9944 } 9945 if ((field != INVALIDf) && (field2 != INVALIDf)) { 9946 if (l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) { 9947 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field, 1); 9948 } else { 9949 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field, 0); 9950 } 9951 9952 if (l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT) { 9953 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field2, 1); 9954 } else { 9955 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field2, 0); 9956 } 9957 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9958 L3MC__HG_MC_DST_MODIDf, l3_egress->module); 9959 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9960 L3MC__HG_MC_DST_PORT_NUMf, l3_egress->port); 9961 9962 sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t)); 9963 soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm, 9964 &macda, MAC_ADDRESSf, l3_egress->mac_addr); 9965 entries[0] = &macda; 9966 rv = _bcm_mac_da_profile_entry_add(unit, entries, 1, 9967 (uint32 *)&macda_index); 9968 if (BCM_FAILURE(rv)) { 9969 goto cleanup; 9970 } 9971 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9972 L3MC__MAC_DA_PROFILE_INDEXf, macda_index); 9973 9974 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9975 L3MC__USE_MAC_DA_PROFILEf, 1); 9976 use_configured_mac = 1; 9977 } 9978 } else 9979 #endif 9980 /* 9981 * TD2Plus has a overlaid mac_address. 9982 * This mac_address field may be overlaid by some other fields 9983 * used for CoE/HG feature. Meanwhile a mac_da_profile_index 9984 * is present for the actual mac_address. 9985 * This index points to EGR_MAC_DA_PROFILE, which is managed in 9986 * Profile mechanism. 9987 */ 9988 #ifdef BCM_HGPROXY_COE_SUPPORT 9989 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 9990 L3MC__MAC_DA_PROFILE_INDEXf) && 9991 _bcm_xgs5_subport_coe_mod_port_local(unit, l3_egress->module, 9992 l3_egress->port)) { 9993 egr_mac_da_profile_entry_t macda; 9994 void *entries[1] = { NULL }; 9995 9996 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 9997 L3MC__USE_MAC_DA_PROFILEf)) { 9998 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 9999 L3MC__USE_MAC_DA_PROFILEf, 1); 10000 } 10001 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 10002 L3MC__HG_MC_DST_MODIDf)) { 10003 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10004 L3MC__HG_MC_DST_MODIDf, l3_egress->module); 10005 } 10006 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 10007 L3MC__HG_MC_DST_PORT_NUMf)) { 10008 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10009 L3MC__HG_MC_DST_PORT_NUMf, l3_egress->port); 10010 } 10011 10012 sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t)); 10013 soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm, 10014 &macda, MAC_ADDRESSf, l3_egress->mac_addr); 10015 entries[0] = &macda; 10016 rv = _bcm_mac_da_profile_entry_add(unit, entries, 1, 10017 (uint32 *)&macda_index); 10018 if (BCM_FAILURE(rv)) { 10019 goto cleanup; 10020 } 10021 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10022 L3MC__MAC_DA_PROFILE_INDEXf, macda_index); 10023 use_configured_mac = 1; 10024 10025 } else 10026 #endif 10027 #if defined(BCM_TRIDENT3_SUPPORT) 10028 if (large_scale_nat_profile_mac == 1) { 10029 egr_mac_da_profile_entry_t macda; 10030 void *entries[1] = { NULL }; 10031 10032 sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t)); 10033 soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm, 10034 &macda, MAC_ADDRESSf, l3_egress->mac_addr); 10035 entries[0] = &macda; 10036 rv = _bcm_mac_da_profile_entry_add(unit, entries, 1, 10037 (uint32 *)&macda_index); 10038 10039 if (BCM_FAILURE(rv)) { 10040 goto cleanup; 10041 } 10042 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10043 L3MC__MAC_DA_PROFILE_INDEXf, macda_index); 10044 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10045 L3MC__USE_MAC_DA_PROFILEf, 1); 10046 use_configured_mac = 1; 10047 } else 10048 #endif /* BCM_TRIDENT3_SUPPORT */ 10049 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_ADDRESSf)) { 10050 soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10051 L3MC__MAC_ADDRESSf, l3_egress->mac_addr); 10052 use_configured_mac = 1; 10053 } else { 10054 if (!BCM_MAC_IS_ZERO(l3_egress->mac_addr)) { 10055 return BCM_E_PARAM; 10056 } 10057 } 10058 if (use_configured_mac) { 10059 if (BCM_MAC_IS_ZERO(l3_egress->mac_addr)) { 10060 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10061 L3MC__L3MC_USE_CONFIGURED_MACf, 0); 10062 } else { 10063 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 10064 L3MC__L3MC_USE_CONFIGURED_MACf, 1); 10065 } 10066 } 10067 10068 rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, 10069 MEM_BLOCK_ALL, nh_index, &egr_nh); 10070 #ifdef BCM_TOMAHAWK3_SUPPORT 10071 if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) { 10072 rv = soc_mem_write(unit, EGR_L3_NEXT_HOP_2m, 10073 MEM_BLOCK_ALL, nh_index, &egr_nh_2); 10074 } 10075 #endif 10076 if (BCM_FAILURE(rv)) { 10077 goto cleanup; 10078 } 10079 return BCM_E_NONE; 10080 10081 cleanup: 10082 if (macda_index != -1) { 10083 (void) _bcm_mac_da_profile_entry_delete(unit, macda_index); 10084 } 10085 return rv; 10086 } 10087 10088 /* 10089 * Function: 10090 * _bcm_tr3_l3_ipmc_nh_entry_parse 10091 * Purpose: 10092 * Parse L3 multicast next hop entry. 10093 * Parameters: 10094 * unit - (IN) SOC unit number. 10095 * ing_nh - (IN) Ingress next hop table entry. 10096 * egr_nh - (IN) Egress next hop table entry. 10097 * l3_egress - (OUT) L3 egress structure. 10098 * Returns: 10099 * BCM_E_XXX 10100 */ 10101 int 10102 _bcm_tr3_l3_ipmc_nh_entry_parse(int unit, uint32 *ing_nh, 10103 uint32 *egr_nh, uint32 *egr_nh_2, bcm_l3_egress_t *l3_egress) 10104 { 10105 bcm_module_t module = 0, module_out = 0; 10106 bcm_port_t port = 0, port_out = 0; 10107 int i; 10108 uint32 flag_array[] = { 10109 BCM_L3_MULTICAST_L2_DEST_PRESERVE, 10110 BCM_L3_MULTICAST_L2_SRC_PRESERVE, 10111 BCM_L3_MULTICAST_L2_VLAN_PRESERVE, 10112 BCM_L3_MULTICAST_TTL_PRESERVE, 10113 BCM_L3_MULTICAST_DEST_PRESERVE, 10114 BCM_L3_MULTICAST_SRC_PRESERVE, 10115 BCM_L3_MULTICAST_VLAN_PRESERVE, 10116 BCM_L3_MULTICAST_L3_DROP, 10117 BCM_L3_MULTICAST_L2_DROP 10118 }; 10119 soc_field_t field_array[] = { 10120 L3MC__L2_MC_DA_DISABLEf, 10121 L3MC__L2_MC_SA_DISABLEf, 10122 L3MC__L2_MC_VLAN_DISABLEf, 10123 L3MC__L3_MC_TTL_DISABLEf, 10124 L3MC__L3_MC_DA_DISABLEf, 10125 L3MC__L3_MC_SA_DISABLEf, 10126 L3MC__L3_MC_VLAN_DISABLEf, 10127 L3MC__L3_DROPf, 10128 L3MC__L2_DROPf 10129 }; 10130 10131 10132 #ifdef BCM_RIOT_SUPPORT 10133 if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 10134 uint32 nh_dest = 0; 10135 nh_dest = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 10136 ing_nh, DESTINATIONf); 10137 bcmi_get_port_from_destination(unit, nh_dest, l3_egress); 10138 if (l3_egress->flags == BCM_L3_TGID) { 10139 l3_egress->trunk = l3_egress->port; 10140 } 10141 } else 10142 #endif 10143 { 10144 /* Get trunk or module and port */ 10145 #if defined(BCM_TRIDENT3_SUPPORT) 10146 if (soc_feature(unit, soc_feature_generic_dest)) { 10147 uint32 dest_val = 0, dest_type = 0; 10148 int dvp_gport = 0; 10149 dest_val = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, ing_nh, 10150 DESTINATIONf, &dest_type); 10151 if (dest_type == SOC_MEM_FIF_DEST_LAG) { 10152 l3_egress->flags |= BCM_L3_TGID; 10153 l3_egress->trunk = dest_val & SOC_MEM_FIF_DGPP_TGID_MASK; 10154 } else if (dest_type == SOC_MEM_FIF_DEST_DGPP) { 10155 port = (dest_val & SOC_MEM_FIF_DGPP_PORT_MASK); 10156 module = (dest_val & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >> 10157 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS; 10158 BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, 10159 BCM_STK_MODMAP_GET, module, port, &module_out, &port_out)); 10160 l3_egress->module = module_out; 10161 l3_egress->port = port_out; 10162 } else if (dest_type == SOC_MEM_FIF_DEST_DVP) { 10163 _bcm_vp_encode_gport(unit, dest_val, &dvp_gport); 10164 l3_egress->port = dvp_gport; 10165 } 10166 } else 10167 #endif /* BCM_TRIDENT3_SUPPORT */ 10168 { 10169 if (soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh, Tf)) { 10170 l3_egress->flags |= BCM_L3_TGID; 10171 l3_egress->trunk = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 10172 ing_nh, TGIDf); 10173 } else { 10174 port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh, 10175 PORT_NUMf); 10176 if (!SOC_IS_TOMAHAWK3(unit)) { 10177 module = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh, 10178 MODULE_IDf); 10179 10180 BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 10181 module, port, &module_out, &port_out)); 10182 } else { 10183 module_out = 0; 10184 port_out = port; 10185 } 10186 l3_egress->module = module_out; 10187 l3_egress->port = port_out; 10188 } 10189 } 10190 } 10191 10192 /* Get VLAN */ 10193 l3_egress->vlan = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh, 10194 VLAN_IDf); 10195 10196 /* Get L3 interface */ 10197 if (SOC_IS_TOMAHAWK3(unit)) { 10198 l3_egress->intf = soc_mem_field32_get(unit, EGR_L3_NEXT_HOP_2m, egr_nh_2, 10199 INTF_NUMf); 10200 } else { 10201 l3_egress->intf = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10202 L3MC__INTF_NUMf); 10203 } 10204 10205 /* Get L3 multicast flags */ 10206 for (i = 0; i < COUNTOF(field_array); i++) { 10207 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, field_array[i])) { 10208 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10209 field_array[i])) { 10210 l3_egress->multicast_flags |= flag_array[i]; 10211 } 10212 } 10213 } 10214 10215 /* Get MAC address */ 10216 #ifdef BCM_TRIDENT3_SUPPORT 10217 if (soc_feature(unit, soc_feature_large_scale_nat) && 10218 soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_DA_PROFILE_INDEXf) && 10219 soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__USE_MAC_DA_PROFILEf) && 10220 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, L3MC__USE_MAC_DA_PROFILEf)) { 10221 egr_mac_da_profile_entry_t macda; 10222 int macda_index = -1; 10223 10224 macda_index = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10225 L3MC__MAC_DA_PROFILE_INDEXf); 10226 10227 /* Read entry from MAC-DA-PROFILEm */ 10228 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm, 10229 MEM_BLOCK_ANY, macda_index, &macda)); 10230 10231 /* Get mac address from EGR_MACDA_PROFILE. */ 10232 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, &macda, 10233 MAC_ADDRESSf, l3_egress->mac_addr); 10234 } else 10235 #endif /* BCM_TRIDENT3_SUPPORT */ 10236 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_ADDRESSf)) { 10237 soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10238 L3MC__MAC_ADDRESSf, l3_egress->mac_addr); 10239 } 10240 10241 #if defined(BCM_TRIDENT3_SUPPORT) 10242 if (soc_feature(unit, soc_feature_large_scale_nat) && 10243 soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__EH_QUEUE_TAGf)) { 10244 l3_egress->replication_id = soc_mem_field32_get(unit, 10245 EGR_L3_NEXT_HOPm, egr_nh, L3MC__EH_QUEUE_TAGf); 10246 } 10247 #endif 10248 #ifdef BCM_TRIDENT2_SUPPORT 10249 if (soc_feature(unit, soc_feature_virtual_port_routing)) { 10250 int vp; 10251 int multicast_flag; 10252 int virtual_interface_id; 10253 bcm_niv_port_t niv_port; 10254 int count; 10255 bcm_niv_egress_t *niv_egress_array; 10256 int rv; 10257 int dvp_valid = 0; 10258 10259 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 10260 if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) { 10261 dvp_valid = (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10262 L3MC__NEXT_PTR_TYPEf) & 0x1); 10263 } else 10264 #endif 10265 { 10266 dvp_valid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10267 L3MC__DVP_VALIDf); 10268 } 10269 if (dvp_valid) { 10270 vp = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10271 L3MC__DVPf); 10272 l3_egress->encap_id = vp; 10273 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 10274 /* If the VP is of NIV type, need to determine if a NIV 10275 * egress object ID needs to be returned in encap_id. 10276 */ 10277 multicast_flag = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 10278 egr_nh, L3MC__VNTAG_Pf); 10279 virtual_interface_id = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 10280 egr_nh, L3MC__VNTAG_DST_VIFf); 10281 if (multicast_flag) { 10282 bcm_niv_port_t_init(&niv_port); 10283 BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, vp); 10284 BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port)); 10285 if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) { 10286 BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit, 10287 niv_port.niv_port_id, 0, NULL, &count)); 10288 if (count > 0) { 10289 niv_egress_array = sal_alloc 10290 (count * sizeof(bcm_niv_egress_t), 10291 "niv_egress_array"); 10292 if (NULL == niv_egress_array) { 10293 return BCM_E_MEMORY; 10294 } 10295 rv = bcm_esw_niv_egress_get(unit, niv_port.niv_port_id, 10296 count, niv_egress_array, &count); 10297 if (BCM_FAILURE(rv)) { 10298 sal_free(niv_egress_array); 10299 return rv; 10300 } 10301 for (i = 0; i < count; i++) { 10302 if (virtual_interface_id == 10303 niv_egress_array[i].virtual_interface_id) { 10304 break; 10305 } 10306 } 10307 if (i == count) { 10308 sal_free(niv_egress_array); 10309 return BCM_E_NOT_FOUND; 10310 } 10311 l3_egress->encap_id = niv_egress_array[i].egress_if; 10312 sal_free(niv_egress_array); 10313 } else { 10314 return BCM_E_INTERNAL; 10315 } 10316 } 10317 } 10318 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) { 10319 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10320 L3MC__L3_DROPf)) { 10321 l3_egress->multicast_flags |= BCM_L3_MULTICAST_L3_DROP; 10322 } 10323 if (l3_egress->port == 0) { 10324 l3_egress->flags2 |= BCM_L3_FLAGS2_UNDERLAY; 10325 } 10326 } 10327 } 10328 } 10329 #endif /* BCM_TRIDENT2_SUPPORT */ 10330 10331 /* Set IPMC flag */ 10332 l3_egress->flags |= BCM_L3_IPMC; 10333 10334 #if defined(INCLUDE_XFLOW_MACSEC) 10335 if (soc_feature(unit, soc_feature_xflow_macsec)) { 10336 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, L3MC__MACSEC_ENCRYPTf) && 10337 (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10338 L3MC__MACSEC_ENCRYPTf))) { 10339 l3_egress->flags2 |= BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT; 10340 } 10341 if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, L3MC__MACSEC_DECRYPTf) && 10342 (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, 10343 L3MC__MACSEC_DECRYPTf))) { 10344 l3_egress->flags2 |= BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT; 10345 } 10346 } 10347 #endif 10348 return BCM_E_NONE; 10349 } 10350 10351 10352 #ifdef BCM_WARM_BOOT_SUPPORT 10353 10354 /* 10355 * Function: 10356 * bcm_tr3_ecmp_dlb_wb_alloc_size_get 10357 * Purpose: 10358 * Get level 2 warm boot scache size for ECMP DLB. 10359 * Parameters: 10360 * unit - (IN) SOC unit number. 10361 * size - (OUT) Allocation size. 10362 * Returns: 10363 * BCM_E_XXX 10364 */ 10365 int 10366 bcm_tr3_ecmp_dlb_wb_alloc_size_get(int unit, int *size) 10367 { 10368 int alloc_size = 0; 10369 int num_elements; 10370 10371 /* Allocate size for the following ECMP DLB parameters: 10372 * int ecmp_dlb_sample_rate; 10373 * int ecmp_dlb_tx_load_min_th; 10374 * int ecmp_dlb_tx_load_max_th; 10375 * int ecmp_dlb_qsize_min_th; 10376 * int ecmp_dlb_qsize_max_th; 10377 * int ecmp_dlb_exp_load_min_th; 10378 * int ecmp_dlb_exp_load_max_th; 10379 * int ecmp_dlb_imbalance_min_th; 10380 * int ecmp_dlb_imbalance_max_th; 10381 */ 10382 alloc_size += sizeof(int) * 9; 10383 10384 /* Allocate size of ecmp_dlb_load_weight array */ 10385 num_elements = 1 << soc_mem_field_length(unit, 10386 DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf); 10387 alloc_size += sizeof(uint8) * num_elements; 10388 10389 *size = alloc_size; 10390 10391 return BCM_E_NONE; 10392 } 10393 10394 /* 10395 * Function: 10396 * bcm_tr3_ecmp_dlb_sync 10397 * Purpose: 10398 * Store ECMP DLB parameters into scache. 10399 * Parameters: 10400 * unit - (IN) SOC unit number. 10401 * scache_ptr - (IN/OUT) Scache pointer 10402 * Returns: 10403 * BCM_E_XXX 10404 */ 10405 int 10406 bcm_tr3_ecmp_dlb_sync(int unit, uint8 **scache_ptr) 10407 { 10408 int value; 10409 int num_elements; 10410 int i; 10411 uint8 load_weight; 10412 10413 /* Store the following ECMP DLB parameters: 10414 * int ecmp_dlb_sample_rate; 10415 * int ecmp_dlb_tx_load_min_th; 10416 * int ecmp_dlb_tx_load_max_th; 10417 * int ecmp_dlb_qsize_min_th; 10418 * int ecmp_dlb_qsize_max_th; 10419 * int ecmp_dlb_exp_load_min_th; 10420 * int ecmp_dlb_exp_load_max_th; 10421 * int ecmp_dlb_imbalance_min_th; 10422 * int ecmp_dlb_imbalance_max_th; 10423 */ 10424 value = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate; 10425 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10426 (*scache_ptr) += sizeof(int); 10427 10428 value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th; 10429 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10430 (*scache_ptr) += sizeof(int); 10431 10432 value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th; 10433 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10434 (*scache_ptr) += sizeof(int); 10435 10436 value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th; 10437 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10438 (*scache_ptr) += sizeof(int); 10439 10440 value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th; 10441 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10442 (*scache_ptr) += sizeof(int); 10443 10444 value = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th; 10445 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10446 (*scache_ptr) += sizeof(int); 10447 10448 value = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th; 10449 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10450 (*scache_ptr) += sizeof(int); 10451 10452 value = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th; 10453 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10454 (*scache_ptr) += sizeof(int); 10455 10456 value = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th; 10457 sal_memcpy((*scache_ptr), &value, sizeof(int)); 10458 (*scache_ptr) += sizeof(int); 10459 10460 /* Store ecmp_dlb_load_weight array */ 10461 num_elements = 1 << soc_mem_field_length(unit, 10462 DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf); 10463 for (i = 0; i < num_elements; i++) { 10464 load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i]; 10465 sal_memcpy((*scache_ptr), &load_weight, sizeof(uint8)); 10466 (*scache_ptr) += sizeof(uint8); 10467 } 10468 10469 return BCM_E_NONE; 10470 } 10471 10472 /* 10473 * Function: 10474 * bcm_tr3_ecmp_dlb_scache_recover 10475 * Purpose: 10476 * Recover ECMP DLB parameters from scache. 10477 * Parameters: 10478 * unit - (IN) SOC unit number. 10479 * scache_ptr - (IN/OUT) Scache pointer 10480 * Returns: 10481 * BCM_E_XXX 10482 */ 10483 int 10484 bcm_tr3_ecmp_dlb_scache_recover(int unit, uint8 **scache_ptr) 10485 { 10486 int value; 10487 int num_elements; 10488 int i; 10489 uint8 load_weight; 10490 10491 /* Recover the following ECMP DLB parameters: 10492 * int ecmp_dlb_sample_rate; 10493 * int ecmp_dlb_tx_load_min_th; 10494 * int ecmp_dlb_tx_load_max_th; 10495 * int ecmp_dlb_qsize_min_th; 10496 * int ecmp_dlb_qsize_max_th; 10497 * int ecmp_dlb_exp_load_min_th; 10498 * int ecmp_dlb_exp_load_max_th; 10499 * int ecmp_dlb_imbalance_min_th; 10500 * int ecmp_dlb_imbalance_max_th; 10501 */ 10502 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10503 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = value; 10504 (*scache_ptr) += sizeof(int); 10505 10506 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10507 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = value; 10508 (*scache_ptr) += sizeof(int); 10509 10510 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10511 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = value; 10512 (*scache_ptr) += sizeof(int); 10513 10514 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10515 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = value; 10516 (*scache_ptr) += sizeof(int); 10517 10518 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10519 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = value; 10520 (*scache_ptr) += sizeof(int); 10521 10522 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10523 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th = value; 10524 (*scache_ptr) += sizeof(int); 10525 10526 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10527 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th = value; 10528 (*scache_ptr) += sizeof(int); 10529 10530 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10531 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th = value; 10532 (*scache_ptr) += sizeof(int); 10533 10534 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 10535 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th = value; 10536 (*scache_ptr) += sizeof(int); 10537 10538 /* Recover ecmp_dlb_load_weight array */ 10539 num_elements = 1 << soc_mem_field_length(unit, 10540 DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf); 10541 for (i = 0; i < num_elements; i++) { 10542 sal_memcpy(&load_weight, (*scache_ptr), sizeof(uint8)); 10543 ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i] = load_weight; 10544 (*scache_ptr) += sizeof(uint8); 10545 } 10546 10547 ECMP_DLB_INFO(unit)->recovered_from_scache = TRUE; 10548 10549 return BCM_E_NONE; 10550 } 10551 10552 /* 10553 * Function: 10554 * _bcm_tr3_ecmp_dlb_member_recover 10555 * Purpose: 10556 * Recover ECMP DLB member ID usage and the next hop indices associated 10557 * with the member IDs. 10558 * Parameters: 10559 * unit - (IN) SOC unit number. 10560 * Returns: 10561 * BCM_E_XXX 10562 */ 10563 STATIC int 10564 _bcm_tr3_ecmp_dlb_member_recover(int unit) 10565 { 10566 int rv = BCM_E_NONE; 10567 int member_bitmap_width; 10568 int alloc_size; 10569 SHR_BITDCL *member_bitmap = NULL; 10570 int member_id; 10571 dlb_ecmp_member_attribute_entry_t member_attr_entry; 10572 int nh_index; 10573 int group; 10574 int i; 10575 dlb_ecmp_group_membership_entry_t group_membership_entry; 10576 int match, match_index, free_index_found, free_index; 10577 _tr3_ecmp_dlb_nh_membership_t *membership; 10578 10579 member_bitmap_width = soc_mem_field_length(unit, 10580 DLB_ECMP_GROUP_MEMBERSHIPm, MEMBER_BITMAPf); 10581 alloc_size = SHR_BITALLOCSIZE(member_bitmap_width); 10582 member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 10583 if (NULL == member_bitmap) { 10584 return BCM_E_MEMORY; 10585 } 10586 10587 for (member_id = 0; member_id < soc_mem_index_count(unit, 10588 DLB_ECMP_MEMBER_ATTRIBUTEm); member_id++) { 10589 rv = READ_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ANY, 10590 member_id, &member_attr_entry); 10591 if (BCM_FAILURE(rv)) { 10592 sal_free(member_bitmap); 10593 return rv; 10594 } 10595 nh_index = soc_DLB_ECMP_MEMBER_ATTRIBUTEm_field32_get(unit, 10596 &member_attr_entry, NEXT_HOP_INDEXf); 10597 if (0 == nh_index) { 10598 /* If next hop index is 0, this member ID is not used. */ 10599 continue; 10600 } 10601 10602 /* Member ID is used */ 10603 _BCM_ECMP_DLB_MEMBER_ID_USED_SET(unit, member_id); 10604 10605 /* Find the ECMP DLB group this member ID belongs to */ 10606 group = -1; 10607 for (i = 0; i < soc_mem_index_count(unit, 10608 DLB_ECMP_GROUP_MEMBERSHIPm); i++) { 10609 rv = READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, 10610 MEM_BLOCK_ANY, i, &group_membership_entry); 10611 if (BCM_FAILURE(rv)) { 10612 sal_free(member_bitmap); 10613 return rv; 10614 } 10615 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit, 10616 &group_membership_entry, MEMBER_BITMAPf, member_bitmap); 10617 if (SHR_BITGET(member_bitmap, member_id)) { 10618 group = i; 10619 break; 10620 } 10621 } 10622 10623 /* Traverse ecmp_dlb_nh_info array to find the nh_index */ 10624 match = FALSE; 10625 match_index = 0; 10626 free_index_found = FALSE; 10627 free_index = 0; 10628 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 10629 if (ECMP_DLB_NH_INFO(unit, i).valid) { 10630 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) { 10631 match = TRUE; 10632 match_index = i; 10633 break; 10634 } 10635 } else { 10636 if (!free_index_found) { 10637 free_index_found = TRUE; 10638 free_index = i; 10639 } 10640 } 10641 } 10642 10643 /* Insert member ID and group to the next hop's linked list of member 10644 * IDs and groups. 10645 */ 10646 membership = sal_alloc(sizeof(_tr3_ecmp_dlb_nh_membership_t), 10647 "ecmp dlb nh membership"); 10648 if (NULL == membership) { 10649 sal_free(member_bitmap); 10650 return BCM_E_MEMORY; 10651 } 10652 membership->member_id = member_id; 10653 membership->group = group; 10654 if (match) { 10655 membership->next = 10656 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 10657 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = membership; 10658 } else { 10659 if (!free_index_found) { 10660 return BCM_E_FULL; 10661 } 10662 membership->next = 10663 ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list; 10664 ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list = membership; 10665 ECMP_DLB_NH_INFO(unit, free_index).nh_index = nh_index; 10666 ECMP_DLB_NH_INFO(unit, free_index).valid = 1; 10667 } 10668 } 10669 10670 sal_free(member_bitmap); 10671 10672 return BCM_E_NONE; 10673 } 10674 10675 /* 10676 * Function: 10677 * _bcm_tr3_ecmp_dlb_group_recover 10678 * Purpose: 10679 * Recover ECMP DLB group usage and flowset table usage. 10680 * Parameters: 10681 * unit - (IN) SOC unit number. 10682 * Returns: 10683 * BCM_E_XXX 10684 */ 10685 STATIC int 10686 _bcm_tr3_ecmp_dlb_group_recover(int unit) 10687 { 10688 int i; 10689 ecmp_count_entry_t ecmp_group_entry; 10690 int group_enable, dlb_id; 10691 dlb_ecmp_group_control_entry_t group_control_entry; 10692 int entry_base_ptr, dynamic_size_encode, dynamic_size; 10693 int block_base_ptr, num_blocks; 10694 10695 for (i = 0; i < soc_mem_index_count(unit, L3_ECMP_COUNTm); i++) { 10696 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, i, 10697 &ecmp_group_entry)); 10698 group_enable = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 10699 GROUP_ENABLEf); 10700 if (0 == group_enable) { 10701 /* DLB not enabled */ 10702 continue; 10703 } 10704 10705 /* Get DLB group ID and marked it as used */ 10706 dlb_id = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 10707 DLB_IDf); 10708 _BCM_ECMP_DLB_ID_USED_SET(unit, dlb_id); 10709 10710 /* Get flow set table usage */ 10711 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit, 10712 MEM_BLOCK_ANY, dlb_id, &group_control_entry)); 10713 entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 10714 &group_control_entry, FLOW_SET_BASEf); 10715 dynamic_size_encode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 10716 &group_control_entry, FLOW_SET_SIZEf); 10717 BCM_IF_ERROR_RETURN 10718 (_bcm_tr3_ecmp_dlb_dynamic_size_decode(dynamic_size_encode, 10719 &dynamic_size)); 10720 block_base_ptr = entry_base_ptr >> 9; 10721 num_blocks = dynamic_size >> 9; 10722 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, 10723 num_blocks); 10724 } 10725 10726 return BCM_E_NONE; 10727 } 10728 10729 /* 10730 * Function: 10731 * _bcm_tr3_ecmp_dlb_quality_parameters_recover 10732 * Purpose: 10733 * Recover ECMP DLB parameters used to derive a member's quality. 10734 * Parameters: 10735 * unit - (IN) SOC unit number. 10736 * Returns: 10737 * BCM_E_XXX 10738 */ 10739 STATIC int 10740 _bcm_tr3_ecmp_dlb_quality_parameters_recover(int unit) 10741 { 10742 uint32 measure_control_reg; 10743 int num_time_units; 10744 dlb_ecmp_pla_quantize_threshold_entry_t quantize_threshold_entry; 10745 int min_th_bytes, min_th_cells; 10746 int max_th_bytes, max_th_cells; 10747 dlb_ecmp_vla_expected_loading_threshold_entry_t expected_loading_threshold_entry; 10748 int exp_load_min_th_kbytes, exp_load_max_th_kbytes; 10749 dlb_ecmp_vla_member_imbalance_threshold_entry_t imbalance_threshold_entry; 10750 int imbalance_min_th_kbytes, imbalance_max_th_kbytes; 10751 int entries_per_profile; 10752 int profile_ptr, base_index; 10753 dlb_ecmp_quality_mapping_entry_t quality_mapping_entry; 10754 int quality; 10755 10756 if (ECMP_DLB_INFO(unit)->recovered_from_scache) { 10757 /* If already recovered from scache, do nothing. */ 10758 return BCM_E_NONE; 10759 } 10760 10761 /* Recover sampling rate */ 10762 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, 10763 &measure_control_reg)); 10764 num_time_units = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 10765 measure_control_reg, HISTORICAL_SAMPLING_PERIODf); 10766 if (num_time_units > 0) { 10767 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = 1000000 / num_time_units; 10768 } 10769 10770 /* Recover min and max load and queue size thresholds: 10771 * Load threshold (in mbps) 10772 * = (bytes per sampling period) * 8 bits per byte / 10773 * (sampling period in seconds) / 10^6 10774 * = (bytes per sampling period) * 8 bits per byte / 10775 * (num_time_units * 1 us per time unit * 10^-6) / 10^6 10776 * = (bytes per sampling period) * 8 / num_time_units 10777 */ 10778 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, 10779 MEM_BLOCK_ANY, 0, &quantize_threshold_entry)); 10780 min_th_bytes = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get 10781 (unit, &quantize_threshold_entry, THRESHOLD_HIST_LOADf); 10782 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = (min_th_bytes << 3) / 10783 num_time_units; 10784 min_th_cells = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get 10785 (unit, &quantize_threshold_entry, THRESHOLD_HIST_QSIZEf); 10786 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = min_th_cells * 208; 10787 10788 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, 10789 MEM_BLOCK_ANY, soc_mem_index_max(unit, 10790 DLB_ECMP_PLA_QUANTIZE_THRESHOLDm), 10791 &quantize_threshold_entry)); 10792 max_th_bytes = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get 10793 (unit, &quantize_threshold_entry, THRESHOLD_HIST_LOADf); 10794 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = (max_th_bytes << 3) / 10795 num_time_units; 10796 max_th_cells = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get 10797 (unit, &quantize_threshold_entry, THRESHOLD_HIST_QSIZEf); 10798 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = max_th_cells * 208; 10799 10800 /* Recover min and max expected load thresholds: 10801 * Load threshold (in mbps) 10802 * = (bytes per sampling period) * 8 bits per byte / 10803 * (sampling period in seconds) / 10^6 10804 * = (bytes per sampling period) * 8 bits per byte / 10805 * (num_time_units * 1 us per time unit * 10^-6) / 10^6 10806 * = (bytes per sampling period) * 8 / num_time_units 10807 * = (kilobytes per sampling period) * 8000 / num_time_units 10808 */ 10809 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit, 10810 MEM_BLOCK_ANY, 0, &expected_loading_threshold_entry)); 10811 exp_load_min_th_kbytes = 10812 soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_get 10813 (unit, &expected_loading_threshold_entry, THRESHOLDf); 10814 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th = 10815 (exp_load_min_th_kbytes << 3) * 1000 / num_time_units; 10816 10817 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit, 10818 MEM_BLOCK_ANY, 14, &expected_loading_threshold_entry)); 10819 exp_load_max_th_kbytes = 10820 soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_get 10821 (unit, &expected_loading_threshold_entry, THRESHOLDf); 10822 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th = 10823 (exp_load_max_th_kbytes << 3) * 1000 / num_time_units; 10824 10825 /* Recover min and max imbalance thresholds: 10826 * Imbalance threshold (in percentage) 10827 * = (imbalance threshold in kbytes) / 10828 * (expected load threshold in kbytes) * 100 10829 */ 10830 SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm(unit, 10831 MEM_BLOCK_ANY, 14, &imbalance_threshold_entry)); 10832 imbalance_min_th_kbytes = 10833 soc_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm_field32_get 10834 (unit, &imbalance_threshold_entry, THRESHOLD_0f); 10835 if ((imbalance_min_th_kbytes >> 20) & 0x1) { 10836 /* Imbalance threshold is negative. Take absolute value. */ 10837 imbalance_min_th_kbytes = ((~imbalance_min_th_kbytes) + 1) & 0x1fffff; 10838 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th = 10839 imbalance_min_th_kbytes * 100 / (exp_load_max_th_kbytes) * -1; 10840 } else { 10841 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th = 10842 imbalance_min_th_kbytes * 100 / (exp_load_max_th_kbytes); 10843 } 10844 10845 imbalance_max_th_kbytes = 10846 soc_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm_field32_get 10847 (unit, &imbalance_threshold_entry, THRESHOLD_6f); 10848 if ((imbalance_max_th_kbytes >> 20) & 0x1) { 10849 /* Imbalance threshold is negative. Take absolute value. */ 10850 imbalance_max_th_kbytes = ((~imbalance_max_th_kbytes) + 1) & 0x1fffff; 10851 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th = 10852 imbalance_max_th_kbytes * 100 / (exp_load_max_th_kbytes) * -1; 10853 } else { 10854 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th = 10855 imbalance_max_th_kbytes * 100 / (exp_load_max_th_kbytes); 10856 } 10857 10858 /* Recover load weights */ 10859 entries_per_profile = 64; 10860 for (profile_ptr = 0; profile_ptr < (1 << soc_mem_field_length(unit, 10861 DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf)); profile_ptr++) { 10862 base_index = profile_ptr * entries_per_profile; 10863 /* quality = (quantized_tx_load * tx_load_percent + 10864 * quantized_qsize * (100 - tx_load_percent)) / 10865 * 100; 10866 * quality = ((quantized_tx_load - quantized_qsize) * 10867 * tx_load_percent + quantized_qsize * 100) / 10868 * 100; 10869 * quality = (quantized_tx_load - quantized_qsize) * 10870 * tx_load_percent / 100 + quantized_qsize; 10871 * tx_load_percent = (quality - quantized_qsize) * 100 / 10872 * (quantized_tx_load - quantized_qsize); 10873 * 10874 * The index to DLB_ECMP_QUALITY_MAPPING table consists of 10875 * base_index + quantized_tx_load * 8 + quantized_qsize, 10876 * where quantized_tx_load and quantized_qsize range from 10877 * 0 to 7. 10878 * 10879 * With quantized_tx_load = 7 and quantized_qsize = 0, the 10880 * index to DLB_ECMP_QUALITY_MAPPING table is 10881 * base_index + 56, and the tx_load_percent expression 10882 * simplifies to quality * 100 / 7; 10883 */ 10884 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_MAPPINGm(unit, 10885 MEM_BLOCK_ANY, base_index + 56, 10886 &quality_mapping_entry)); 10887 quality = soc_DLB_ECMP_QUALITY_MAPPINGm_field32_get(unit, 10888 &quality_mapping_entry, QUALITYf); 10889 ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr] = 10890 quality * 100 / 7; 10891 } 10892 10893 return BCM_E_NONE; 10894 } 10895 10896 /* 10897 * Function: 10898 * bcm_tr3_ecmp_dlb_hw_recover 10899 * Purpose: 10900 * Recover ECMP DLB internal state from hardware. 10901 * Parameters: 10902 * unit - (IN) SOC unit number. 10903 * scache_ptr - (IN/OUT) Scache pointer 10904 * Returns: 10905 * BCM_E_XXX 10906 */ 10907 int 10908 bcm_tr3_ecmp_dlb_hw_recover(int unit) 10909 { 10910 /* TD3TBD */ 10911 if (SOC_IS_TRIDENT3X(unit)) { 10912 return BCM_E_NONE; 10913 } 10914 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_recover(unit)); 10915 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_group_recover(unit)); 10916 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_quality_parameters_recover(unit)); 10917 return BCM_E_NONE; 10918 } 10919 10920 /* 10921 * Function: 10922 * _bcm_tr3_l3_esm_host_state_recover 10923 * Purpose: 10924 * Warmboot recovery for ESM host tbl state. 10925 * This is a 'level one' recovery. 10926 * Parameters: 10927 * unit - (IN) SOC unit number. 10928 * Returns: 10929 * BCM_E_XXX 10930 */ 10931 int 10932 _bcm_tr3_l3_esm_host_state_recover(int unit) 10933 { 10934 #if 0 10935 int tbl; 10936 soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES]; 10937 10938 mem[0] = BCM_XGS3_L3_MEM(unit, v4_esm); 10939 mem[1] = BCM_XGS3_L3_MEM(unit, v4_esm_wide); 10940 mem[2] = BCM_XGS3_L3_MEM(unit, v6_esm); 10941 mem[3] = BCM_XGS3_L3_MEM(unit, v6_esm_wide); 10942 10943 for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES; tbl++) { 10944 /* For each of the ESM tables, starting from zero, 10945 * check the index of the first EXT_TCAM_VBITm 10946 * that is invalid. That is the first available 10947 * free entry. Set _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) 10948 * to this value */ 10949 10950 } 10951 #endif 10952 10953 return (BCM_E_NONE); 10954 } 10955 10956 #endif /* BCM_WARM_BOOT_SUPPORT */ 10957 10958 #ifndef BCM_SW_STATE_DUMP_DISABLE 10959 10960 /* 10961 * Function: 10962 * _bcm_l3_sw_dump 10963 * Purpose: 10964 * Displays L3 information maintained by software. 10965 * Parameters: 10966 * unit - Device unit number 10967 * Returns: 10968 * None 10969 */ 10970 void 10971 bcm_tr3_ecmp_dlb_sw_dump(int unit) 10972 { 10973 int i; 10974 _tr3_ecmp_dlb_nh_membership_t *current_ptr; 10975 int num_entries_per_profile; 10976 int num_profiles; 10977 int rv; 10978 int ref_count; 10979 10980 LOG_CLI((BSL_META_U(unit, 10981 " ECMP DLB Info -\n"))); 10982 10983 /* Print ECMP DLB next hop info */ 10984 LOG_CLI((BSL_META_U(unit, 10985 " ECMP DLB Next Hop Info -\n"))); 10986 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) { 10987 if (ECMP_DLB_NH_INFO(unit, i).valid) { 10988 LOG_CLI((BSL_META_U(unit, 10989 " Next hop index %d is "), 10990 ECMP_DLB_NH_INFO(unit, i).nh_index)); 10991 current_ptr = ECMP_DLB_NH_INFO(unit, i).nh_membership_list; 10992 while (NULL != current_ptr) { 10993 LOG_CLI((BSL_META_U(unit, 10994 "member %d in group %d"), 10995 current_ptr->member_id, current_ptr->group)); 10996 current_ptr = current_ptr->next; 10997 if (NULL == current_ptr) { 10998 LOG_CLI((BSL_META_U(unit, 10999 "\n"))); 11000 } else { 11001 LOG_CLI((BSL_META_U(unit, 11002 ", "))); 11003 } 11004 } 11005 } 11006 } 11007 11008 /* Print ECMP DLB group usage */ 11009 LOG_CLI((BSL_META_U(unit, 11010 " ECMP DLB Groups Used:"))); 11011 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) { 11012 if (_BCM_ECMP_DLB_ID_USED_GET(unit, i)) { 11013 LOG_CLI((BSL_META_U(unit, 11014 " %d"), i)); 11015 } 11016 } 11017 LOG_CLI((BSL_META_U(unit, 11018 "\n"))); 11019 11020 /* Print ECMP DLB flowset table usage */ 11021 LOG_CLI((BSL_META_U(unit, 11022 " ECMP DLB Flowset Table Blocks Used:"))); 11023 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_FLOWSETm) >> 9; i++) { 11024 if (_BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(unit, i)) { 11025 LOG_CLI((BSL_META_U(unit, 11026 " %d"), i)); 11027 } 11028 } 11029 LOG_CLI((BSL_META_U(unit, 11030 "\n"))); 11031 11032 /* Print ECMP DLB member ID usage */ 11033 LOG_CLI((BSL_META_U(unit, 11034 " ECMP DLB Member IDs Used:"))); 11035 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_MEMBER_ATTRIBUTEm); i++) { 11036 if (_BCM_ECMP_DLB_MEMBER_ID_USED_GET(unit, i)) { 11037 LOG_CLI((BSL_META_U(unit, 11038 " %d"), i)); 11039 } 11040 } 11041 LOG_CLI((BSL_META_U(unit, 11042 "\n"))); 11043 11044 /* Print sample rate and threshold parameters */ 11045 LOG_CLI((BSL_META_U(unit, 11046 " Sample rate: %d per second\n"), 11047 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate)); 11048 LOG_CLI((BSL_META_U(unit, 11049 " Tx load min threshold: %d mbps\n"), 11050 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th)); 11051 LOG_CLI((BSL_META_U(unit, 11052 " Tx load max threshold: %d mbps\n"), 11053 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th)); 11054 LOG_CLI((BSL_META_U(unit, 11055 " Queue size min threshold: %d cells\n"), 11056 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th)); 11057 LOG_CLI((BSL_META_U(unit, 11058 " Queue size max threshold: %d cells\n"), 11059 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th)); 11060 LOG_CLI((BSL_META_U(unit, 11061 " Expected load min threshold: %d mbps\n"), 11062 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th)); 11063 LOG_CLI((BSL_META_U(unit, 11064 " Expected load max threshold: %d mbps\n"), 11065 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th)); 11066 LOG_CLI((BSL_META_U(unit, 11067 " Imbalance min threshold: %d percent\n"), 11068 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th)); 11069 LOG_CLI((BSL_META_U(unit, 11070 " Imbalance max threshold: %d percent\n"), 11071 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th)); 11072 11073 /* Print quality mapping profiles */ 11074 LOG_CLI((BSL_META_U(unit, 11075 " Quality mapping profiles:\n"))); 11076 num_entries_per_profile = 64; 11077 num_profiles = soc_mem_index_count(unit, DLB_ECMP_QUALITY_MAPPINGm) / 11078 num_entries_per_profile; 11079 for (i = 0; i < num_profiles; i++) { 11080 LOG_CLI((BSL_META_U(unit, 11081 " Profile %d: load weight %d percent, "), 11082 i, ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i])); 11083 rv = soc_profile_mem_ref_count_get(unit, 11084 ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile, 11085 i * num_entries_per_profile, &ref_count); 11086 if (SOC_FAILURE(rv)) { 11087 LOG_CLI((BSL_META_U(unit, 11088 "\n"))); 11089 continue; 11090 } 11091 LOG_CLI((BSL_META_U(unit, 11092 "ref count %d\n"), ref_count)); 11093 } 11094 11095 return; 11096 } 11097 11098 /* 11099 * Function: 11100 * _bcm_tr3_esm_host_tbl_sw_dump 11101 * Purpose: 11102 * Displays L3 information maintained by software. 11103 * Parameters: 11104 * unit - Device unit number 11105 * Returns: 11106 * None 11107 */ 11108 void 11109 _bcm_tr3_esm_host_tbl_sw_dump(int unit) { 11110 11111 int tbl; 11112 for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES ; tbl++) { 11113 LOG_CLI((BSL_META_U(unit, 11114 "ESM Host table %d, free entry: %d\n"), tbl, 11115 _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl))); 11116 } 11117 } 11118 11119 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 11120 11121 #endif /* INCLUDE_L3 && BCM_TRIUMPH3_SUPPORT */