l3.c (72274B)
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: Triumph2 L3 function implementations 9 */ 10 11 12 #include <soc/defs.h> 13 14 #include <assert.h> 15 #include <shared/bsl.h> 16 #include <sal/core/libc.h> 17 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3) 18 19 #include <shared/util.h> 20 #include <soc/mem.h> 21 #include <soc/cm.h> 22 #include <soc/drv.h> 23 #include <soc/register.h> 24 #include <soc/memory.h> 25 #include <soc/l3x.h> 26 #include <soc/lpm.h> 27 #include <soc/tnl_term.h> 28 #include <soc/defragment.h> 29 30 #include <bcm/l3.h> 31 #include <bcm/tunnel.h> 32 #include <bcm/debug.h> 33 #include <bcm/error.h> 34 #include <bcm/stack.h> 35 36 #include <bcm_int/esw/mbcm.h> 37 #include <bcm_int/esw/firebolt.h> 38 #include <bcm_int/esw/trx.h> 39 #include <bcm_int/esw/triumph2.h> 40 #include <bcm_int/esw/l3.h> 41 #include <bcm_int/esw/xgs3.h> 42 #include <bcm_int/esw/stack.h> 43 #include <bcm_int/esw_dispatch.h> 44 #if defined(BCM_TRIDENT2_SUPPORT) 45 #include <bcm_int/esw/trident2.h> 46 #endif /* BCM_TRIDENT2_SUPPORT*/ 47 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 48 #include <bcm_int/esw/trident2plus.h> 49 #endif /* BCM_TRIDENT2_SUPPORT*/ 50 #if defined(BCM_TOMAHAWK_SUPPORT) 51 #include <bcm_int/esw/tomahawk.h> 52 #endif /* BCM_TOMAHAWK_SUPPORT */ 53 #if defined(BCM_TRIDENT3_SUPPORT) 54 #include <bcm_int/esw/trident3.h> 55 #endif /* BCM_TRIDENT3_SUPPORT */ 56 #include <bcm_int/esw/ecn.h> 57 58 #define ECN_INFO(_unit_) (&_bcm_xgs5_ecn_bk_info[_unit_]) 59 60 /* L3 ECMP table defragmentation buffer info */ 61 typedef struct _bcm_tr2_l3_ecmp_defragment_buffer_s { 62 int base_ptr; /* Starting index of the buffer used 63 in ECMP table defragmentation */ 64 int size; /* Size of the buffer */ 65 } _bcm_tr2_l3_ecmp_defragment_buffer_t; 66 67 extern int ecmp_mode_hierarchical; 68 extern int ecmp_mode_single; 69 70 STATIC _bcm_tr2_l3_ecmp_defragment_buffer_t 71 *_bcm_tr2_l3_ecmp_defragment_buffer_info[BCM_MAX_NUM_UNITS]; 72 73 /* 74 * Function: 75 * _bcm_tr2_l3_tnl_term_add 76 * Purpose: 77 * Add tunnel termination entry to the hw. 78 * Parameters: 79 * unit - (IN)SOC unit number. 80 * tnl_info - (IN)Tunnel terminator parameters. 81 * Returns: 82 * BCM_E_XXX 83 */ 84 int 85 _bcm_tr2_l3_tnl_term_add(int unit, uint32 *entry_ptr, bcm_tunnel_terminator_t *tnl_info) 86 { 87 bcm_module_t mod_in, mod_out, my_mod; 88 bcm_port_t port_in, port_out; 89 _bcm_l3_ingress_intf_t iif; 90 int tunnel, wlan; 91 int rv; 92 93 /* Program remote port */ 94 if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 95 (tnl_info->type == bcmTunnelTypeWlanAcToAc) || 96 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) || 97 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 98 wlan = 1; 99 } else { 100 wlan = 0; 101 } 102 103 if (wlan) { 104 if (tnl_info->flags & BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE) { 105 if (!BCM_GPORT_IS_MODPORT(tnl_info->remote_port)) { 106 return BCM_E_PARAM; 107 } 108 mod_in = BCM_GPORT_MODPORT_MODID_GET(tnl_info->remote_port); 109 port_in = BCM_GPORT_MODPORT_PORT_GET(tnl_info->remote_port); 110 BCM_IF_ERROR_RETURN 111 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 112 port_in, &mod_out, &port_out)); 113 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 114 return (BCM_E_BADID); 115 } 116 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 117 return (BCM_E_PORT); 118 } 119 soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf, 120 (mod_out << 6) | port_out); 121 } else { 122 /* Send to the local loopback port */ 123 rv = bcm_esw_stk_my_modid_get(unit, &my_mod); 124 BCM_IF_ERROR_RETURN(rv); 125 port_in = 54; 126 mod_in = my_mod; 127 rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 128 port_in, &mod_out, &port_out); 129 BCM_IF_ERROR_RETURN(rv); 130 131 soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf, 132 (mod_out << 6) | port_out); 133 } 134 /* Program tunnel id */ 135 if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) { 136 if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) { 137 return BCM_E_PARAM; 138 } 139 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) { 140 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id); 141 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf, 142 tunnel); 143 } 144 } 145 146 } 147 if ((tnl_info->type == bcmTunnelTypeAutoMulticast) || 148 (tnl_info->type == bcmTunnelTypeAutoMulticast6)) { 149 /* Program L3_IIFm */ 150 if(SOC_MEM_FIELD_VALID(unit, L3_IIFm, IPMC_L3_IIFf)) { 151 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 152 iif.intf_id = tnl_info->vlan; 153 154 rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 155 BCM_IF_ERROR_RETURN(rv); 156 iif.vrf = tnl_info->vrf; 157 #if defined(BCM_TRIDENT2_SUPPORT) 158 if (soc_feature(unit, soc_feature_l3_iif_profile)) { 159 iif.profile_flags |= _BCM_L3_IIF_PROFILE_DO_NOT_UPDATE; 160 } 161 #endif /* BCM_TRIDENT2_SUPPORT */ 162 rv = _bcm_tr_l3_ingress_interface_set(unit, &iif,NULL, NULL); 163 BCM_IF_ERROR_RETURN(rv); 164 } 165 166 /* Program tunnel id */ 167 if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) { 168 if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) { 169 return BCM_E_PARAM; 170 } 171 if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) { 172 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id); 173 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf, 174 tunnel); 175 } 176 } 177 } 178 return (BCM_E_NONE); 179 } 180 181 /* 182 * Function: 183 * _bcm_tr2_l3_tnl_term_entry_init 184 * Purpose: 185 * Initialize soc tunnel terminator entry key portion. 186 * Parameters: 187 * unit - (IN) BCM device number. 188 * tnl_info - (IN) BCM buffer with tunnel info. 189 * entry - (OUT) SOC buffer with key filled in. 190 * Returns: 191 * BCM_E_XXX 192 */ 193 int 194 _bcm_tr2_l3_tnl_term_entry_init(int unit, bcm_tunnel_terminator_t *tnl_info, 195 soc_tunnel_term_t *entry) 196 { 197 int idx; /* Entry iteration index. */ 198 int idx_max; /* Entry widht. */ 199 uint32 *entry_ptr; /* Filled entry pointer. */ 200 _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */ 201 int rv; /* Operation return status. */ 202 int valid_bit = 0; 203 soc_mem_t mem = L3_TUNNELm; 204 205 /* Input parameters check. */ 206 if ((NULL == tnl_info) || (NULL == entry)) { 207 return (BCM_E_PARAM); 208 } 209 210 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 211 mem = L3_TUNNEL_DOUBLEm; 212 } 213 214 /* Get tunnel type & sub_type. */ 215 BCM_IF_ERROR_RETURN 216 (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type)); 217 218 /* Reset destination structure. */ 219 sal_memset(entry, 0, sizeof(soc_tunnel_term_t)); 220 221 /* Set Destination/Source pair. */ 222 entry_ptr = (uint32 *)&entry->entry_arr[0]; 223 if (tnl_type.tnl_outer_hdr_ipv6 == 1) { 224 /* Apply mask on source address. */ 225 rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6); 226 BCM_IF_ERROR_RETURN(rv); 227 228 /* SIP [0-63] */ 229 soc_mem_ip6_addr_set(unit, mem, 230 (uint32 *)&entry->entry_arr[0], IP_ADDRf, 231 tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY); 232 /* SIP [64-127] */ 233 soc_mem_ip6_addr_set(unit, mem, 234 (uint32 *)&entry->entry_arr[1], IP_ADDRf, 235 tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY); 236 /* DIP [0-63] */ 237 soc_mem_ip6_addr_set(unit, mem, 238 (uint32 *)&entry->entry_arr[2], IP_ADDRf, 239 tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY); 240 /* DIP [64-127] */ 241 soc_mem_ip6_addr_set(unit, mem, 242 (uint32 *)&entry->entry_arr[3], IP_ADDRf, 243 tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY); 244 245 /* SIP MASK [0-63] */ 246 soc_mem_ip6_addr_set(unit, mem, 247 (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf, 248 tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY); 249 /* SIP MASK [64-127] */ 250 soc_mem_ip6_addr_set(unit, mem, 251 (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf, 252 tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY); 253 /* DIP MASK [0-63] */ 254 soc_mem_ip6_addr_set(unit, mem, 255 (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf, 256 tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY); 257 /* DIP MASK [64-127] */ 258 soc_mem_ip6_addr_set(unit, mem, 259 (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf, 260 tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY); 261 } else if (tnl_type.tnl_outer_hdr_ipv6 == 0) { 262 tnl_info->sip &= tnl_info->sip_mask; 263 264 /* Set destination ip. */ 265 soc_mem_field32_set(unit, mem, entry_ptr, DIPf, tnl_info->dip); 266 267 /* Set source ip. */ 268 soc_mem_field32_set(unit, mem, entry_ptr, SIPf, tnl_info->sip); 269 270 /* Set destination subnet mask. */ 271 soc_mem_field32_set(unit, mem, entry_ptr, DIP_MASKf, 272 tnl_info->dip_mask); 273 274 /* Set source subnet mask. */ 275 soc_mem_field32_set(unit, mem, entry_ptr, SIP_MASKf, 276 tnl_info->sip_mask); 277 } 278 /* Resolve number of entries hw entry occupies. */ 279 idx_max = (tnl_type.tnl_outer_hdr_ipv6 == 1) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \ 280 (tnl_type.tnl_outer_hdr_ipv6 == 0) ? SOC_TNL_TERM_IPV4_ENTRY_WIDTH : 0; 281 282 for (idx = 0; idx < idx_max; idx++) { 283 entry_ptr = (uint32 *)&entry->entry_arr[idx]; 284 285 /* Set valid bit. */ 286 valid_bit = 1 << soc_mem_field_length(unit,mem,VALIDf); 287 valid_bit -= 1; 288 soc_mem_field32_set(unit, mem, entry_ptr, VALIDf, valid_bit); 289 290 /* Set tunnel subtype. */ 291 soc_mem_field32_set(unit, mem, entry_ptr, SUB_TUNNEL_TYPEf, 292 tnl_type.tnl_sub_type); 293 294 /* Set tunnel type. */ 295 soc_mem_field32_set(unit, mem, entry_ptr, TUNNEL_TYPEf, 296 tnl_type.tnl_auto); 297 298 /* Set entry mode. */ 299 300 if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) { 301 soc_mem_field32_set(unit, mem, entry_ptr, MODEf, 302 tnl_type.tnl_outer_hdr_ipv6); 303 soc_mem_field32_set(unit, mem, entry_ptr, MODE_MASKf, 1); 304 } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) { 305 soc_mem_field32_set(unit, mem, entry_ptr, KEY_TYPEf, 306 tnl_type.tnl_outer_hdr_ipv6); 307 soc_mem_field32_set(unit, mem, entry_ptr, KEY_TYPE_MASKf, 1); 308 } 309 310 if (0 == idx) { 311 /* Set the PROTOCOL field */ 312 if ((tnl_info->type == bcmTunnelTypeIpAnyIn4) || 313 (tnl_info->type == bcmTunnelTypeIpAnyIn6)) 314 { 315 /* Set PROTOCOL and PROTOCOL_MASK field to zero for IpAnyInx tunnel type*/ 316 soc_mem_field32_set(unit, mem, entry_ptr, PROTOCOLf, 0x0); 317 soc_mem_field32_set(unit, mem, entry_ptr, PROTOCOL_MASKf, 0x0); 318 } else { 319 soc_mem_field32_set(unit, mem, entry_ptr, PROTOCOLf, 320 tnl_type.tnl_protocol); 321 soc_mem_field32_set(unit, mem, entry_ptr, 322 PROTOCOL_MASKf, 0xff); 323 } 324 } 325 326 if (SOC_MEM_FIELD_VALID(unit, mem, BFD_ENABLEf)) { 327 soc_mem_field32_set(unit, mem, entry_ptr, BFD_ENABLEf, 0); 328 } 329 330 if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 331 (tnl_info->type == bcmTunnelTypeWlanAcToAc) || 332 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) || 333 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 334 335 /* Set the L4 ports - WLAN/AMT tunnels */ 336 if (0 == idx) { 337 soc_mem_field32_set(unit, mem, entry_ptr, L4_DEST_PORTf, 338 tnl_info->udp_dst_port); 339 340 soc_mem_field32_set(unit, mem, entry_ptr, 341 L4_DEST_PORT_MASKf, 0xffff); 342 343 soc_mem_field32_set(unit, mem, entry_ptr, L4_SRC_PORTf, 344 tnl_info->udp_src_port); 345 346 soc_mem_field32_set(unit, mem, entry_ptr, 347 L4_SRC_PORT_MASKf, 0xffff); 348 } 349 350 /* Set UDP tunnel type. */ 351 if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) { 352 soc_mem_field32_set(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf, 353 tnl_type.tnl_udp_type); 354 } 355 /* Ignore UDP checksum */ 356 if (soc_mem_field_valid(unit, mem, IGNORE_UDP_CHECKSUMf)) { 357 soc_mem_field32_set(unit, mem, entry_ptr, IGNORE_UDP_CHECKSUMf, 0x1); 358 } 359 } else if (tnl_info->type == bcmTunnelTypeAutoMulticast) { 360 361 /* Set UDP tunnel type. */ 362 if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) { 363 soc_mem_field32_set(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf, 364 tnl_type.tnl_udp_type); 365 } 366 367 if (soc_mem_field_valid(unit, mem, IGNORE_UDP_CHECKSUMf)) { 368 soc_mem_field32_set(unit, mem, entry_ptr, IGNORE_UDP_CHECKSUMf, 0x1); 369 } 370 371 if (soc_mem_field_valid(unit, mem, CTRL_PKTS_TO_CPUf)) { 372 soc_mem_field32_set(unit, mem, entry_ptr, CTRL_PKTS_TO_CPUf, 0x1); 373 } 374 } else if (tnl_info->type == bcmTunnelTypeAutoMulticast6) { 375 376 /* Set UDP tunnel type. */ 377 if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) { 378 soc_mem_field32_set(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf, 379 tnl_type.tnl_udp_type); 380 } 381 382 if (soc_mem_field_valid(unit, mem, IGNORE_UDP_CHECKSUMf)) { 383 soc_mem_field32_set(unit, mem, entry_ptr, IGNORE_UDP_CHECKSUMf, 0x1); 384 } 385 386 if (soc_mem_field_valid(unit, mem, CTRL_PKTS_TO_CPUf)) { 387 soc_mem_field32_set(unit, mem, entry_ptr, CTRL_PKTS_TO_CPUf, 0x1); 388 } 389 } 390 391 /* Save vlan id for ipmc lookup.*/ 392 if((tnl_info->vlan) && SOC_MEM_FIELD_VALID(unit, mem, L3_IIFf)) { 393 soc_mem_field32_set(unit, mem, entry_ptr, L3_IIFf, tnl_info->vlan); 394 } 395 396 /* Set GRE payload */ 397 if (tnl_type.tnl_gre) { 398 /* GRE IPv6 payload is allowed. */ 399 soc_mem_field32_set(unit, mem, entry_ptr, GRE_PAYLOAD_IPV6f, 400 tnl_type.tnl_gre_v6_payload); 401 402 /* GRE IPv6 payload is allowed. */ 403 soc_mem_field32_set(unit, mem, entry_ptr, GRE_PAYLOAD_IPV4f, 404 tnl_type.tnl_gre_v4_payload); 405 } 406 } 407 return (BCM_E_NONE); 408 } 409 410 /* 411 * Function: 412 * _bcm_tr2_l3_tnl_term_entry_parse 413 * Purpose: 414 * Parse tunnel terminator entry portion. 415 * Parameters: 416 * unit - (IN) BCM device number. 417 * entry - (IN) SOC buffer with tunne information. 418 * tnl_info - (OUT) BCM buffer with tunnel info. 419 * Returns: 420 * BCM_E_XXX 421 */ 422 int 423 _bcm_tr2_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry, 424 bcm_tunnel_terminator_t *tnl_info) 425 { 426 _bcm_tnl_term_type_t tnl_type; /* Tunnel type information. */ 427 uint32 *entry_ptr; /* Filled entry pointer. */ 428 int tunnel_id; /* Tunnel ID */ 429 int remote_port; /* Remote port */ 430 bcm_module_t mod, mod_out, my_mod; /* Module IDs */ 431 bcm_port_t port, port_out; /* Physical ports */ 432 soc_mem_t mem = L3_TUNNELm; 433 /* Input parameters check. */ 434 if ((NULL == tnl_info) || (NULL == entry)) { 435 return (BCM_E_PARAM); 436 } 437 438 /* Reset destination structure. */ 439 bcm_tunnel_terminator_t_init(tnl_info); 440 sal_memset(&tnl_type, 0, sizeof(_bcm_tnl_term_type_t)); 441 442 if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) { 443 mem = L3_TUNNEL_DOUBLEm; 444 } 445 446 entry_ptr = (uint32 *)&entry->entry_arr[0]; 447 448 /* Get valid bit. */ 449 if (!soc_mem_field32_get(unit, mem, entry_ptr, VALIDf)) { 450 return (BCM_E_NOT_FOUND); 451 } 452 453 if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) { 454 tnl_type.tnl_outer_hdr_ipv6 = 455 soc_mem_field32_get(unit, mem, entry_ptr, MODEf); 456 } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) { 457 tnl_type.tnl_outer_hdr_ipv6 = 458 soc_mem_field32_get(unit, mem, entry_ptr, KEY_TYPEf); 459 460 } 461 462 /* Get Destination/Source pair. */ 463 if (tnl_type.tnl_outer_hdr_ipv6 == 1) { 464 /* SIP [0-63] */ 465 soc_mem_ip6_addr_get(unit, mem, 466 (uint32 *)&entry->entry_arr[0], IP_ADDRf, 467 tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY); 468 /* SIP [64-127] */ 469 soc_mem_ip6_addr_get(unit, mem, 470 (uint32 *)&entry->entry_arr[1], IP_ADDRf, 471 tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY); 472 /* DIP [0-63] */ 473 soc_mem_ip6_addr_get(unit, mem, 474 (uint32 *)&entry->entry_arr[2], IP_ADDRf, 475 tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY); 476 /* DIP [64-127] */ 477 soc_mem_ip6_addr_get(unit, mem, 478 (uint32 *)&entry->entry_arr[3], IP_ADDRf, 479 tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY); 480 481 /* SIP MASK [0-63] */ 482 soc_mem_ip6_addr_get(unit, mem, 483 (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf, 484 tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY); 485 /* SIP MASK [64-127] */ 486 soc_mem_ip6_addr_get(unit, mem, 487 (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf, 488 tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY); 489 /* DIP MASK [0-63] */ 490 soc_mem_ip6_addr_get(unit, mem, 491 (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf, 492 tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY); 493 /* DIP MASK [64-127] */ 494 soc_mem_ip6_addr_get(unit, mem, 495 (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf, 496 tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY); 497 498 } else if (tnl_type.tnl_outer_hdr_ipv6 == 0) { 499 /* Get destination ip. */ 500 tnl_info->dip = soc_mem_field32_get(unit, mem, entry_ptr, DIPf); 501 502 /* Get source ip. */ 503 tnl_info->sip = soc_mem_field32_get(unit, mem, entry_ptr, SIPf); 504 505 /* Destination subnet mask. */ 506 tnl_info->dip_mask = BCM_XGS3_L3_IP4_FULL_MASK; 507 508 /* Source subnet mask. */ 509 tnl_info->sip_mask = soc_mem_field32_get(unit, mem, entry_ptr, 510 SIP_MASKf); 511 } 512 513 /* Get tunnel subtype. */ 514 tnl_type.tnl_sub_type = 515 soc_mem_field32_get(unit, mem, entry_ptr, SUB_TUNNEL_TYPEf); 516 517 /* Get UDP tunnel type. */ 518 if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) { 519 tnl_type.tnl_udp_type = 520 soc_mem_field32_get(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf); 521 } 522 523 /* Get tunnel type. */ 524 tnl_type.tnl_auto = 525 soc_mem_field32_get(unit, mem, entry_ptr, TUNNEL_TYPEf); 526 527 /* Copy DSCP from outer header flag. */ 528 if (soc_mem_field32_get(unit, mem, entry_ptr, USE_OUTER_HDR_DSCPf)) { 529 tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_DSCP; 530 } 531 /* Copy TTL from outer header flag. */ 532 if (soc_mem_field32_get(unit, mem, entry_ptr, USE_OUTER_HDR_TTLf)) { 533 tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_TTL; 534 } 535 /* Keep inner header DSCP flag. */ 536 if (soc_mem_field32_get(unit, mem, entry_ptr, 537 DONOT_CHANGE_INNER_HDR_DSCPf)) { 538 tnl_info->flags |= BCM_TUNNEL_TERM_KEEP_INNER_DSCP; 539 } 540 541 soc_mem_pbmp_field_get(unit, mem, entry_ptr, ALLOWED_PORT_BITMAPf, 542 &tnl_info->pbmp); 543 544 /* Tunnel or IPMC lookup vlan id */ 545 tnl_info->vlan = soc_mem_field32_get(unit, mem, entry_ptr, IINTFf); 546 547 /* Get trust dscp per tunnel */ 548 if (soc_mem_field32_get(unit, mem, entry_ptr, USE_OUTER_HDR_DSCPf)) { 549 tnl_info->flags |= BCM_TUNNEL_TERM_DSCP_TRUST; 550 } 551 552 /* Get Tunnel class id for VFP match */ 553 if(SOC_MEM_FIELD_VALID(unit, mem, TUNNEL_CLASS_IDf)) { 554 tnl_info->tunnel_class = soc_mem_field32_get(unit, mem, entry_ptr, 555 TUNNEL_CLASS_IDf); 556 } 557 558 /* Get the protocol field and make some decisions */ 559 tnl_type.tnl_protocol = soc_mem_field32_get(unit, mem, entry_ptr, 560 PROTOCOLf); 561 switch (tnl_type.tnl_protocol) { 562 case 0x2F: 563 tnl_type.tnl_gre = 1; 564 break; 565 case 0x67: 566 tnl_type.tnl_pim_sm = 1; 567 default: 568 break; 569 } 570 /* Get gre IPv4 payload allowed. */ 571 tnl_type.tnl_gre_v4_payload = 572 soc_mem_field32_get(unit, mem, entry_ptr, GRE_PAYLOAD_IPV4f); 573 574 /* Get gre IPv6 payload allowed. */ 575 tnl_type.tnl_gre_v6_payload = 576 soc_mem_field32_get(unit, mem, entry_ptr, GRE_PAYLOAD_IPV6f); 577 578 /* Get the L4 data */ 579 if (soc_mem_field_valid (unit, mem, L4_SRC_PORTf)) { 580 tnl_info->udp_src_port = soc_mem_field32_get(unit, mem, entry_ptr, 581 L4_SRC_PORTf); 582 } 583 if (soc_mem_field_valid (unit, mem, L4_DEST_PORTf)) { 584 tnl_info->udp_dst_port = soc_mem_field32_get(unit, mem, entry_ptr, 585 L4_DEST_PORTf); 586 } 587 /* Get the tunnel ID */ 588 if (SOC_MEM_FIELD_VALID(unit, mem, TUNNEL_IDf)) { 589 tunnel_id = soc_mem_field32_get(unit, mem, entry_ptr, TUNNEL_IDf); 590 if (tunnel_id) { 591 BCM_GPORT_TUNNEL_ID_SET(tnl_info->tunnel_id, tunnel_id); 592 tnl_info->flags |= BCM_TUNNEL_TERM_TUNNEL_WITH_ID; 593 } 594 } 595 596 /* Get tunnel type, sub_type and protocol. */ 597 BCM_IF_ERROR_RETURN 598 (_bcm_xgs3_l3_get_tnl_term_type(unit, tnl_info, &tnl_type)); 599 /* Get the remote port member */ 600 if (SOC_MEM_FIELD_VALID(unit, mem, REMOTE_TERM_GPPf)) { 601 remote_port = soc_mem_field32_get(unit, mem, entry_ptr, 602 REMOTE_TERM_GPPf); 603 mod = (remote_port >> 6) & 0x7F; 604 port = remote_port & 0x3F; 605 BCM_IF_ERROR_RETURN 606 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 607 mod, port, &mod_out, &port_out)); 608 BCM_GPORT_MODPORT_SET(tnl_info->remote_port, mod_out, port_out); 609 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_mod)); 610 if (mod != my_mod) { 611 if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 612 (tnl_info->type == bcmTunnelTypeWlanAcToAc) || 613 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) || 614 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 615 tnl_info->flags |= BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE; 616 } 617 } 618 } 619 /* Get IIF if l3 ingress mode is not set */ 620 if (!BCM_XGS3_L3_INGRESS_MODE_ISSET(unit) && 621 BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (tnl_info->vlan > BCM_VLAN_MAX)) { 622 _bcm_l3_ingress_intf_t iif; 623 sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t)); 624 iif.intf_id = tnl_info->vlan; 625 BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif)); 626 627 tnl_info->vrf = iif.vrf; 628 tnl_info->if_class = iif.if_class; 629 tnl_info->qos_map_id = iif.qos_map_id; 630 #ifdef BCM_TOMAHAWK_SUPPORT 631 if (SOC_IS_TOMAHAWKX(unit) && soc_feature(unit, soc_feature_ecn_wred)) { 632 if (bcmi_xgs5_ecn_map_used_get(unit, iif.tunnel_term_ecn_map_id, 633 _bcmEcnmapTypeTunnelTerm)) { 634 tnl_info->tunnel_term_ecn_map_id = iif.tunnel_term_ecn_map_id | 635 _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM; 636 tnl_info->flags |= BCM_TUNNEL_TERM_ECN_MAP; 637 } 638 } 639 #endif 640 } 641 #ifdef BCM_TRIDENT3_SUPPORT 642 if (SOC_MEM_FIELD_VALID(unit, mem, DEFAULT_VLAN_PROFILE_INDEXf)) { 643 int vlan_profile_idx = soc_mem_field32_get(unit, mem, entry_ptr, 644 DEFAULT_VLAN_PROFILE_INDEXf); 645 if (vlan_profile_idx) { 646 /* Get the forwarding VLAN ID */ 647 tunnel_default_vlan_profile_entry_t tunnel_default_vlan_profile_entry; 648 649 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, 650 MEM_BLOCK_ANY, vlan_profile_idx, 651 &tunnel_default_vlan_profile_entry)); 652 653 tnl_info->fwd_vlan = soc_mem_field32_get(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, 654 (uint32 *)&tunnel_default_vlan_profile_entry, OUTER_VLAN_TAGf); 655 } 656 } 657 #endif 658 659 return (BCM_E_NONE); 660 } 661 662 /* 663 * Function: 664 * _bcm_tr2_l3_ecmp_grp_get 665 * Purpose: 666 * Get ecmp group next hop members by index. 667 * Parameters: 668 * unit - (IN)SOC unit number. 669 * ecmp_grp - (IN)Ecmp group id to read. 670 * ecmp_count - (IN)Maximum number of entries to read. 671 * nh_idx - (OUT)Next hop indexes. 672 * Returns: 673 * BCM_E_XXX 674 */ 675 int 676 _bcm_tr2_l3_ecmp_grp_get(int unit, int ecmp_grp, int ecmp_group_size, int *nh_idx) 677 { 678 int idx; /* Iteration index. */ 679 int max_ent_count; /* Number of entries to read. */ 680 uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer to read hw entry. */ 681 int one_entry_grp = TRUE; /* Single next hop entry group. */ 682 int rv = BCM_E_UNAVAIL; /* Operation return status. */ 683 int ecmp_idx; 684 685 /* Input parameters sanity check. */ 686 if ((NULL == nh_idx) || (ecmp_group_size < 1)) { 687 return (BCM_E_PARAM); 688 } 689 690 /* Zero all next hop indexes first. */ 691 sal_memset(nh_idx, 0, ecmp_group_size * sizeof(int)); 692 sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 693 694 /* Get group base pointer. */ 695 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 696 MEM_BLOCK_ANY, ecmp_grp, hw_buf)); 697 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, BASE_PTRf); 698 699 /* Read zero based ecmp count. */ 700 rv = soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, ecmp_grp, hw_buf); 701 if (BCM_FAILURE(rv)) { 702 return rv; 703 } 704 705 max_ent_count = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, COUNTf); 706 max_ent_count++; /* Count is zero based. */ 707 708 /* Read all the indexes from hw. */ 709 for (idx = 0; idx < max_ent_count; idx++) { 710 711 /* Read next hop index. */ 712 rv = soc_mem_read(unit, L3_ECMPm, MEM_BLOCK_ANY, 713 (ecmp_idx + idx), hw_buf); 714 if (rv < 0) { 715 break; 716 } 717 nh_idx[idx] = soc_mem_field32_get(unit, L3_ECMPm, 718 hw_buf, NEXT_HOP_INDEXf); 719 /* Check if group contains . */ 720 if (idx && (nh_idx[idx] != nh_idx[0])) { 721 one_entry_grp = FALSE; 722 } 723 724 if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) { 725 /* Next hops popuplated in cycle,stop once you read first entry again */ 726 if (idx && (FALSE == one_entry_grp) && (nh_idx[idx] == nh_idx[0])) { 727 nh_idx[idx] = 0; 728 break; 729 } 730 } else { 731 one_entry_grp = FALSE; 732 } 733 } 734 /* Reset rest of the group if only 1 next hop is present. */ 735 if (one_entry_grp) { 736 sal_memset(nh_idx + 1, 0, (ecmp_group_size - 1) * sizeof(int)); 737 } 738 return rv; 739 } 740 741 /* 742 * Function: 743 * _bcm_tr2_l3_ecmp_grp_add 744 * Purpose: 745 * Add ecmp group next hop members, or reset ecmp group entry. 746 * NOTE: Function always writes all the entries in ecmp group. 747 * If there is not enough nh indexes - next hops written 748 * in cycle. 749 * Parameters: 750 * unit - (IN)SOC unit number. 751 * ecmp_grp - (IN)ecmp group id to write. 752 * buf - (IN)Next hop indexes or NULL for entry reset. 753 * info - (IN)ECMP additional info 754 * Returns: 755 * BCM_E_XXX 756 */ 757 int 758 _bcm_tr2_l3_ecmp_grp_add(int unit, int ecmp_grp, void *buf, void *info) 759 { 760 uint32 l3_ecmp[SOC_MAX_MEM_FIELD_WORDS]; /* l3_ecmp buf */ 761 uint32 l3_ecmp_count[SOC_MAX_MEM_FIELD_WORDS]; /* l3_ecmp_count buf */ 762 uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* l3_ecmp_count buf */ 763 int ecmp_idx; /* Ecmp table entry index. */ 764 int *nh_idx; /* Ecmp group nh indexes. */ 765 int nh_cycle_idx; 766 int entry_type; 767 uint32 reg_val, value; 768 ing_l3_next_hop_entry_t ing_nh; 769 _bcm_l3_tbl_op_t data; 770 int max_grp_size = 0; /* Maximum ecmp group size.*/ 771 int idx = 0; /* Iteration index. */ 772 int rv = BCM_E_UNAVAIL; /* Operation return value. */ 773 int l3_ecmp_oif_flds[8] = { L3_OIF_0f, 774 L3_OIF_1f, 775 L3_OIF_2f, 776 L3_OIF_3f, 777 L3_OIF_4f, 778 L3_OIF_5f, 779 L3_OIF_6f, 780 L3_OIF_7f }; 781 int l3_ecmp_oif_type_flds[8] = { L3_OIF_0_TYPEf, 782 L3_OIF_1_TYPEf, 783 L3_OIF_2_TYPEf, 784 L3_OIF_3_TYPEf, 785 L3_OIF_4_TYPEf, 786 L3_OIF_5_TYPEf, 787 L3_OIF_6_TYPEf, 788 L3_OIF_7_TYPEf }; 789 _bcm_l3_ecmp_group_info_t *ecmp_info = info; 790 _bcm_l3_ecmp_group_buffer_t *ecmp_buffer = buf; 791 792 /* Input parameters check. */ 793 if (NULL == ecmp_buffer || NULL == ecmp_info || 794 NULL == ecmp_buffer->group_buffer) { 795 return (BCM_E_PARAM); 796 } 797 798 /* Cast input buffer. */ 799 nh_idx = ecmp_buffer->group_buffer; 800 max_grp_size = ecmp_info->max_paths; 801 802 if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 803 ecmp_grp), ecmp_grp)) { 804 /* Group has already exists, get base ptr from group table */ 805 sal_memset (hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 806 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 807 MEM_BLOCK_ANY, ecmp_grp, hw_buf)); 808 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, BASE_PTRf); 809 } else { 810 /* Get index to the first slot in the ECMP table 811 * that can accomodate max_grp_size */ 812 data.width = ecmp_info->max_paths; 813 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 814 data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 815 data.entry_index = -1; 816 rv = _bcm_xgs3_tbl_free_idx_get(unit, &data); 817 if (BCM_FAILURE(rv)) { 818 if (rv == BCM_E_FULL) { 819 /* Defragment ECMP table */ 820 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0)); 821 822 /* Attempt to get free index again */ 823 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_free_idx_get(unit, &data)); 824 } else { 825 return rv; 826 } 827 } 828 ecmp_idx = data.entry_index; 829 BCM_XGS3_L3_ENT_REF_CNT_INC(data.tbl_ptr, data.entry_index, max_grp_size); 830 } 831 832 if (ecmp_idx >= BCM_XGS3_L3_ECMP_TBL_SIZE(unit)) { 833 return BCM_E_FULL; 834 } 835 836 sal_memset (hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 837 838 /* Write all the indexes to hw. */ 839 for (idx = 0, nh_cycle_idx = 0; idx < max_grp_size; idx++, nh_cycle_idx++) { 840 841 /* Set next hop index. */ 842 sal_memset (l3_ecmp, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 843 844 /* If this is the last nhop then program black-hole. */ 845 if ( (!idx) && (!nh_idx[nh_cycle_idx]) ) { 846 nh_cycle_idx = 0; 847 } else if (!nh_idx[nh_cycle_idx]) { 848 break; 849 } 850 851 soc_mem_field32_set(unit, L3_ECMPm, l3_ecmp, NEXT_HOP_INDEXf, 852 nh_idx[nh_cycle_idx]); 853 854 /* Write buffer to hw L3_ECMPm table. */ 855 rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 856 (ecmp_idx + idx), l3_ecmp); 857 if (BCM_FAILURE(rv)) { 858 break; 859 } 860 861 /* Write buffer to hw INITIAL_L3_ECMPm table. */ 862 rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 863 (ecmp_idx + idx), l3_ecmp); 864 if (BCM_FAILURE(rv)) { 865 break; 866 } 867 868 if (soc_feature(unit, soc_feature_urpf)) { 869 /* Check if URPF is enabled on device */ 870 BCM_IF_ERROR_RETURN( 871 READ_L3_DEFIP_RPF_CONTROLr(unit, ®_val)); 872 if (reg_val) { 873 if (idx < 8) { 874 BCM_IF_ERROR_RETURN (soc_mem_read(unit, 875 ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 876 nh_idx[idx], &ing_nh)); 877 878 entry_type = soc_ING_L3_NEXT_HOPm_field32_get(unit, 879 &ing_nh, ENTRY_TYPEf); 880 881 if (entry_type == 0x0) { 882 value = soc_ING_L3_NEXT_HOPm_field32_get(unit, 883 &ing_nh, VLAN_IDf); 884 if (soc_mem_field_valid(unit, 885 L3_ECMP_COUNTm, l3_ecmp_oif_type_flds[idx])) { 886 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 887 l3_ecmp_oif_type_flds[idx], entry_type); 888 } 889 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 890 l3_ecmp_oif_flds[idx], value); 891 } else if (entry_type == 0x1) { 892 value = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, L3_OIFf); 893 if (soc_mem_field_valid(unit, 894 L3_ECMP_COUNTm, l3_ecmp_oif_type_flds[idx])) { 895 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 896 l3_ecmp_oif_type_flds[idx], entry_type); 897 } 898 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 899 l3_ecmp_oif_flds[idx], value); 900 } 901 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, URPF_COUNTf, idx); 902 } else { 903 /* Inorder to avoid TRAP_TO_CPU, urpf_mode on L3_IIF/PORT must be set 904 * to STRICT_MODE / LOOSE_MODE */ 905 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, ECMP_GT8f , 1); 906 } 907 } 908 } 909 } 910 911 if (BCM_SUCCESS(rv)) { 912 /* mode 0 = 512 ecmp groups */ 913 if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 914 /* Set Max Group Size. */ 915 sal_memset (l3_ecmp_count, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 916 soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNTf, max_grp_size - 1); 917 918 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 919 (ecmp_grp+1), l3_ecmp_count); 920 BCM_IF_ERROR_RETURN(rv); 921 } 922 /* Set zero based ecmp count. */ 923 if (!idx) { 924 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, COUNTf, idx); 925 } else { 926 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, COUNTf, idx - 1); 927 } 928 929 /* Set group base pointer. */ 930 soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 931 BASE_PTRf, ecmp_idx); 932 933 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 934 ecmp_grp, hw_buf); 935 936 BCM_IF_ERROR_RETURN(rv); 937 938 rv = soc_mem_write(unit, INITIAL_L3_ECMP_COUNTm, 939 MEM_BLOCK_ALL, ecmp_grp, hw_buf); 940 /* mode 1 = max possible ecmp groups */ 941 if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 942 /* Save the max possible paths for this ECMP group in s/w */ 943 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = ecmp_info->max_paths; 944 } 945 } 946 return rv; 947 } 948 949 /* 950 * Function: 951 * _bcm_tr2_l3_ecmp_grp_del 952 * Purpose: 953 * Reset ecmp group next hop members 954 * Parameters: 955 * unit - (IN)SOC unit number. 956 * ecmp_grp - (IN)ecmp group id to write. 957 * info - (IN)ECMP additional info 958 * Returns: 959 * BCM_E_XXX 960 */ 961 int 962 _bcm_tr2_l3_ecmp_grp_del(int unit, int ecmp_grp, void *info) 963 { 964 uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer to write hw entry.*/ 965 ecmp_count_entry_t ecmp_count_entry; 966 int ecmp_idx; /* Ecmp table entry index. */ 967 int idx; /* Iteration index. */ 968 int rv = BCM_E_UNAVAIL; /* Operation return value. */ 969 _bcm_l3_tbl_op_t data; 970 data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 971 972 if (NULL == info) { 973 return BCM_E_INTERNAL; 974 } 975 976 /* Initialize ecmp entry. */ 977 sal_memset (hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 978 979 /* Calculate table index. */ 980 BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, 981 MEM_BLOCK_ANY, ecmp_grp, &ecmp_count_entry)); 982 ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_count_entry, 983 BASE_PTRf); 984 985 /* Write all the indexes to hw. */ 986 for (idx = 0; idx < ((_bcm_l3_ecmp_group_info_t*)info)->max_paths; idx++) { 987 /* Write buffer to hw. */ 988 rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 989 (ecmp_idx + idx), hw_buf); 990 991 if (BCM_FAILURE(rv)) { 992 return rv; 993 } 994 995 /* Write initial ecmp table. */ 996 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) { 997 /* Write buffer to hw. */ 998 rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 999 (ecmp_idx + idx), hw_buf); 1000 if (BCM_FAILURE(rv)) { 1001 return rv; 1002 } 1003 } 1004 } 1005 1006 /* Decrement ref count for the entries in ecmp table 1007 * Ref count for ecmp_group table is decremented in common table del func. */ 1008 BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, ecmp_idx, 1009 ((_bcm_l3_ecmp_group_info_t*)info)->max_paths); 1010 1011 /* Set group base pointer. */ 1012 ecmp_idx = ecmp_grp; 1013 1014 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 1015 ecmp_idx, hw_buf); 1016 BCM_IF_ERROR_RETURN(rv); 1017 1018 if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 1019 rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 1020 (ecmp_idx+1), hw_buf); 1021 BCM_IF_ERROR_RETURN(rv); 1022 } 1023 1024 rv = soc_mem_write(unit, INITIAL_L3_ECMP_COUNTm, MEM_BLOCK_ALL, 1025 ecmp_idx, hw_buf); 1026 1027 if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 1028 /* Reset the max paths of the deleted group */ 1029 BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = 0; 1030 } 1031 1032 return rv; 1033 } 1034 1035 /* 1036 * Function: 1037 * _bcm_tr2_l3_intf_urpf_default_route_set 1038 * Purpose: 1039 * Set urpf_default_route enable flag for the L3 interface. 1040 * Parameters: 1041 * unit - (IN)SOC unit number. 1042 * vid - (IN)Vlan id. 1043 * enable - (IN)Enable. 1044 * Returns: 1045 * BCM_E_XXX. 1046 */ 1047 int 1048 _bcm_tr2_l3_intf_urpf_default_route_set(int unit, bcm_vlan_t vid, int enable) 1049 { 1050 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 1051 int ret_val; /* Operation return value. */ 1052 1053 /* Input parameters sanity check. */ 1054 if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 1055 (vid < soc_mem_index_min(unit, L3_IIFm))) { 1056 return (BCM_E_PARAM); 1057 } 1058 1059 iif.intf_id = vid; 1060 soc_mem_lock(unit, L3_IIFm); 1061 1062 ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 1063 if (BCM_FAILURE(ret_val)) { 1064 soc_mem_unlock(unit, L3_IIFm); 1065 return (ret_val); 1066 } 1067 1068 if (enable) { 1069 iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 1070 } else { 1071 iif.flags &= ~BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK; 1072 } 1073 1074 ret_val = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL); 1075 1076 soc_mem_unlock(unit, L3_IIFm); 1077 1078 return (ret_val); 1079 } 1080 1081 /* 1082 * Function: 1083 * _bcm_tr2_l3_intf_urpf_default_route_get 1084 * Purpose: 1085 * Get the urpf_default_route_check enable flag for the specified L3 interface 1086 * Parameters: 1087 * unit - (IN)SOC unit number. 1088 * vid - (IN)Vlan id. 1089 * enable - (OUT)enable. 1090 * Returns: 1091 * BCM_E_XXX. 1092 */ 1093 int 1094 _bcm_tr2_l3_intf_urpf_default_route_get (int unit, bcm_vlan_t vid, int *enable) 1095 { 1096 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 1097 1098 /* Input parameters sanity check. */ 1099 if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 1100 (vid < soc_mem_index_min(unit, L3_IIFm))) { 1101 return (BCM_E_PARAM); 1102 } 1103 1104 iif.intf_id = vid; 1105 1106 BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif)); 1107 1108 *enable = (iif.flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) ? 1 : 0; 1109 return (BCM_E_NONE); 1110 } 1111 /* 1112 * Function: 1113 * _bcm_tr2_l3_intf_urpf_mode_set 1114 * Purpose: 1115 * Set the urpf_mode info for the specified L3 interface 1116 * Parameters: 1117 * unit - (IN)SOC unit number. 1118 * vid - (IN)Vlan id. 1119 * urpf_mode - (IN)urpf_mode. 1120 * Returns: 1121 * BCM_E_XXX. 1122 */ 1123 int 1124 _bcm_tr2_l3_intf_urpf_mode_set(int unit, bcm_vlan_t vid, bcm_vlan_urpf_mode_t urpf_mode) 1125 { 1126 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 1127 int ret_val; /* Operation return value. */ 1128 1129 /* Input parameters sanity check. */ 1130 if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 1131 (vid < soc_mem_index_min(unit, L3_IIFm))) { 1132 return (BCM_E_PARAM); 1133 } 1134 1135 iif.intf_id = vid; 1136 soc_mem_lock(unit, L3_IIFm); 1137 1138 ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif); 1139 if (BCM_FAILURE(ret_val)) { 1140 soc_mem_unlock(unit, L3_IIFm); 1141 return (ret_val); 1142 } 1143 1144 iif.urpf_mode = urpf_mode; 1145 1146 ret_val = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL); 1147 1148 soc_mem_unlock(unit, L3_IIFm); 1149 1150 return (ret_val); 1151 } 1152 1153 /* 1154 * Function: 1155 * _bcm_tr2_l3_intf_urpf_mode_get 1156 * Purpose: 1157 * Get the urpf_mode info for the specified L3 interface 1158 * Parameters: 1159 * unit - (IN)SOC unit number. 1160 * vid - (IN)Vlan id. 1161 * urpf_mode - (OUT) urpf_mode 1162 * Returns: 1163 * BCM_E_XXX. 1164 */ 1165 int 1166 _bcm_tr2_l3_intf_urpf_mode_get(int unit, bcm_vlan_t vid, bcm_vlan_urpf_mode_t *urpf_mode) 1167 { 1168 _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/ 1169 1170 /* Input parameters sanity check. */ 1171 if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 1172 (vid < soc_mem_index_min(unit, L3_IIFm))) { 1173 return (BCM_E_PARAM); 1174 } 1175 1176 iif.intf_id = vid; 1177 1178 BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif)); 1179 1180 *urpf_mode = iif.urpf_mode; 1181 return (BCM_E_NONE); 1182 } 1183 1184 /* 1185 * Function: 1186 * bcm_tr2_l3_ecmp_defragment_buffer_init 1187 * Purpose: 1188 * Initialize L3 ECMP table defragmentation buffer. 1189 * Parameters: 1190 * unit - (IN) SOC unit number. 1191 * Returns: 1192 * BCM_E_XXX. 1193 */ 1194 int 1195 bcm_tr2_l3_ecmp_defragment_buffer_init(int unit) 1196 { 1197 if (NULL == _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]) { 1198 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit] = 1199 sal_alloc(sizeof(_bcm_tr2_l3_ecmp_defragment_buffer_t), 1200 "l3 ecmp defragmentation buffer info"); 1201 if (NULL == _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]) { 1202 return BCM_E_MEMORY; 1203 } 1204 } 1205 sal_memset(_bcm_tr2_l3_ecmp_defragment_buffer_info[unit], 0, 1206 sizeof(_bcm_tr2_l3_ecmp_defragment_buffer_t)); 1207 1208 return BCM_E_NONE; 1209 } 1210 1211 /* 1212 * Function: 1213 * bcm_tr2_l3_ecmp_defragment_buffer_deinit 1214 * Purpose: 1215 * De-initialize L3 ECMP table defragmentation buffer. 1216 * Parameters: 1217 * unit - (IN) SOC unit number. 1218 * Returns: 1219 * None. 1220 */ 1221 void 1222 bcm_tr2_l3_ecmp_defragment_buffer_deinit(int unit) 1223 { 1224 if (NULL != _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]) { 1225 sal_free(_bcm_tr2_l3_ecmp_defragment_buffer_info[unit]); 1226 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit] = NULL; 1227 } 1228 } 1229 1230 /* 1231 * Function: 1232 * bcm_tr2_l3_ecmp_defragment_buffer_set 1233 * Purpose: 1234 * Set L3 ECMP table defragmentation buffer. 1235 * Parameters: 1236 * unit - (IN) SOC unit number. 1237 * size - (IN) Defragmentation buffer size. 1238 * Returns: 1239 * BCM_E_XXX. 1240 */ 1241 int 1242 bcm_tr2_l3_ecmp_defragment_buffer_set(int unit, int size) 1243 { 1244 _bcm_l3_tbl_t *tbl_ptr; 1245 int old_base_ptr, old_size; 1246 int base_ptr; 1247 int i, j; 1248 int buffer_found; 1249 1250 if (!soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) && 1251 !soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 1252 return BCM_E_UNAVAIL; 1253 } 1254 1255 L3_LOCK(unit); 1256 1257 tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 1258 1259 /* Free old defragmentation buffer */ 1260 old_base_ptr = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr; 1261 old_size = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size; 1262 if (old_size > 0) { 1263 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, old_base_ptr, old_size); 1264 } 1265 1266 /* Fist, attempt to find new defragmentation buffer at end of ECMP table. 1267 * Such a buffer introduces less fragmentation than a buffer that's 1268 * located in the middle of the ECMP table. 1269 */ 1270 for (i = tbl_ptr->idx_max + 1 - size; i < (tbl_ptr->idx_max + 1); i++) { 1271 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) { 1272 break; 1273 } 1274 } 1275 1276 if (i == (tbl_ptr->idx_max + 1)) { 1277 /* An available buffer is found at end of ECMP table */ 1278 base_ptr = tbl_ptr->idx_max + 1 - size; 1279 } else { 1280 /* Attempt to find new defragmentation buffer in ECMP table */ 1281 buffer_found = FALSE; 1282 for (i = tbl_ptr->idx_min; i < (tbl_ptr->idx_max + 1 - size); i++) { 1283 for (j = i; j < (i + size); j++) { 1284 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, j)) { 1285 break; 1286 } 1287 } 1288 if (j == (i + size)) { 1289 buffer_found = TRUE; 1290 break; 1291 } 1292 } 1293 1294 if (buffer_found) { 1295 base_ptr = i; 1296 } else { 1297 /* A free buffer of the requested size cannot be found. 1298 * Restore the old buffer. 1299 */ 1300 if (old_size > 0) { 1301 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, old_base_ptr, old_size); 1302 } 1303 1304 L3_UNLOCK(unit); 1305 return BCM_E_RESOURCE; 1306 } 1307 } 1308 1309 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, base_ptr, size); 1310 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr = base_ptr; 1311 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size = size; 1312 1313 L3_UNLOCK(unit); 1314 return BCM_E_NONE; 1315 } 1316 1317 /* 1318 * Function: 1319 * bcm_tr2_l3_ecmp_defragment_buffer_get 1320 * Purpose: 1321 * Get L3 ECMP table defragmentation buffer size. 1322 * Parameters: 1323 * unit - (IN) SOC unit number. 1324 * size - (OUT) Defragmentation buffer size. 1325 * Returns: 1326 * BCM_E_XXX. 1327 */ 1328 int 1329 bcm_tr2_l3_ecmp_defragment_buffer_get(int unit, int *size) 1330 { 1331 if (!soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) && 1332 !soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 1333 return BCM_E_UNAVAIL; 1334 } 1335 1336 (*size) = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size; 1337 1338 return BCM_E_NONE; 1339 } 1340 1341 /* 1342 * Function: 1343 * _bcm_tr2_l3_ecmp_member_copy 1344 * Purpose: 1345 * Copy ECMP table entry. 1346 * Parameters: 1347 * unit - (IN) SOC unit number. 1348 * src_index - (IN) Index of the entry to be copied. 1349 * dst_index - (IN) Destination index. 1350 * Returns: 1351 * BCM_E_XXX. 1352 */ 1353 int 1354 _bcm_tr2_l3_ecmp_member_copy(int unit, int src_index, int dst_index) 1355 { 1356 ecmp_entry_t ecmp_entry; 1357 initial_l3_ecmp_entry_t initial_ecmp_entry; 1358 1359 if (src_index < 0 || src_index > soc_mem_index_max(unit, L3_ECMPm)) { 1360 return BCM_E_PARAM; 1361 } 1362 if (dst_index < 0 || dst_index > soc_mem_index_max(unit, L3_ECMPm)) { 1363 return BCM_E_PARAM; 1364 } 1365 1366 SOC_IF_ERROR_RETURN 1367 (READ_L3_ECMPm(unit, MEM_BLOCK_ANY, src_index, &ecmp_entry)); 1368 SOC_IF_ERROR_RETURN 1369 (WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL, dst_index, &ecmp_entry)); 1370 1371 if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) { 1372 SOC_IF_ERROR_RETURN 1373 (READ_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ANY, src_index, 1374 &initial_ecmp_entry)); 1375 SOC_IF_ERROR_RETURN 1376 (WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL, dst_index, 1377 &initial_ecmp_entry)); 1378 } 1379 /* Increment reference count for ECMP table entry at dst_index */ 1380 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), dst_index, 1); 1381 1382 return BCM_E_NONE; 1383 } 1384 1385 /* 1386 * Function: 1387 * _bcm_tr2_l3_ecmp_member_clear 1388 * Purpose: 1389 * Clear an ECMP table entry. 1390 * Parameters: 1391 * unit - (IN) SOC unit number. 1392 * index - (IN) Index of the entry to be cleared. 1393 * Returns: 1394 * BCM_E_XXX. 1395 */ 1396 int 1397 _bcm_tr2_l3_ecmp_member_clear(int unit, int index) 1398 { 1399 if (index < 0 || index > soc_mem_index_max(unit, L3_ECMPm)) { 1400 return BCM_E_PARAM; 1401 } 1402 1403 SOC_IF_ERROR_RETURN(WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL, index, 1404 soc_mem_entry_null(unit, L3_ECMPm))); 1405 if (!soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) { 1406 SOC_IF_ERROR_RETURN(WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL, index, 1407 soc_mem_entry_null(unit, INITIAL_L3_ECMPm))); 1408 } 1409 1410 /* Decrement reference count for the just cleared ECMP table entry */ 1411 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), index, 1); 1412 1413 return BCM_E_NONE; 1414 } 1415 1416 /* 1417 * Function: 1418 * _bcm_tr2_l3_ecmp_group_base_ptr_update 1419 * Purpose: 1420 * Update the base pointer field of the given ECMP group. 1421 * Parameters: 1422 * unit - (IN) SOC unit number. 1423 * group - (IN) ECMP group. 1424 * base_ptr - (IN) New base pointer. 1425 * Returns: 1426 * BCM_E_XXX. 1427 */ 1428 int 1429 _bcm_tr2_l3_ecmp_group_base_ptr_update(int unit, int group, int base_ptr) 1430 { 1431 ecmp_count_entry_t ecmp_group_entry; 1432 uint32 initial_ecmp_group_entry[SOC_MAX_MEM_FIELD_WORDS]; 1433 soc_mem_t initial_ecmp_group_mem; 1434 soc_field_t base_ptr_f = INVALIDf; 1435 1436 if (group < 0 || group > soc_mem_index_max(unit, L3_ECMP_COUNTm)) { 1437 return BCM_E_PARAM; 1438 } 1439 1440 /* Read L3 ECMP group table */ 1441 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, group, 1442 &ecmp_group_entry)); 1443 1444 /* Choose correct base pointer field */ 1445 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 1446 uint32 ing_config_2; 1447 uint8 ecmp_hash_16bits = 1; 1448 if (SOC_REG_IS_VALID(unit, ING_CONFIG_2r)) { 1449 SOC_IF_ERROR_RETURN( 1450 READ_ING_CONFIG_2r(unit, &ing_config_2)); 1451 ecmp_hash_16bits = 1452 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 1453 ECMP_HASH_16BITSf); 1454 } 1455 1456 if (ecmp_hash_16bits && 1457 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf)) { 1458 base_ptr_f = BASE_PTRf; 1459 } else if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 1460 base_ptr_f = BASE_PTR_0f; 1461 } 1462 } else if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 1463 base_ptr_f = BASE_PTR_0f; 1464 } else { 1465 base_ptr_f = BASE_PTRf; 1466 } 1467 1468 /* Modify base pointer */ 1469 if (base_ptr_f == BASE_PTRf) { 1470 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, 1471 BASE_PTRf, base_ptr); 1472 } else { 1473 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, 1474 BASE_PTR_0f, base_ptr); 1475 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, 1476 BASE_PTR_1f, base_ptr); 1477 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, 1478 BASE_PTR_2f, base_ptr); 1479 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, 1480 BASE_PTR_3f, base_ptr); 1481 } 1482 1483 /* Write L3 ECMP group table */ 1484 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, group, 1485 &ecmp_group_entry)); 1486 1487 #ifdef BCM_TOMAHAWK3_SUPPORT 1488 if (soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) { 1489 return BCM_E_NONE; 1490 } 1491 #endif 1492 1493 /* Read Initial L3 ECMP group table */ 1494 if (soc_mem_is_valid(unit, INITIAL_L3_ECMP_COUNTm)) { 1495 initial_ecmp_group_mem = INITIAL_L3_ECMP_COUNTm; 1496 } else if (soc_mem_is_valid(unit, INITIAL_L3_ECMP_GROUPm)) { 1497 initial_ecmp_group_mem = INITIAL_L3_ECMP_GROUPm; 1498 } else { 1499 return BCM_E_INTERNAL; 1500 } 1501 SOC_IF_ERROR_RETURN(soc_mem_read(unit, initial_ecmp_group_mem, 1502 MEM_BLOCK_ANY, group, &initial_ecmp_group_entry)); 1503 1504 /* Modify base pointer */ 1505 if (base_ptr_f == BASE_PTRf) { 1506 soc_mem_field32_set(unit, initial_ecmp_group_mem, 1507 &initial_ecmp_group_entry, BASE_PTRf, base_ptr); 1508 } else { 1509 soc_mem_field32_set(unit, initial_ecmp_group_mem, 1510 &initial_ecmp_group_entry, BASE_PTR_0f, base_ptr); 1511 soc_mem_field32_set(unit, initial_ecmp_group_mem, 1512 &initial_ecmp_group_entry, BASE_PTR_1f, base_ptr); 1513 soc_mem_field32_set(unit, initial_ecmp_group_mem, 1514 &initial_ecmp_group_entry, BASE_PTR_2f, base_ptr); 1515 soc_mem_field32_set(unit, initial_ecmp_group_mem, 1516 &initial_ecmp_group_entry, BASE_PTR_3f, base_ptr); 1517 } 1518 1519 /* Write Initial L3 ECMP group table */ 1520 SOC_IF_ERROR_RETURN(soc_mem_write(unit, initial_ecmp_group_mem, 1521 MEM_BLOCK_ALL, group, &initial_ecmp_group_entry)); 1522 1523 return BCM_E_NONE; 1524 } 1525 1526 /* 1527 * Function: 1528 * bcm_tr2_l3_ecmp_defragment_no_lock 1529 * Purpose: 1530 * Defragment L3 ECMP table. This procedure does not obtain 1531 * L3 lock. It's assumed that L3 lock was obtained before 1532 * invoking this procedure. 1533 * Parameters: 1534 * unit - (IN) SOC unit number. 1535 * ecmp_level - (IN) Ecmp Level 1536 * Default value is 0, entire ECMP table is de-fragmented 1537 * ecmp_level 1 and 2 is applicable to Hierarchical Ecmp feature, 1538 * only level 1 or level 2 Ecmp table is defragmented 1539 * Returns: 1540 * BCM_E_XXX. 1541 */ 1542 int 1543 bcm_tr2_l3_ecmp_defragment_no_lock(int unit, int ecmp_level) 1544 { 1545 _bcm_l3_tbl_t *ecmp_group_tbl_ptr; 1546 soc_defragment_block_t *block_array; 1547 soc_defragment_block_t reserved_block; 1548 soc_defragment_member_op_t member_op; 1549 soc_defragment_group_op_t group_op; 1550 int block_count; 1551 int i, ecmp_group_idx_increment; 1552 int rv; 1553 int max_paths; 1554 soc_field_t base_ptr_f; 1555 int base_ptr = 0; 1556 ecmp_count_entry_t ecmp_group_entry; 1557 int min_idx = 0; 1558 int max_idx = 0; 1559 int ecmp_tbl_size = 0; 1560 int free_base_ptr = 0; 1561 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_RIOT_SUPPORT) || \ 1562 defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1563 int vp_lag_base_idx = 0; 1564 #endif 1565 #if defined(BCM_TOMAHAWK_SUPPORT) 1566 int hecmp_enable = 0; 1567 int ecmp_min_idx = 0; 1568 int ecmp_max_idx = 0; 1569 #endif 1570 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1571 _bcm_l3_tbl_t *ecmp_tbl_ptr; 1572 #endif 1573 1574 if (!soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) && 1575 !soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 1576 return BCM_E_UNAVAIL; 1577 } 1578 1579 #if defined(BCM_TOMAHAWK_SUPPORT) 1580 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 1581 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical)) { 1582 hecmp_enable = 1; 1583 } 1584 #endif 1585 1586 ecmp_group_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 1587 1588 if (ecmp_level == 1) { 1589 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1590 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 1591 block_array = sal_alloc(sizeof(soc_defragment_block_t) * 1592 (ecmp_group_tbl_ptr->idx_maxused - 1593 ecmp_group_tbl_ptr->split_idx + 1), 1594 "defragment block array"); 1595 } else 1596 #endif 1597 { 1598 /* 1599 * Allocate block array of size equal to size of overlay table 1600 * since we do not keep track of the highest used index at Level 1 1601 */ 1602 block_array = sal_alloc(sizeof(soc_defragment_block_t) * 1603 (ecmp_group_tbl_ptr->idx_max + 1), "defragment block array"); 1604 } 1605 } else if (ecmp_level == 2) { 1606 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1607 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 1608 block_array = sal_alloc(sizeof(soc_defragment_block_t) * 1609 (ecmp_group_tbl_ptr->split_maxused + 1), 1610 "defragment block array"); 1611 } else 1612 #endif 1613 #if defined(BCM_TOMAHAWK_SUPPORT) 1614 if (hecmp_enable) { 1615 block_array = sal_alloc(sizeof(soc_defragment_block_t) * 1616 (ecmp_group_tbl_ptr->idx_maxused + 1), 1617 "defragment block array"); 1618 } else 1619 #endif /* BCM_TOMAHAWK_SUPPORT */ 1620 { 1621 /* Allocate block array of size equal to number of used entries at level 2 */ 1622 block_array = sal_alloc(sizeof(soc_defragment_block_t) * 1623 (ecmp_group_tbl_ptr->idx_maxused - 1624 ecmp_group_tbl_ptr->idx_min + 1), 1625 "defragment block array"); 1626 } 1627 } else { 1628 block_array = sal_alloc(sizeof(soc_defragment_block_t) * 1629 (ecmp_group_tbl_ptr->idx_maxused + 1), "defragment block array"); 1630 } 1631 1632 /* Get the ECMP table base_ptr and max group size of all the active 1633 * ECMP groups 1634 */ 1635 block_count = 0; 1636 if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 1637 ecmp_group_idx_increment = _BCM_SINGLE_WIDE; 1638 } else { 1639 ecmp_group_idx_increment = _BCM_DOUBLE_WIDE; 1640 } 1641 1642 if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) { 1643 uint32 ing_config_2; 1644 uint8 ecmp_hash_16bits = 1; 1645 if (SOC_REG_IS_VALID(unit, ING_CONFIG_2r)) { 1646 rv = READ_ING_CONFIG_2r(unit, &ing_config_2); 1647 if (SOC_FAILURE(rv)) { 1648 sal_free(block_array); 1649 return rv; 1650 } 1651 ecmp_hash_16bits = 1652 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2, 1653 ECMP_HASH_16BITSf); 1654 } 1655 1656 if (ecmp_hash_16bits && 1657 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf)) { 1658 base_ptr_f = BASE_PTRf; 1659 } else { 1660 base_ptr_f = BASE_PTR_0f; 1661 } 1662 } else if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) { 1663 base_ptr_f = BASE_PTR_0f; 1664 } else { 1665 base_ptr_f = BASE_PTRf; 1666 } 1667 1668 if (ecmp_level == 2) { 1669 min_idx = ecmp_group_tbl_ptr->idx_min; 1670 max_idx = ecmp_group_tbl_ptr->idx_maxused; 1671 free_base_ptr = min_idx; 1672 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1673 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 1674 max_idx = ecmp_group_tbl_ptr->split_maxused; 1675 } else 1676 #endif 1677 #if defined(BCM_TOMAHAWK_SUPPORT) 1678 if (hecmp_enable) { 1679 min_idx = soc_mem_index_min(unit, L3_ECMP_COUNTm); 1680 max_idx = ecmp_group_tbl_ptr->idx_maxused; 1681 ecmp_min_idx = soc_mem_index_count(unit, L3_ECMPm)/2; 1682 ecmp_max_idx = soc_mem_index_count(unit, L3_ECMPm); 1683 free_base_ptr = ecmp_min_idx; 1684 } else 1685 #endif /* BCM_TOMAHAWK_SUPPORT */ 1686 { 1687 free_base_ptr = soc_mem_index_count(unit, L3_ECMPm)/2; 1688 } 1689 ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm)/2; 1690 } else if (ecmp_level == 1) { 1691 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1692 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 1693 min_idx = ecmp_group_tbl_ptr->split_idx; 1694 max_idx = ecmp_group_tbl_ptr->idx_maxused; 1695 ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm); 1696 if (soc_feature(unit, soc_feature_td3_style_riot)) { 1697 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 1698 free_base_ptr = ecmp_tbl_ptr->split_idx; 1699 } else { 1700 free_base_ptr = soc_mem_index_count(unit, L3_ECMPm)/2; 1701 } 1702 vp_lag_base_idx = min_idx; 1703 } else 1704 #endif 1705 #if defined(BCM_TOMAHAWK_SUPPORT) 1706 if (hecmp_enable) { 1707 min_idx = ecmp_group_tbl_ptr->idx_min; 1708 max_idx = ecmp_group_tbl_ptr->idx_max; 1709 ecmp_min_idx = 0; 1710 ecmp_max_idx = soc_mem_index_max(unit, L3_ECMPm)/2; 1711 free_base_ptr = ecmp_min_idx; 1712 ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm)/2; 1713 } else 1714 #endif /* BCM_TOMAHAWK_SUPPORT */ 1715 { 1716 min_idx = ecmp_group_tbl_ptr->idx_min; 1717 /* 1718 * Using table max index since we do not keep track of highest 1719 * index used at this level 1 1720 */ 1721 max_idx = ecmp_group_tbl_ptr->idx_max; 1722 free_base_ptr = 0; 1723 ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm)/2; 1724 } 1725 } else { 1726 min_idx = ecmp_group_tbl_ptr->idx_min; 1727 max_idx = ecmp_group_tbl_ptr->idx_maxused; 1728 ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm); 1729 free_base_ptr = 0; 1730 } 1731 1732 for (i = min_idx; i <= max_idx; i += ecmp_group_idx_increment) { 1733 1734 #ifdef BCM_TRIDENT2_SUPPORT 1735 /* Skip vp_lag checks at level 2 as vp lag entries are only at level 1 */ 1736 if (soc_feature(unit, soc_feature_vp_lag) && (ecmp_level != 2)) { 1737 int is_vp_lag, is_used, has_member; 1738 rv = bcm_td2_vp_lag_status_get(unit, i - vp_lag_base_idx, 1739 &is_vp_lag, &is_used, &has_member); 1740 if (BCM_FAILURE(rv)) { 1741 sal_free(block_array); 1742 return rv; 1743 } 1744 if (is_vp_lag) { 1745 /* Skip VP LAG entries */ 1746 continue; 1747 } 1748 } 1749 #endif /* BCM_TRIDENT2_SUPPORT */ 1750 1751 if (!BCM_XGS3_L3_ENT_REF_CNT(ecmp_group_tbl_ptr, i)) { 1752 continue; 1753 } 1754 1755 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, i, &ecmp_group_entry); 1756 if (SOC_FAILURE(rv)) { 1757 sal_free(block_array); 1758 return rv; 1759 } 1760 base_ptr = 1761 soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, base_ptr_f); 1762 rv = bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, 1763 i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), NULL, &max_paths); 1764 if (BCM_FAILURE(rv)) { 1765 sal_free(block_array); 1766 return rv; 1767 } 1768 1769 #if defined(BCM_TOMAHAWK_SUPPORT) 1770 /* In HECMP mode, there are 3 kinds of ECMP_GROUP, and they can be 1771 * coexisted, so we need to handle mixed ecmp group case; 1772 * ecmp_group_flags: 1773 * 0 : ecmp_index [0 ~ 16K-1] nh-hop 1774 * OVERLAY : ecmp_index [0 ~ 8K-1] ecmp_grp_ptr, Level 1 1775 * UNDERLAY: ecmp_index [8K ~ 16K-1] nh-hop 1776 * ecmp_index range between [8K ~ 16K-1] can't be ecmp_grp_ptr. 1777 * 1778 * So for a given ecmp_index in range [8K ~ 16K-1], the ecmp can 1779 * be either level 1 group or level 2 group. 1780 */ 1781 if (hecmp_enable) { 1782 /* Adjust free_base_ptr when group member across the boundaries */ 1783 if (ecmp_min_idx > 0 && 1784 base_ptr < ecmp_min_idx && 1785 (base_ptr + max_paths) > ecmp_min_idx) { 1786 free_base_ptr = (base_ptr + max_paths); 1787 continue; 1788 } 1789 1790 /* Ignore out of range groups */ 1791 if (base_ptr < ecmp_min_idx || base_ptr > ecmp_max_idx) { 1792 continue; 1793 } 1794 1795 if ((base_ptr + max_paths) > ecmp_max_idx) { 1796 continue; 1797 } 1798 } 1799 #endif 1800 1801 block_array[block_count].base_ptr = base_ptr; 1802 block_array[block_count].size = max_paths; 1803 block_array[block_count].group = i; 1804 block_count++; 1805 } 1806 1807 #ifdef BCM_TRIDENT2_SUPPORT 1808 /* In Trident2, the VP LAG and ECMP features share the same group and 1809 * member tables. Defragmentation of the member table also requires 1810 * the group base_ptr and group size of all the active VP LAGs. 1811 */ 1812 if (soc_feature(unit, soc_feature_vp_lag)) { 1813 int vp_id_min = -1, vp_id_max = -1; 1814 int min_vp_lag_id, max_vp_lag_id; 1815 int is_vp_lag, is_used, has_member; 1816 1817 rv = _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min, 1818 &vp_id_max, NULL); 1819 if (BCM_FAILURE(rv)) { 1820 sal_free(block_array); 1821 return rv; 1822 } 1823 if (vp_id_min != -1 && vp_id_max != -1) { 1824 min_vp_lag_id = 0; 1825 max_vp_lag_id = vp_id_max - vp_id_min; 1826 for (i = min_vp_lag_id; i <= max_vp_lag_id; i++) { 1827 rv = bcm_td2_vp_lag_status_get(unit, i, &is_vp_lag, &is_used, 1828 &has_member); 1829 if (BCM_FAILURE(rv)) { 1830 sal_free(block_array); 1831 return rv; 1832 } 1833 if (!is_vp_lag) { 1834 sal_free(block_array); 1835 return BCM_E_INTERNAL; 1836 } 1837 if (!is_used) { 1838 continue; 1839 } 1840 if (!has_member) { 1841 continue; 1842 } 1843 1844 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, i + vp_lag_base_idx, 1845 &ecmp_group_entry); 1846 if (SOC_FAILURE(rv)) { 1847 sal_free(block_array); 1848 return rv; 1849 } 1850 block_array[block_count].base_ptr = 1851 soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 1852 BASE_PTRf); 1853 block_array[block_count].size = 1 + 1854 soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, 1855 COUNTf); 1856 block_array[block_count].group = i + vp_lag_base_idx; 1857 block_count++; 1858 } 1859 } 1860 } 1861 #endif /* BCM_TRIDENT2_SUPPORT */ 1862 1863 /* Get the defragmentation buffer base_ptr and size */ 1864 reserved_block.base_ptr = 1865 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr; 1866 reserved_block.size = 1867 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size; 1868 reserved_block.group = -1; 1869 1870 /* Set functions to copy and clear ECMP member entries */ 1871 member_op.member_copy = _bcm_tr2_l3_ecmp_member_copy; 1872 member_op.member_clear = _bcm_tr2_l3_ecmp_member_clear; 1873 1874 /* Set function to update ECMP group's base_ptr */ 1875 group_op.group_base_ptr_update = _bcm_tr2_l3_ecmp_group_base_ptr_update; 1876 1877 /* Call defragmentation routine */ 1878 rv = soc_defragment(unit, block_count, block_array, &reserved_block, 1879 ecmp_tbl_size, &member_op, &group_op, free_base_ptr); 1880 if (SOC_FAILURE(rv)) { 1881 sal_free(block_array); 1882 return rv; 1883 } 1884 1885 sal_free(block_array); 1886 return BCM_E_NONE; 1887 } 1888 1889 /* 1890 * Function: 1891 * bcm_tr2_l3_ecmp_defragment 1892 * Purpose: 1893 * Defragment L3 ECMP table. 1894 * Parameters: 1895 * unit - (IN) SOC unit number. 1896 * Returns: 1897 * BCM_E_XXX. 1898 */ 1899 int 1900 bcm_tr2_l3_ecmp_defragment(int unit) 1901 { 1902 int rv; 1903 1904 L3_LOCK(unit); 1905 1906 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 1907 if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) { 1908 rv = bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2); 1909 1910 if (BCM_FAILURE(rv)){ 1911 L3_UNLOCK(unit); 1912 return rv; 1913 } 1914 rv = bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1); 1915 if (BCM_FAILURE(rv)){ 1916 L3_UNLOCK(unit); 1917 return rv; 1918 } 1919 1920 } else 1921 #endif 1922 { 1923 rv = bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0); 1924 } 1925 1926 L3_UNLOCK(unit); 1927 1928 return rv; 1929 } 1930 1931 #ifdef BCM_WARM_BOOT_SUPPORT 1932 1933 /* 1934 * Function: 1935 * bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get 1936 * Purpose: 1937 * Get level 2 warm boot scache size for ECMP defragmentation 1938 * buffer parameters. 1939 * Parameters: 1940 * unit - (IN) SOC unit number. 1941 * size - (OUT) Allocation size. 1942 * Returns: 1943 * BCM_E_XXX 1944 */ 1945 int 1946 bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get(int unit, int *size) 1947 { 1948 *size = 0; 1949 1950 /* Allocate for buffer base_ptr */ 1951 *size += sizeof(int); 1952 1953 /* Allocate for buffer size */ 1954 *size += sizeof(int); 1955 1956 return BCM_E_NONE; 1957 } 1958 1959 /* 1960 * Function: 1961 * bcm_tr2_l3_ecmp_defragment_buffer_sync 1962 * Purpose: 1963 * Store ECMP defragmentation buffer parameters into scache. 1964 * Parameters: 1965 * unit - (IN) SOC unit number. 1966 * scache_ptr - (IN/OUT) Scache pointer 1967 * Returns: 1968 * BCM_E_XXX 1969 */ 1970 int 1971 bcm_tr2_l3_ecmp_defragment_buffer_sync(int unit, uint8 **scache_ptr) 1972 { 1973 int value; 1974 1975 /* Store buffer base_ptr */ 1976 value = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr; 1977 sal_memcpy((*scache_ptr), &value, sizeof(int)); 1978 (*scache_ptr) += sizeof(int); 1979 1980 /* Store buffer base_ptr */ 1981 value = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size; 1982 sal_memcpy((*scache_ptr), &value, sizeof(int)); 1983 (*scache_ptr) += sizeof(int); 1984 1985 return BCM_E_NONE; 1986 } 1987 1988 /* 1989 * Function: 1990 * bcm_tr2_l3_ecmp_defragment_buffer_recover 1991 * Purpose: 1992 * Recover ECMP defragment buffer parameters from scache. 1993 * Parameters: 1994 * unit - (IN) SOC unit number. 1995 * scache_ptr - (IN/OUT) Scache pointer 1996 * Returns: 1997 * BCM_E_XXX 1998 */ 1999 int 2000 bcm_tr2_l3_ecmp_defragment_buffer_recover(int unit, uint8 **scache_ptr) 2001 { 2002 int value; 2003 2004 /* Recover defragmentation buffer base_ptr */ 2005 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 2006 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr = value; 2007 (*scache_ptr) += sizeof(int); 2008 2009 /* Recover defragmentation buffer size */ 2010 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 2011 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size = value; 2012 (*scache_ptr) += sizeof(int); 2013 2014 return BCM_E_NONE; 2015 } 2016 2017 #endif /* BCM_WARM_BOOT_SUPPORT */ 2018 2019 #ifndef BCM_SW_STATE_DUMP_DISABLE 2020 /* 2021 * Function: 2022 * bcm_tr2_l3_ecmp_defragment_buffer_sw_dump 2023 * Purpose: 2024 * Displays ECMP defragmentation buffer information maintained by software. 2025 * Parameters: 2026 * unit - Device unit number 2027 * Returns: 2028 * None 2029 */ 2030 void 2031 bcm_tr2_l3_ecmp_defragment_buffer_sw_dump(int unit) 2032 { 2033 LOG_CLI((BSL_META_U(unit, 2034 " ECMP Defragment Buffer: base_ptr = %d, size = %d\n"), 2035 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr, 2036 _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size)); 2037 return; 2038 } 2039 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 2040 2041 #else /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */ 2042 int bcm_esw_triumph2_l3_not_empty; 2043 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */ 2044