l3.c (45006B)
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: Tomahawk L3 function implementations 9 */ 10 11 #include <soc/defs.h> 12 #include <shared/bsl.h> 13 #if defined(INCLUDE_L3) && defined(BCM_TOMAHAWK_SUPPORT) 14 15 #include <soc/drv.h> 16 #include <bcm/vlan.h> 17 #include <bcm/error.h> 18 19 #include <bcm/l3.h> 20 #include <soc/l3x.h> 21 #include <soc/lpm.h> 22 23 #include <soc/tomahawk.h> 24 #include <bcm/tunnel.h> 25 #include <bcm/debug.h> 26 #include <bcm/error.h> 27 #include <bcm/stack.h> 28 #include <soc/trident2.h> 29 #include <soc/defragment.h> 30 31 #include <bcm_int/esw/tomahawk.h> 32 #include <bcm_int/esw/trident2.h> 33 #include <bcm_int/esw/firebolt.h> 34 #include <bcm_int/esw/triumph.h> 35 #include <bcm_int/esw/triumph2.h> 36 #include <bcm_int/esw/stack.h> 37 #include <bcm_int/esw/flex_ctr.h> 38 #include <bcm_int/esw_dispatch.h> 39 #include <bcm_int/esw/flex_ctr.h> 40 #include <bcm_int/esw/virtual.h> 41 #include <bcm_int/esw/qos.h> 42 43 #if defined(BCM_TRIDENT3_SUPPORT) 44 #include <bcm_int/esw/trident3.h> 45 #endif 46 47 #if defined(BCM_TRX_SUPPORT) 48 #include <bcm_int/esw/trx.h> 49 #endif /* BCM_TRX_SUPPORT */ 50 51 #define _BCM_TD2_L3_MEM_BANKS_ALL (-1) 52 #define _BCM_TD2_HOST_ENTRY_NOT_FOUND (-1) 53 static soc_profile_mem_t *_bcm_th_macda_oui_profile[BCM_MAX_NUM_UNITS]; 54 static soc_profile_mem_t *_bcm_th_vntag_etag_profile[BCM_MAX_NUM_UNITS]; 55 56 57 /* IP Options Handling */ 58 #define L3_INFO(_unit_) (&_bcm_l3_bk_info[_unit_]) 59 #define _BCM_IP_OPTION_PROFILE_CHUNK 256 60 #define _BCM_IP4_OPTIONS_LEN \ 61 (soc_mem_index_count(unit, IP_OPTION_CONTROL_PROFILE_TABLEm)/ \ 62 _BCM_IP_OPTION_PROFILE_CHUNK) 63 64 /* 65 * Function: 66 * _bcm_th_macda_oui_profile_init 67 * Purpose: 68 * Allocate and initialize _bcm_th_macda_oui_profile_init 69 * Parameters: 70 * unit - (IN)SOC unit number. 71 * Returns: 72 * BCM_X_XXX 73 */ 74 bcm_error_t 75 _bcm_th_macda_oui_profile_init(int unit) 76 { 77 soc_mem_t mem_profile; 78 int entry_words[1]; 79 80 /* Create profile for MACDA_OUI_PROFILE table*/ 81 if (_bcm_th_macda_oui_profile[unit] == NULL) { 82 _bcm_th_macda_oui_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 83 "MACDA OUI Profile Mem"); 84 if (_bcm_th_macda_oui_profile[unit] == NULL) { 85 return BCM_E_MEMORY; 86 } 87 } else { 88 BCM_IF_ERROR_RETURN 89 (soc_profile_mem_destroy(unit, _bcm_th_macda_oui_profile[unit])); 90 } 91 soc_profile_mem_t_init(_bcm_th_macda_oui_profile[unit]); 92 mem_profile = EGR_MACDA_OUI_PROFILEm; 93 entry_words[0] = BYTES2WORDS(sizeof(egr_macda_oui_profile_entry_t)); 94 SOC_IF_ERROR_RETURN 95 (soc_profile_mem_create(unit, &mem_profile, entry_words, 1, 96 _bcm_th_macda_oui_profile[unit])); 97 98 return BCM_E_NONE; 99 } 100 101 102 /* 103 * Function: 104 * _bcm_th_macda_oui_profile_deinit 105 * Purpose: 106 * Deallocate _bcm_th_macda_oui_profile 107 * Parameters: 108 * unit - (IN)SOC unit number. 109 * Returns: 110 * BCM_X_XXX 111 */ 112 void 113 _bcm_th_macda_oui_profile_deinit(int unit) 114 { 115 if (_bcm_th_macda_oui_profile[unit]) { 116 (void)soc_profile_mem_destroy(unit, _bcm_th_macda_oui_profile[unit]); 117 sal_free(_bcm_th_macda_oui_profile[unit]); 118 _bcm_th_macda_oui_profile[unit] = NULL; 119 } 120 } 121 122 /* 123 * Function: 124 * _bcm_th_vntag_etag_profile_init 125 * Purpose: 126 * Allocate and initialize _bcm_th_vntag_etag_profile 127 * Parameters: 128 * unit - (IN)SOC unit number. 129 * Returns: 130 * BCM_X_XXX 131 */ 132 bcm_error_t 133 _bcm_th_vntag_etag_profile_init(int unit) 134 { 135 soc_mem_t mem_profile; 136 int entry_words[1]; 137 void *entries[1]; 138 uint32 profile_idx; 139 egr_vntag_etag_profile_entry_t vntag_etag_profile_entry; 140 141 /* Create profile for EGR_VNTAG_ETAG_PROFILE table */ 142 if (_bcm_th_vntag_etag_profile[unit] == NULL) { 143 _bcm_th_vntag_etag_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t), 144 "EGR VNTAG ETAG Profile Mem"); 145 if (_bcm_th_vntag_etag_profile[unit] == NULL) { 146 return BCM_E_MEMORY; 147 } 148 } else { 149 BCM_IF_ERROR_RETURN 150 (soc_profile_mem_destroy(unit, _bcm_th_vntag_etag_profile[unit])); 151 } 152 soc_profile_mem_t_init(_bcm_th_vntag_etag_profile[unit]); 153 mem_profile = EGR_VNTAG_ETAG_PROFILEm; 154 entry_words[0] = BYTES2WORDS(sizeof(egr_vntag_etag_profile_entry_t)); 155 SOC_IF_ERROR_RETURN 156 (soc_profile_mem_create(unit, &mem_profile, entry_words, 1, 157 _bcm_th_vntag_etag_profile[unit])); 158 159 /* Index 0 in EGR_VNTAG_ETAG_PROFILE table is reserved for non NIV/PE flow 160 * hence adding this dummy entry at index 0 during init time 161 */ 162 sal_memset(&vntag_etag_profile_entry, 0, sizeof(vntag_etag_profile_entry)); 163 entries[0] = &vntag_etag_profile_entry; 164 BCM_IF_ERROR_RETURN 165 (soc_profile_mem_add(unit, _bcm_th_vntag_etag_profile[unit], 166 entries, 1, &profile_idx)); 167 168 return BCM_E_NONE; 169 } 170 171 172 /* 173 * Function: 174 * _bcm_th_vntag_etag_profile_deinit 175 * Purpose: 176 * Deallocate _bcm_th_vntag_etag_profile 177 * Parameters: 178 * unit - (IN)SOC unit number. 179 * Returns: 180 * BCM_X_XXX 181 */ 182 void 183 _bcm_th_vntag_etag_profile_deinit(int unit) 184 { 185 if (_bcm_th_vntag_etag_profile[unit]) { 186 (void)soc_profile_mem_destroy(unit, _bcm_th_vntag_etag_profile[unit]); 187 sal_free(_bcm_th_vntag_etag_profile[unit]); 188 _bcm_th_vntag_etag_profile[unit] = NULL; 189 } 190 } 191 192 /* 193 * Function: 194 * _bcm_th_l3_vp_entry_del 195 * Purpose: 196 * Delete entry from profile table 197 * Parameters: 198 * unit - (IN) SOC unit number. 199 * ipv6 - (IN) IPV4 or IPv6 flag 200 * l3cfg - (IN) L3 entry info. 201 * bufentry - (IN) hw buffer 202 * Returns: 203 */ 204 bcm_error_t 205 _bcm_th_l3_vp_entry_del(int unit, _bcm_l3_cfg_t *l3cfg, 206 int macda_oui_profile_index ,int vntag_etag_profile_index) 207 { 208 209 int rv = BCM_E_NONE; 210 211 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 212 213 /* delete an entry or decrement ref count from EGR_MACDA_OUI_PROFILE table */ 214 soc_mem_lock(unit, EGR_MACDA_OUI_PROFILEm); 215 if (macda_oui_profile_index != -1) { 216 rv = soc_profile_mem_delete(unit, _bcm_th_macda_oui_profile[unit], 217 macda_oui_profile_index); 218 } 219 if (BCM_FAILURE(rv)) { 220 soc_mem_unlock(unit, EGR_MACDA_OUI_PROFILEm); 221 return rv; 222 } 223 soc_mem_unlock(unit, EGR_MACDA_OUI_PROFILEm); 224 225 /* delete an entry or decrement ref count from EGR_VNTAG_ETAG_PROFILE table */ 226 soc_mem_lock(unit, EGR_VNTAG_ETAG_PROFILEm); 227 /* profile 0 is reserved for NON NIV/PE entries */ 228 if (vntag_etag_profile_index != 0) { 229 rv = soc_profile_mem_delete(unit, _bcm_th_vntag_etag_profile[unit], 230 vntag_etag_profile_index); 231 } 232 if (BCM_FAILURE(rv)) { 233 soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm); 234 return rv; 235 } 236 soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm); 237 238 } 239 240 return rv; 241 } 242 243 /* 244 * Function: 245 * _bcm_th_l3_vp_ent_parse 246 * Purpose: 247 * TH helper routine used to parse hw l3 entry to api format 248 * Parameters: 249 * unit - (IN) SOC unit number. 250 * mem - (IN) L3 table memory. 251 * l3cfg - (IN) L3 entry info. 252 * l3x_entry - (IN) hw buffer. 253 * Returns: 254 */ 255 bcm_error_t 256 _bcm_th_l3_vp_ent_parse(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 257 { 258 259 uint32 profile_index; 260 uint32 dst_vif; 261 uint32 mac_field; 262 bcm_gport_t vp_gport; 263 uint32 vntag_actions; 264 int rv = BCM_E_NONE; 265 uint32 glp; /* Global port. */ 266 int ipv6; /* Entry is IPv6 flag. */ 267 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 268 uint32 *buf_p; /* HW buffer address. */ 269 egr_macda_oui_profile_entry_t macda_oui_profile_entry; 270 egr_vntag_etag_profile_entry_t vntag_etag_profile_entry; 271 int is_trunk = -1; 272 uint32 HG_VNTAG_MODIFY_ENABLE_FLAG = 0; 273 274 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 275 buf_p = (uint32 *)l3x_entry; 276 277 /* Set table fields */ 278 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 279 soc_mem_mac_address_get(unit, mem, buf_p, fld->macda_low, 280 l3cfg->l3c_mac_addr, 281 SOC_MEM_MAC_LOWER_ONLY); 282 /* Read upper 3 bytes of MAC address from profile table */ 283 profile_index = soc_mem_field32_get(unit, mem, buf_p, 284 fld->oui_profile_id); 285 SOC_IF_ERROR_RETURN 286 (READ_EGR_MACDA_OUI_PROFILEm(unit, MEM_BLOCK_ANY, profile_index, 287 &macda_oui_profile_entry)); 288 soc_EGR_MACDA_OUI_PROFILEm_field_get(unit, &macda_oui_profile_entry, 289 MACDA_OUIf, &mac_field); 290 l3cfg->l3c_mac_addr[0] = (uint8) (mac_field >> 16 & 0xff); 291 l3cfg->l3c_mac_addr[1] = (uint8) (mac_field >> 8 & 0xff); 292 l3cfg->l3c_mac_addr[2] = (uint8) (mac_field & 0xff); 293 glp = soc_mem_field32_get(unit, mem, buf_p, fld->glp); 294 _bcm_th_glp_resolve_embedded_nh(unit, glp, &l3cfg->l3c_modid, 295 &l3cfg->l3c_port_tgid, &is_trunk); 296 #ifdef BCM_TRIDENT3_SUPPORT 297 if (SOC_IS_TRIDENT3X(unit)) { 298 uint32 dest, dtype; 299 dest = soc_mem_field32_dest_get(unit, mem, buf_p, 300 fld->dest, &dtype); 301 if (dtype == SOC_MEM_FIF_DEST_LAG) { 302 is_trunk = 1; 303 l3cfg->l3c_port_tgid = (dest & SOC_MEM_FIF_DGPP_TGID_MASK); 304 } else if (dtype == SOC_MEM_FIF_DEST_DGPP) { 305 l3cfg->l3c_port_tgid = (dest & SOC_MEM_FIF_DGPP_PORT_MASK); 306 l3cfg->l3c_modid = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >> 307 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS; 308 } 309 } 310 #endif 311 if (is_trunk == 1) { 312 l3cfg->l3c_flags |= BCM_L3_TGID; 313 } 314 315 dst_vif = soc_mem_field32_get(unit, mem, buf_p, 316 fld->dst_vif); 317 profile_index = soc_mem_field32_get(unit, mem, buf_p, 318 fld->vntag_etag_profile_id); 319 320 if (profile_index != L3_EXT_VIEW_INVALID_VNTAG_ETAG_PROFILE) { 321 SOC_IF_ERROR_RETURN 322 (READ_EGR_VNTAG_ETAG_PROFILEm(unit, MEM_BLOCK_ANY, profile_index, 323 &vntag_etag_profile_entry)); 324 soc_EGR_VNTAG_ETAG_PROFILEm_field_get(unit, &vntag_etag_profile_entry, 325 HG_VNTAG_MODIFY_ENABLEf, 326 &HG_VNTAG_MODIFY_ENABLE_FLAG); 327 l3cfg->l3c_flags2 = HG_VNTAG_MODIFY_ENABLE_FLAG; 328 soc_EGR_VNTAG_ETAG_PROFILEm_field_get(unit, &vntag_etag_profile_entry, 329 VNTAG_ACTIONSf, &vntag_actions); 330 switch (vntag_actions) { 331 case VNTAG_ACTIONS_NIV: /* NIV encap */ 332 if (_bcm_niv_gport_get(unit, is_trunk, l3cfg->l3c_modid, 333 l3cfg->l3c_port_tgid, dst_vif, 334 &vp_gport) == BCM_E_NONE) { 335 l3cfg->l3c_port_tgid = vp_gport; 336 } 337 break; 338 case VNTAG_ACTIONS_ETAG: /* PE encap */ 339 if (_bcm_extender_gport_get(unit, is_trunk, l3cfg->l3c_modid, 340 l3cfg->l3c_port_tgid, dst_vif, 341 &vp_gport) == BCM_E_NONE) { 342 l3cfg->l3c_port_tgid = vp_gport; 343 } 344 break; 345 default: 346 break; 347 } 348 } 349 350 return rv; 351 } 352 353 354 /* 355 * Function: 356 * _bcm_th_l3_vp_entry_add 357 * Purpose: 358 * TH helper routine used to parse hw l3 entry to api format 359 * Parameters: 360 * unit - (IN) SOC unit number. 361 * mem - (IN) L3 table memory. 362 * l3cfg - (IN) L3 entry info. 363 * buf_p - (IN) hw buffer. 364 * Returns: 365 * BCM_X_XXX 366 */ 367 bcm_error_t 368 _bcm_th_l3_vp_entry_add(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, 369 uint32 *buf_p, int *macda_oui_profile_index, 370 int *vntag_etag_profile_index) 371 { 372 373 int rv = BCM_E_NONE; 374 int rv1 = BCM_E_NONE; 375 int ipv6; /* Entry is IPv6 flag. */ 376 _bcm_l3_fields_t *fld; /* L3 table common fields. */ 377 uint32 *bufp; /* HW buffer address. */ 378 uint32 profile_idx; 379 uint32 mac_field; 380 uint32 vntag_actions; 381 void *entries[1]; 382 egr_macda_oui_profile_entry_t macda_oui_profile_entry; 383 egr_vntag_etag_profile_entry_t vntag_etag_profile_entry; 384 385 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 386 /* Set table fields */ 387 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 388 bufp = buf_p; 389 390 if (soc_feature(unit, soc_feature_virtual_port_routing) && 391 (l3cfg->l3c_encap_id > 0 && 392 l3cfg->l3c_encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))) { 393 int virtual_interface_id; 394 uint32 hg_vntag_modify = 1; 395 int count; 396 if (_bcm_vp_used_get(unit, l3cfg->l3c_encap_id, 397 _bcmVpTypeNiv)) { /* NIV */ 398 bcm_niv_port_t niv_port; 399 bcm_niv_egress_t niv_egress; 400 BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, 401 l3cfg->l3c_encap_id); 402 BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port)); 403 if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) { 404 BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit, 405 niv_port.niv_port_id, 1, 406 &niv_egress, &count)); 407 if (count == 0) { 408 return BCM_E_CONFIG; 409 } 410 if (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) { 411 return BCM_E_PARAM; 412 } 413 virtual_interface_id = niv_egress.virtual_interface_id; 414 } else { 415 if (niv_port.flags & BCM_NIV_PORT_MULTICAST) { 416 return BCM_E_PARAM; 417 } 418 virtual_interface_id = niv_port.virtual_interface_id; 419 } 420 soc_mem_field32_set(unit, mem, bufp, fld->dst_vif, 421 virtual_interface_id); 422 423 sal_memset(&vntag_etag_profile_entry, 0, sizeof(vntag_etag_profile_entry)); 424 vntag_actions = 1; 425 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry, 426 VNTAG_ACTIONSf, &vntag_actions); 427 if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) { 428 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry, 429 HG_VNTAG_MODIFY_ENABLEf, &hg_vntag_modify); 430 } 431 entries[0] = &vntag_etag_profile_entry; 432 BCM_IF_ERROR_RETURN(soc_profile_mem_add(unit, _bcm_th_vntag_etag_profile[unit], 433 entries, 1, &profile_idx)); 434 *vntag_etag_profile_index = profile_idx; 435 soc_mem_field32_set(unit, mem, bufp, fld->vntag_etag_profile_id, 436 profile_idx); 437 } else if (_bcm_vp_used_get(unit, l3cfg->l3c_encap_id, 438 _bcmVpTypeExtender)) { /* PE */ 439 bcm_extender_port_t ep; 440 int etag_dot1p_mapping_ptr = 0; 441 bcm_extender_egress_t extender_egress; 442 uint16 extended_port_vid; 443 int qos_map_id; 444 445 BCM_GPORT_EXTENDER_PORT_ID_SET(ep.extender_port_id, 446 l3cfg->l3c_encap_id); 447 BCM_IF_ERROR_RETURN(bcm_esw_extender_port_get(unit, &ep)); 448 if (ep.flags & BCM_EXTENDER_PORT_MATCH_NONE) { 449 bcm_extender_egress_t_init(&extender_egress); 450 BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit, 451 ep.extender_port_id, 1, &extender_egress, &count)); 452 if (count == 0) { 453 return BCM_E_CONFIG; 454 } 455 if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) { 456 return BCM_E_PARAM; 457 } 458 qos_map_id = extender_egress.qos_map_id; 459 extended_port_vid = extender_egress.extended_port_vid; 460 } else { 461 if (ep.flags & BCM_EXTENDER_PORT_MULTICAST) { 462 return BCM_E_PARAM; 463 } 464 qos_map_id = ep.qos_map_id; 465 extended_port_vid = ep.extended_port_vid; 466 } 467 468 sal_memset(&vntag_etag_profile_entry, 0, sizeof(vntag_etag_profile_entry)); 469 vntag_actions = 2; 470 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry, 471 VNTAG_ACTIONSf, &vntag_actions); 472 if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) { 473 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry, 474 HG_VNTAG_MODIFY_ENABLEf, &hg_vntag_modify); 475 } 476 bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id, 477 &etag_dot1p_mapping_ptr); 478 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry, 479 ETAG_DOT1P_MAPPING_PTRf, 480 (uint32 *)&etag_dot1p_mapping_ptr); 481 482 entries[0] = &vntag_etag_profile_entry; 483 BCM_IF_ERROR_RETURN(soc_profile_mem_add(unit, _bcm_th_vntag_etag_profile[unit], 484 entries, 1, &profile_idx)); 485 *vntag_etag_profile_index = profile_idx; 486 soc_mem_field32_set(unit, mem, bufp, fld->vntag_etag_profile_id, 487 profile_idx); 488 virtual_interface_id = extended_port_vid; 489 soc_mem_field32_set(unit, mem, bufp, fld->dst_vif, virtual_interface_id); 490 } else { 491 return BCM_E_PARAM; 492 } 493 } else { 494 soc_mem_field32_set(unit, mem, bufp, fld->vntag_etag_profile_id, 495 L3_EXT_VIEW_INVALID_VNTAG_ETAG_PROFILE); 496 } 497 soc_mem_mac_address_set(unit, mem, bufp, fld->macda_low, 498 l3cfg->l3c_mac_addr, 499 SOC_MEM_MAC_LOWER_ONLY); 500 mac_field = ((l3cfg->l3c_mac_addr[0] << 16) | 501 (l3cfg->l3c_mac_addr[1] << 8) | 502 (l3cfg->l3c_mac_addr[2] << 0)); 503 sal_memset(&macda_oui_profile_entry, 0, sizeof(macda_oui_profile_entry)); 504 soc_EGR_MACDA_OUI_PROFILEm_field_set(unit, &macda_oui_profile_entry, 505 MACDA_OUIf, &mac_field); 506 entries[0] = &macda_oui_profile_entry; 507 rv = soc_profile_mem_add(unit, _bcm_th_macda_oui_profile[unit], 508 entries, 1, &profile_idx); 509 if (BCM_FAILURE(rv)) { 510 /* delete previously added entry or decrement ref count 511 * from EGR_VNTAG_ETAG_PROFILE table 512 */ 513 soc_mem_lock(unit, EGR_VNTAG_ETAG_PROFILEm); 514 /* profile 0 is reserved for NON NIV/PE entries */ 515 if (*vntag_etag_profile_index != 0) { 516 rv1 = soc_profile_mem_delete(unit, _bcm_th_vntag_etag_profile[unit], 517 *vntag_etag_profile_index); 518 } 519 if (BCM_FAILURE(rv1)) { 520 soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm); 521 return rv1; 522 } 523 soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm); 524 return rv; 525 } 526 527 *macda_oui_profile_index = profile_idx; 528 soc_mem_field32_set(unit, mem, bufp, fld->oui_profile_id, 529 profile_idx); 530 531 #ifdef BCM_TRIDENT3_SUPPORT 532 if (SOC_IS_TRIDENT3X(unit)) { 533 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 534 soc_mem_field32_set(unit, mem, bufp, MACDA_OUI_PROFILE_VALIDf, 1); 535 } 536 } 537 #endif 538 return rv; 539 } 540 541 /* 542 * Function: 543 * th_glp_resolve 544 * Purpose: 545 * TH helper routine function to get modid, port, and trunk_id 546 * from a bcm_gport_t 547 * Parameters : (IN) unit - BCM device number 548 * (IN) gport - Global port identifier 549 * (OUT) modid - Module ID 550 * (OUT) port - Port number 551 * (OUT) is_trunk - Trunk 552 553 * Returns: 554 * BCM_X_XXX 555 */ 556 557 void _bcm_th_glp_resolve_embedded_nh(int unit, uint32 gport, 558 bcm_module_t *modid, bcm_port_t *port, 559 int *is_trunk) 560 { 561 562 uint8 port_mask_len = 0, modid_mask_len = 0; 563 uint32 temp = 0; 564 565 /* Determine length of port mask */ 566 temp = SOC_PORT_ADDR_MAX(unit); 567 while (0 != temp) { 568 port_mask_len++; 569 temp >>= 1; 570 } 571 572 /* Determine length of modid mask */ 573 temp = SOC_MODID_MAX(unit); 574 while (0 != temp) { 575 modid_mask_len++; 576 temp >>= 1; 577 } 578 *modid = (gport >> port_mask_len) & SOC_MODID_MAX(unit); 579 580 if (gport & (1 << (port_mask_len + modid_mask_len))) { 581 *is_trunk = 1; 582 } 583 *port = gport & SOC_PORT_ADDR_MAX(unit); 584 } 585 586 /* 587 * Function: 588 * _bcm_th_l3_ext_ent_init 589 * Purpose: 590 * TH helper routine used to init extended l3 host entry buffer 591 * Parameters: 592 * unit - (IN) SOC unit number. 593 * mem - (IN) L3 extended host memory. 594 * l3cfg - (IN/OUT) l3 entry lookup key & search result. 595 * l3x_entry - (IN) hw buffer. 596 * Returns: 597 * void 598 */ 599 STATIC int 600 _bcm_th_l3_ext_ent_init(int unit, soc_mem_t mem_ext, 601 _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 602 { 603 int ipv6; /* Entry is IPv6 flag. */ 604 uint32 *buf_p; /* HW buffer address. */ 605 606 607 /* Get entry type. */ 608 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 609 610 /* Zero destination buffer. */ 611 buf_p = (uint32 *)l3x_entry; 612 sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem_ext)); 613 614 if (ipv6) { /* ipv6 entry */ 615 if (BCM_XGS3_L3_MEM(unit, v6_4) == mem_ext) { 616 soc_mem_ip6_addr_set(unit, mem_ext, buf_p, IPV6UC_EXT__IP_ADDR_LWR_64f, 617 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 618 soc_mem_ip6_addr_set(unit, mem_ext, buf_p, IPV6UC_EXT__IP_ADDR_UPR_64f, 619 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 620 soc_mem_field32_set(unit, mem_ext, buf_p, IPV6UC_EXT__VRF_IDf, 621 l3cfg->l3c_vrf); 622 /* ipv6 extended host entry */ 623 #ifdef BCM_TRIDENT3_SUPPORT 624 if (SOC_IS_TRIDENT3X(unit)) { 625 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPEf, 626 TD3_L3_HASH_KEY_TYPE_V6UC_EXT); 627 soc_mem_field32_set(unit, mem_ext, buf_p, DATA_TYPEf, 628 TD3_L3_HASH_DATA_TYPE_V6UC_EXT); 629 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_0f, 3); 630 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_1f, 4); 631 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_2f, 7); 632 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_3f, 7); 633 } else 634 #endif 635 { 636 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_0f, 3); 637 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_1f, 3); 638 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_2f, 3); 639 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_3f, 3); 640 641 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_0f, 1); 642 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_1f, 1); 643 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_2f, 1); 644 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_3f, 1); 645 } 646 } else { 647 return BCM_E_NOT_FOUND; 648 } 649 } else { /* ipv4 entry */ 650 if (BCM_XGS3_L3_MEM(unit, v4_2) == mem_ext) { 651 soc_mem_field32_set(unit, mem_ext, buf_p, IPV4UC_EXT__IP_ADDRf, 652 l3cfg->l3c_ip_addr); 653 soc_mem_field32_set(unit, mem_ext, buf_p, IPV4UC_EXT__VRF_IDf, 654 l3cfg->l3c_vrf); 655 /* ipv4 extended host entry */ 656 #ifdef BCM_TRIDENT3_SUPPORT 657 if (SOC_IS_TRIDENT3X(unit)) { 658 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPEf, 659 TD3_L3_HASH_KEY_TYPE_V4UC_EXT); 660 soc_mem_field32_set(unit, mem_ext, buf_p, DATA_TYPEf, 661 TD3_L3_HASH_DATA_TYPE_V4UC_EXT); 662 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_0f, 1); 663 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_1f, 7); 664 } else 665 #endif 666 { 667 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_0f, 1); 668 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_1f, 1); 669 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_1f, 1); 670 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_0f, 1); 671 } 672 } else { 673 return BCM_E_NOT_FOUND; 674 } 675 } 676 return BCM_E_NONE; 677 678 } 679 680 /* 681 * Function: 682 * _bcm_th_l3_ent_init 683 * Purpose: 684 * TH helper routine used to init l3 host entry buffer 685 * Parameters: 686 * unit - (IN) SOC unit number. 687 * mem - (IN) L3 host memory. 688 * l3cfg - (IN/OUT) l3 entry lookup key & search result. 689 * l3x_entry - (IN) hw buffer. 690 * Returns: 691 * void 692 */ 693 STATIC int 694 _bcm_th_l3_ent_init(int unit, soc_mem_t mem, 695 _bcm_l3_cfg_t *l3cfg, void *l3x_entry) 696 { 697 int ipv6; /* Entry is IPv6 flag. */ 698 uint32 *buf_p; /* HW buffer address. */ 699 700 701 /* Get entry type. */ 702 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 703 704 /* Zero destination buffer. */ 705 buf_p = (uint32 *)l3x_entry; 706 sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 707 708 if (ipv6) { /* ipv6 entry */ 709 if (BCM_XGS3_L3_MEM(unit, v6) == mem) { 710 soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, 711 l3cfg->l3c_vrf); 712 #ifdef BCM_TRIDENT3_SUPPORT 713 if (SOC_IS_TRIDENT3X(unit)) { 714 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_LWR_64f, 715 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 716 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_UPR_64f, 717 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 718 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 2); 719 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, 3); 720 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, 4); 721 } else 722 #endif 723 { 724 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f, 725 l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY); 726 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f, 727 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY); 728 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 729 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 730 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 2); 731 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 2); 732 } 733 } else { 734 return BCM_E_NOT_FOUND; 735 } 736 } else { /* ipv4 entry */ 737 if (BCM_XGS3_L3_MEM(unit, v4) == mem) { 738 soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf, 739 l3cfg->l3c_ip_addr); 740 soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, 741 l3cfg->l3c_vrf); 742 /* ipv4 unicast */ 743 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 0); 744 #ifdef BCM_TRIDENT3_SUPPORT 745 if (SOC_IS_TRIDENT3X(unit)) { 746 soc_mem_field32_set(unit, mem, buf_p, BASE_VALIDf, 1); 747 } else 748 #endif 749 { 750 soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1); 751 } 752 } else { 753 return BCM_E_NOT_FOUND; 754 } 755 } 756 return BCM_E_NONE; 757 758 } 759 760 /* 761 * Function: 762 * _bcm_th_get_extended_profile_index 763 * Purpose: 764 * TH helper routine used to get profile index for EGR_MACDA_OUI_PROFILE 765 * and EGR_VNTAG_ETAG_PROFILE 766 * Parameters: 767 * unit - (IN) SOC unit number. 768 * mem - (IN) L3 Extended table memory. 769 * l3cfg - (IN) L3 entry info. 770 * macda_oui_profile_index - (out) EGR_MACDA_OUI profile index. 771 * vntag_etag_profile_index - (out) EGR_VNTAG_ETAG profile index. 772 * Returns: 773 * BCM_X_XXX 774 */ 775 bcm_error_t _bcm_th_get_extended_profile_index(int unit, soc_mem_t mem_ext, 776 _bcm_l3_cfg_t *l3cfg, 777 int *macda_oui_profile_index, 778 int *vntag_etag_profile_index, 779 int *ref_count) { 780 781 int ipv6; /* IPv6 entry indicator.*/ 782 int rv = BCM_E_NONE; /* Operation return status. */ 783 uint32 *buf_key, *buf_entry; /* Key and entry buffer ptrs*/ 784 l3_entry_ipv4_unicast_entry_t l3v4_key, l3v4_entry; /* IPv4 */ 785 l3_entry_ipv4_multicast_entry_t l3v4_ext_key, l3v4_ext_entry; /* IPv4-Embedded */ 786 l3_entry_ipv6_unicast_entry_t l3v6_key, l3v6_entry; /* IPv6 */ 787 l3_entry_ipv6_multicast_entry_t l3v6_ext_key, l3v6_ext_entry; /* IPv6-Embedded */ 788 soc_field_t macda_oui_id, vntag_etag_id; 789 soc_mem_t mem; 790 791 792 /* Get entry type. */ 793 ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6); 794 795 if (ipv6) { 796 #ifdef BCM_TRIDENT3_SUPPORT 797 if (SOC_IS_TRIDENT3X(unit)) { 798 macda_oui_id = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf; 799 } else 800 #endif 801 { 802 macda_oui_id = IPV6UC_EXT__MAC_DA_OUI_PROFILE_IDf; 803 } 804 vntag_etag_id = IPV6UC_EXT__VNTAG_ETAG_PROFILE_IDf; 805 mem = BCM_XGS3_L3_MEM(unit, v6); 806 } else { 807 #ifdef BCM_TRIDENT3_SUPPORT 808 if (SOC_IS_TRIDENT3X(unit)) { 809 macda_oui_id = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf; 810 } else 811 #endif 812 { 813 macda_oui_id = IPV4UC_EXT__MAC_DA_OUI_PROFILE_IDf; 814 } 815 vntag_etag_id = IPV4UC_EXT__VNTAG_ETAG_PROFILE_IDf; 816 mem = BCM_XGS3_L3_MEM(unit, v4); 817 } 818 819 /* Assign entry-key buf based on table being used */ 820 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key, 821 l3v4_key, 822 l3v4_ext_key, 823 l3v6_key, 824 l3v6_ext_key); 825 826 /* Assign entry buf based on table being used */ 827 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry, 828 l3v4_entry, 829 l3v4_ext_entry, 830 l3v6_entry, 831 l3v6_ext_entry); 832 833 /* Prepare lookup key. */ 834 BCM_IF_ERROR_RETURN 835 (_bcm_th_l3_ext_ent_init(unit, mem_ext, l3cfg, buf_key)); 836 837 /* Perform lookup hw. */ 838 rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY, 839 _BCM_TD2_L3_MEM_BANKS_ALL, 840 buf_key, buf_entry, &l3cfg->l3c_hw_index); 841 if (BCM_SUCCESS(rv)) { 842 *macda_oui_profile_index = soc_mem_field32_get(unit, mem_ext, buf_entry, 843 macda_oui_id); 844 *vntag_etag_profile_index = soc_mem_field32_get(unit, mem_ext, buf_entry, 845 vntag_etag_id); 846 rv = soc_profile_mem_ref_count_get(unit, 847 _bcm_th_macda_oui_profile[unit], 848 *macda_oui_profile_index, 849 ref_count); 850 return rv; 851 } else if (BCM_E_NOT_FOUND == rv) { 852 /* Check if entry was added in regular L3_ENTRY table view */ 853 854 /* Assign entry-key buf based on table being used */ 855 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, 856 l3v4_key, 857 l3v4_ext_key, 858 l3v6_key, 859 l3v6_ext_key); 860 861 /* Assign entry buf based on table being used */ 862 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, 863 l3v4_entry, 864 l3v4_ext_entry, 865 l3v6_entry, 866 l3v6_ext_entry); 867 868 /* Prepare lookup key. */ 869 BCM_IF_ERROR_RETURN(_bcm_th_l3_ent_init(unit, mem, l3cfg, buf_key)); 870 871 /* Perform lookup */ 872 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 873 _BCM_TD2_L3_MEM_BANKS_ALL, 874 buf_key, buf_entry, &l3cfg->l3c_hw_index); 875 return rv; 876 } 877 878 return rv; 879 880 } 881 882 /* 883 * Function: 884 * _bcm_th_l3_ecmp_across_layers_move 885 * Purpose: 886 * Move ecmp entries (which have no flags - BCM_L3_ECMP_UNDERLAY/OVERLAY) 887 * across two layers 888 * Parameters: 889 * unit - (IN) SOC unit number. 890 * threshold - (IN) Move threshold. 891 * direction - (IN) Move direction (0: L2 -> L1, 1: L1 -> L2). 892 * Returns: 893 * BCM_E_XXX. 894 */ 895 int 896 _bcm_th_l3_ecmp_across_layers_move(int unit, int threshold, int direction) 897 { 898 int rv = BCM_E_NONE; 899 int idx_min = 0; 900 int idx_max = 0; 901 int i = 0; 902 int idx_increment = 0; 903 int max_paths = 0; 904 int base_ptr = 0; 905 int boundary = 0; 906 int old_ecmp_tbl_idx_min = 0; 907 int old_ecmp_tbl_idx_max = 0; 908 int move_width = 0; 909 _bcm_l3_tbl_op_t data; 910 _bcm_l3_tbl_t *ecmp_group_tbl_ptr = NULL; 911 _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL; 912 ecmp_count_entry_t *ecmp_group_entry = NULL; 913 uint8 *ecmp_group_buf = NULL; 914 soc_defragment_member_op_t member_op; 915 soc_defragment_group_op_t group_op; 916 917 ecmp_group_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 918 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 919 old_ecmp_tbl_idx_max = ecmp_tbl_ptr->idx_max; 920 old_ecmp_tbl_idx_min = ecmp_tbl_ptr->idx_min; 921 if (direction) { 922 /* direction: L1 -> L2, try to get free index in L2 */ 923 ecmp_tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMPm) - 1; 924 ecmp_tbl_ptr->idx_min = soc_mem_index_count(unit, L3_ECMPm) / 2; 925 } else { 926 /* direction: L2 -> L1, try to get free index in L1 */ 927 ecmp_tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMPm) / 2 - 1; 928 ecmp_tbl_ptr->idx_min = soc_mem_index_min(unit, L3_ECMPm); 929 } 930 931 sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t)); 932 data.tbl_ptr = ecmp_tbl_ptr; 933 data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 934 data.entry_index = -1; 935 936 member_op.member_copy = _bcm_tr2_l3_ecmp_member_copy; 937 member_op.member_clear = _bcm_tr2_l3_ecmp_member_clear; 938 group_op.group_base_ptr_update = _bcm_tr2_l3_ecmp_group_base_ptr_update; 939 940 boundary = soc_mem_index_count(unit, L3_ECMPm) / 2; 941 942 /* 943 * Max_Ecmp_Group : TH 2K TH2 4K 944 * Max_Ecmp_Member : TH 16K TH2 32K 945 * 946 * Combination_1 for ecmp_group_flags with 0 : 947 * Group Index [0 ~ Max_Ecmp_Group / 2 - 1] 948 * Member Index [0 ~ Max_Ecmp_Member - 1] 949 * 950 * Combination_2 for ecmp_group_flags with 0 : 951 * Group Index [Max_Ecmp_Group / 2 ~ Max_Ecmp_Group - 1] 952 * Member Index [Max_Ecmp_Member /2 ~ Max_Ecmp_Member - 1] 953 * 954 * So only can move ecmp members of the groups [0 ~ Max_Ecmp_Group / 2 - 1] 955 * across layers 956 */ 957 idx_min = soc_mem_index_min(unit, L3_ECMP_COUNTm); 958 idx_max = soc_mem_index_count(unit, L3_ECMP_COUNTm) / 2 - 1; 959 960 ecmp_group_buf = 961 soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, L3_ECMP_COUNTm), 962 "L3_ECMP_COUNT buffer"); 963 if (NULL == ecmp_group_buf) { 964 goto clean_up; 965 } 966 967 rv = soc_mem_read_range(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, 968 idx_min, idx_max, ecmp_group_buf); 969 if (SOC_FAILURE(rv)) { 970 goto clean_up; 971 } 972 973 idx_increment = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 974 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE; 975 976 for (i = idx_min; i <= idx_max; i += idx_increment) { 977 if (soc_feature(unit, soc_feature_vp_lag)) { 978 /* Skip VP LAG entries */ 979 int is_vp_lag, is_used, has_member; 980 rv = bcm_td2_vp_lag_status_get( 981 unit, i, &is_vp_lag, &is_used, &has_member); 982 if (BCM_FAILURE(rv)) { 983 goto clean_up; 984 } 985 if (is_vp_lag) { 986 continue; 987 } 988 } 989 990 if (!BCM_XGS3_L3_ENT_REF_CNT(ecmp_group_tbl_ptr, i)) { 991 /* Skip unused entries */ 992 continue; 993 } 994 995 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, i, BCM_L3_ECMP_OVERLAY) || 996 BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, i, BCM_L3_ECMP_UNDERLAY)) { 997 /* Skip entries which have BCM_L3_ECMP_OVERLAY/OVERLAY flags */ 998 continue; 999 } 1000 1001 ecmp_group_entry = soc_mem_table_idx_to_pointer(unit, L3_ECMP_COUNTm, 1002 ecmp_count_entry_t *, 1003 ecmp_group_buf, i); 1004 base_ptr = 1005 soc_L3_ECMP_COUNTm_field32_get(unit, ecmp_group_entry, BASE_PTRf); 1006 rv = bcm_xgs3_l3_egress_ecmp_max_paths_get( 1007 unit, i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), NULL, &max_paths); 1008 if (BCM_FAILURE(rv)) { 1009 goto clean_up; 1010 } 1011 1012 if (((1 == direction) && (base_ptr < boundary)) || 1013 ((0 == direction) && (base_ptr >= boundary))) { 1014 1015 data.width = max_paths; 1016 rv = _bcm_xgs3_tbl_free_idx_get(unit, &data); 1017 if (BCM_SUCCESS(rv)) { 1018 rv = soc_defragment_block_move(unit, base_ptr, 1019 data.entry_index, max_paths, 1020 &member_op, i, &group_op); 1021 if (BCM_FAILURE(rv)) { 1022 goto clean_up; 1023 } 1024 1025 move_width += max_paths; 1026 if (move_width >= threshold) { 1027 break; 1028 } 1029 } 1030 } 1031 } 1032 1033 rv = BCM_E_NONE; 1034 1035 clean_up: 1036 1037 if (NULL != ecmp_group_buf) { 1038 soc_cm_sfree(unit, ecmp_group_buf); 1039 } 1040 1041 ecmp_tbl_ptr->idx_max = old_ecmp_tbl_idx_max; 1042 ecmp_tbl_ptr->idx_min = old_ecmp_tbl_idx_min; 1043 1044 return rv; 1045 } 1046 1047 /* 1048 * Function: 1049 * bcm_th_l3_extended_required_scache_size_get 1050 * Purpose: 1051 * Get required NIV module scache size for Level 2 Warm Boot in Tomahawk 1052 * L3_ENTRY extended view 1053 * Parameters: 1054 * unit - StrataSwitch unit number. 1055 * size - (OUT) Required scache size. 1056 */ 1057 void 1058 bcm_th_l3_extended_required_scache_size_get(int unit, int *size) 1059 { 1060 1061 if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 1062 /* Sync the ref_count of EGR_MACDA_OUI_PROFILEm */ 1063 *size += SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm) * sizeof(uint32); 1064 1065 /* Sync the ref_count of EGR_VNTAG_ETAG_PROFILEm */ 1066 *size += SOC_MEM_SIZE(unit, EGR_VNTAG_ETAG_PROFILEm) * sizeof(uint32); 1067 } 1068 } 1069 1070 /* 1071 * Function: 1072 * soc_profile_th_mem_ref_count_get 1073 * Purpose: 1074 * Get the reference count of the cached entry at the specified index. 1075 * 1076 * Parameters: 1077 * unit - (IN) Unit 1078 * profile - (IN) Pointer to profile memory structure 1079 * index0 - (IN) Base index to the entries in HW for table 0 1080 * ref_count - (OUT) Reference count 1081 * Returns: 1082 * SOC_E_XXX 1083 */ 1084 static soc_error_t 1085 soc_profile_th_mem_ref_count_get(int unit, 1086 soc_profile_mem_t *profile, 1087 int index0, 1088 uint32 *ref_count) 1089 { 1090 soc_profile_mem_table_t *table; 1091 int base0; 1092 1093 if (profile == NULL || ref_count == NULL) { 1094 return SOC_E_PARAM; 1095 } 1096 1097 if (profile->tables == NULL || profile->table_count == 0) { 1098 return SOC_E_INIT; 1099 } 1100 1101 table = &profile->tables[0]; 1102 if (index0 < table->index_min || index0 > table->index_max) { 1103 return SOC_E_PARAM; 1104 } 1105 1106 base0 = index0 - table->index_min; 1107 1108 *ref_count = table->entries[base0].ref_count; 1109 1110 return SOC_E_NONE; 1111 } 1112 1113 /* 1114 * Function: 1115 * bcm_th_l3_extended_view_sync 1116 * Purpose: 1117 * Record persistent info into the scache for the TH NIV software module 1118 * for L3_ENTRY extended view. 1119 * Parameters: 1120 * unit - StrataSwitch unit # 1121 * scache_ptr - (IN/OUT) Scache pointer 1122 * Returns: 1123 * BCM_E_xxx 1124 */ 1125 bcm_error_t 1126 bcm_th_l3_extended_view_sync(int unit, uint8 **scache_ptr) 1127 { 1128 int rv = BCM_E_NONE; 1129 int i; 1130 uint32 ref_count; 1131 1132 if (!BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 1133 return rv; 1134 } 1135 1136 if ((scache_ptr == NULL) || (*scache_ptr == NULL)) { 1137 return BCM_E_PARAM; 1138 } 1139 1140 /* Record EGR_MACDA_OUI_PROFILEm ref_count in scache */ 1141 for (i = 0; i < SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm); i++) { 1142 /* Generic profile library has a routine which takes ref_count as 1143 * int. However, MACDA_OUI_PROFILE table can have ref_count exceeding 1144 * int max value. Below routine takes ref_count as uint32 for TH 1145 */ 1146 rv = soc_profile_th_mem_ref_count_get(unit, 1147 _bcm_th_macda_oui_profile[unit], 1148 i, 1149 &ref_count); 1150 if (!(rv == SOC_E_NONE)) { 1151 return rv; 1152 } 1153 1154 sal_memcpy((*scache_ptr), &ref_count, sizeof(uint32)); 1155 (*scache_ptr) += sizeof(ref_count); 1156 } 1157 1158 /* Record EGR_VNTAG_ETAG_PROFILEm ref_count in scache */ 1159 for (i = 0; i < SOC_MEM_SIZE(unit, EGR_VNTAG_ETAG_PROFILEm); i++) { 1160 rv = soc_profile_th_mem_ref_count_get(unit, 1161 _bcm_th_vntag_etag_profile[unit], 1162 i, 1163 &ref_count); 1164 if (!(rv == SOC_E_NONE)) { 1165 return rv; 1166 } 1167 1168 sal_memcpy((*scache_ptr), &ref_count, sizeof(uint32)); 1169 (*scache_ptr) += sizeof(ref_count); 1170 } 1171 1172 return rv; 1173 } 1174 1175 /* 1176 * Function: 1177 * bcm_th_l3_extended_view_reinit 1178 * Purpose: 1179 * Warm boot recovery for the TH NIV software module for L3_ENTRY 1180 * extended view 1181 * Parameters: 1182 * unit - Device Number 1183 * defaul_ver - Warm boot default version 1184 * Returns: 1185 * BCM_E_XXX 1186 */ 1187 bcm_error_t 1188 bcm_th_l3_extended_view_reinit(int unit, uint8 **scache_ptr) 1189 { 1190 int rv = BCM_E_NONE; 1191 soc_profile_mem_t *profile_mem; 1192 int i, j, size; 1193 uint32 ref_count; 1194 1195 if (!BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) { 1196 return rv; 1197 } 1198 1199 if ((scache_ptr == NULL) || (*scache_ptr == NULL)) { 1200 return BCM_E_PARAM; 1201 } 1202 1203 /* Update EGR_MACDA_OUI_PROFILE memory profile reference counter */ 1204 profile_mem = _bcm_th_macda_oui_profile[unit]; 1205 size = SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm); 1206 for (i = 0; i < size; i++) { 1207 sal_memcpy(&ref_count, (*scache_ptr), sizeof(uint32)); 1208 (*scache_ptr) += sizeof(ref_count); 1209 for (j = 0; j < ref_count; j++) { 1210 SOC_IF_ERROR_RETURN( 1211 soc_profile_mem_reference(unit, profile_mem, i, 1)); 1212 } 1213 } 1214 1215 /* Update EGR_VNTAG_ETAG_PROFILE memory profile reference counter */ 1216 profile_mem = _bcm_th_vntag_etag_profile[unit]; 1217 size = SOC_MEM_SIZE(unit, EGR_VNTAG_ETAG_PROFILEm); 1218 for (i = 0; i < size; i++) { 1219 sal_memcpy(&ref_count, (*scache_ptr), sizeof(uint32)); 1220 (*scache_ptr) += sizeof(ref_count); 1221 for (j = 0; j < ref_count; j++) { 1222 SOC_IF_ERROR_RETURN( 1223 soc_profile_mem_reference(unit, profile_mem, i, 1)); 1224 } 1225 } 1226 1227 return rv; 1228 } 1229 1230 #endif 1231