l3_th.c (124204B)
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 14 #if defined(INCLUDE_L3) && defined(ALPM_ENABLE) 15 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) 16 17 #include <soc/drv.h> 18 #include <bcm/vlan.h> 19 #include <bcm/error.h> 20 21 #include <bcm/l3.h> 22 #include <soc/l3x.h> 23 #include <soc/lpm.h> 24 25 #include <soc/alpm.h> 26 #include <soc/esw/alpm_int.h> 27 28 #include <soc/tomahawk.h> 29 #include <bcm/tunnel.h> 30 #include <bcm/debug.h> 31 #include <bcm/error.h> 32 #include <bcm/stack.h> 33 #include <soc/trident2.h> 34 35 #include <bcm_int/esw/tomahawk.h> 36 #include <bcm_int/esw/trident2.h> 37 #include <bcm_int/esw/firebolt.h> 38 #include <bcm_int/esw/triumph.h> 39 #include <bcm_int/esw/triumph2.h> 40 #include <bcm_int/esw/stack.h> 41 #include <bcm_int/esw/flex_ctr.h> 42 #include <bcm_int/esw_dispatch.h> 43 #include <bcm_int/esw/flex_ctr.h> 44 #include <bcm_int/esw/virtual.h> 45 #include <bcm_int/esw/qos.h> 46 47 #if defined(BCM_TRX_SUPPORT) 48 #include <bcm_int/esw/trx.h> 49 #endif /* BCM_TRX_SUPPORT */ 50 51 extern int l3_alpm_ipv4_double_wide[SOC_MAX_NUM_DEVICES]; 52 53 /* 54 * Function: 55 * _bcm_th_alpm_lpm_vrf_init 56 * Purpose: 57 * Service routine used to translate API vrf id to hw specific. 58 * Parameters: 59 * unit - (IN)SOC unit number. 60 * lpm_cfg - (IN)Prefix info. 61 * vrf_id - (OUT)Internal vrf id. 62 * vrf_mask - (OUT)Internal vrf mask. 63 * Returns: 64 * BCM_E_XXX 65 */ 66 STATIC int 67 _bcm_th_alpm_lpm_vrf_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 68 int *vrf_id, int *vrf_mask) 69 { 70 /* Handle special vrf id cases. */ 71 switch (lpm_cfg->defip_vrf) { 72 case BCM_L3_VRF_OVERRIDE: 73 case BCM_L3_VRF_GLOBAL: /* only for td2 */ 74 *vrf_id = 0; 75 *vrf_mask = 0; 76 break; 77 default: 78 *vrf_id = lpm_cfg->defip_vrf; 79 *vrf_mask = SOC_VRF_MAX(unit); 80 break; 81 } 82 83 /* In any case vrf id shouldn't exceed max field mask. */ 84 if ((*vrf_id < 0) || (*vrf_id > SOC_VRF_MAX(unit))) { 85 return (BCM_E_PARAM); 86 } 87 return (BCM_E_NONE); 88 } 89 90 /* 91 * Function: 92 * _bcm_th_alpm_lpm64_key_init 93 * Purpose: 94 * Set an IP6 address field in L3_DEFIPm 95 * Parameters: 96 * unit - (IN) SOC unit number; 97 * lpm_key - (OUT) Buffer to fill. 98 * lpm_cfg - (IN) Route information. 99 * alpm_entry - (OUT) ALPM entry to fill 100 * Note: 101 * See soc_mem_ip6_addr_set() 102 */ 103 STATIC void 104 _bcm_th_alpm_lpm64_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 105 defip_entry_t *lpm_key) 106 { 107 bcm_ip6_t mask; /* Subnet mask. */ 108 uint8 *ip6; /* Ip6 address. */ 109 uint32 ip6_word[2]; /* Temp storage. */ 110 int idx; /* Iteration index . */ 111 112 /* Just to keep variable name short. */ 113 ip6 = lpm_cfg->defip_ip6_addr; 114 115 /* Create mask from prefix length. */ 116 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 117 118 /* Apply subnet mask */ 119 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 120 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 121 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 122 ip6[idx] = 0; /* Reset rest of bytes. */ 123 } 124 125 ip6_word[1] = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 126 ip6_word[0]= ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 127 128 /* Set IP Addr */ 129 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word[1]); 130 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word[0]); 131 132 /* Set IP MASK */ 133 ip6_word[0] = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3])); 134 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f, (void *)&ip6_word[0]); 135 136 ip6_word[0] = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7])); 137 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f, (void *)&ip6_word[0]); 138 } 139 140 141 /* 142 * Function: 143 * _bcm_th_alpm_lpm_init 144 * Purpose: 145 * Service routine used to initialize lkup key for lpm entry. 146 * Also initializes the ALPM SRAM entry. 147 * Parameters: 148 * unit - (IN)SOC unit number. 149 * lpm_cfg - (IN)Prefix info. 150 * lpm_entry - (OUT)Hw buffer to fill. 151 * Returns: 152 * BCM_E_XXX 153 */ 154 STATIC int 155 _bcm_th_alpm_lpm_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 156 defip_entry_t *lpm_entry, int nh_ecmp_idx, uint32 *flags) 157 { 158 bcm_ip_t ip4_mask; 159 int vrf_id; 160 int vrf_mask; 161 int ipv6; 162 163 ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 164 165 /* Extract entry vrf id & vrf mask. */ 166 BCM_IF_ERROR_RETURN 167 (_bcm_th_alpm_lpm_vrf_init(unit, lpm_cfg, &vrf_id, &vrf_mask)); 168 169 170 /* Zero buffers. */ 171 sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip)); 172 173 /* Set hit bit. */ 174 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 175 soc_L3_DEFIPm_field32_set(unit, lpm_entry, HIT0f, 1); 176 } 177 178 /* Set priority override bit. */ 179 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 180 soc_L3_DEFIPm_field32_set(unit, lpm_entry, RPE0f, 1); 181 } 182 183 /* Write priority field. */ 184 soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio); 185 186 /* Fill next hop information. */ 187 if (soc_feature(unit, soc_feature_generic_dest)) { 188 uint32 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 189 uint32 dest_val = 0; 190 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 191 dest_type = SOC_MEM_FIF_DEST_ECMP; 192 dest_val = nh_ecmp_idx; 193 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 194 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 195 dest_val = nh_ecmp_idx; 196 } else { 197 dest_type = SOC_MEM_FIF_DEST_INVALID; 198 } 199 200 if (dest_type != SOC_MEM_FIF_DEST_INVALID) { 201 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, 202 DESTINATION0f, dest_type, dest_val); 203 } 204 } else { 205 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 206 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1); 207 soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, 208 nh_ecmp_idx); 209 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 210 soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, 211 nh_ecmp_idx); 212 } 213 } 214 215 /* Set destination discard flag. */ 216 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 217 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DST_DISCARD0f, 1); 218 } 219 220 /* remember src discard flag */ 221 if (lpm_cfg->defip_flags & BCM_L3_SRC_DISCARD) { 222 *flags |= SOC_ALPM_RPF_SRC_DISCARD; 223 } 224 225 if (soc_feature(unit, soc_feature_alpm_flex_stat)) { 226 *flags |= SOC_ALPM_STAT_FLEX; 227 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f, 228 _soc_th_alpm_lpm_entry_view_get(unit, ipv6, 0x1)); 229 } 230 231 /* Set classification group id. */ 232 soc_L3_DEFIPm_field32_set(unit, lpm_entry, CLASS_ID0f, 233 lpm_cfg->defip_lookup_class); 234 235 /* Set Global route flag. */ 236 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 237 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_ROUTE0f, 0x1); 238 } 239 240 /* Indicate this is an override entry */ 241 if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 242 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_HIGH0f, 0x1); 243 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_ROUTE0f, 0x1); 244 } 245 246 /* Set VRF */ 247 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_0f, vrf_id); 248 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK0f, vrf_mask); 249 250 if (soc_feature(unit, soc_feature_ipmc_defip) && 251 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 252 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 253 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MULTICAST_ROUTE0f, 1); 254 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 255 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 2); 256 } 257 258 if (soc_feature(unit, soc_feature_generic_dest)) { 259 if (lpm_cfg->defip_mc_group > 0) { 260 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 261 SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group); 262 } 263 } else { 264 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f, lpm_cfg->defip_mc_group); 265 } 266 267 /* 268 * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, 269 * Now it wil fit in EXPECTED_L3_IIFf 270 */ 271 if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) { 272 soc_L3_DEFIPm_field32_set(unit, lpm_entry, EXPECTED_L3_IIF0f, 273 _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp)); 274 } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) 275 && (lpm_cfg->defip_expected_intf != 0)) { 276 277 soc_L3_DEFIPm_field32_set(unit, lpm_entry, EXPECTED_L3_IIF0f, 278 lpm_cfg->defip_expected_intf); 279 280 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) { 281 soc_L3_DEFIPm_field32_set(unit, lpm_entry, 282 IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, 1); 283 } 284 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 285 soc_L3_DEFIPm_field32_set(unit, lpm_entry, 286 IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, 1); 287 } 288 } 289 } 290 291 if (ipv6) { 292 /* Set prefix ip address & mask. */ 293 _bcm_th_alpm_lpm64_key_init(unit, lpm_cfg, lpm_entry); 294 295 /* Set second part valid bit. */ 296 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 1); 297 298 /* Set mode to ipv6 */ 299 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODE0_f(unit), 1); 300 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODE1_f(unit), 1); 301 302 /* Set Virtual Router id */ 303 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_1f, vrf_id); 304 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK1f, vrf_mask); 305 } else { 306 ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len); 307 /* Apply subnet mask. */ 308 lpm_cfg->defip_ip_addr &= ip4_mask; 309 310 /* Set address to the buffer. */ 311 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR0f, 312 lpm_cfg->defip_ip_addr); 313 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_MASK0f, ip4_mask); 314 } 315 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID0f, 1); 316 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DWf)) { 317 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, DWf, 0); 318 } 319 320 /* Set Mode Masks */ 321 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, MODE_MASK0_f(unit), 322 (1 << soc_mem_field_length(unit, L3_DEFIPm, MODE_MASK0_f(unit))) - 1); 323 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, MODE_MASK1_f(unit), 324 (1 << soc_mem_field_length(unit, L3_DEFIPm, MODE_MASK1_f(unit))) - 1); 325 326 /* Set Entry Type Masks */ 327 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_TYPE0_f(unit), 328 (1 << soc_mem_field_length(unit, L3_DEFIPm, ENTRY_TYPE0_f(unit))) - 1); 329 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_TYPE1_f(unit), 330 (1 << soc_mem_field_length(unit, L3_DEFIPm, ENTRY_TYPE1_f(unit))) - 1); 331 /* 332 * Note ipv4 entries are expected to reside in part 0 of the entry. 333 */ 334 335 /* Base counter index. */ 336 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f, 337 lpm_cfg->defip_flex_ctr_base_id); 338 /* Counter offset mode. */ 339 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_OFFSET_MODE0f, 340 lpm_cfg->defip_flex_ctr_mode); 341 /* Counter pool number. */ 342 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_POOL_NUMBER0f, 343 lpm_cfg->defip_flex_ctr_pool); 344 345 return (BCM_E_NONE); 346 } 347 348 349 /* 350 * Function: 351 * _bcm_th_alpm_lpm128_addr_init 352 * Purpose: 353 * Set IP6 address field in memory from ip6 addr type. 354 * Parameters: 355 * unit - (IN) BCM device number. 356 * mem - (IN) Memory id. 357 * entry - (IN) HW entry buffer. 358 * ip6 - (IN) SW ip6 address buffer. 359 * Returns: void 360 */ 361 STATIC void 362 _bcm_th_alpm_lpm128_addr_init(int unit, soc_mem_t mem, uint32 *entry, 363 const ip6_addr_t ip6) 364 { 365 uint32 ip6_field[4]; 366 ip6_field[3] = ((ip6[12] << 24)| (ip6[13] << 16) | 367 (ip6[14] << 8) | (ip6[15] << 0)); 368 soc_mem_field_set(unit, mem, entry, IP_ADDR0_LWRf, &ip6_field[3]); 369 ip6_field[2] = ((ip6[8] << 24) | (ip6[9] << 16) | 370 (ip6[10] << 8) | (ip6[11] << 0)); 371 soc_mem_field_set(unit, mem, entry, IP_ADDR1_LWRf, &ip6_field[2]); 372 ip6_field[1] = ((ip6[4] << 24) | (ip6[5] << 16) | 373 (ip6[6] << 8) | (ip6[7] << 0)); 374 soc_mem_field_set(unit, mem, entry, IP_ADDR0_UPRf, &ip6_field[1]); 375 ip6_field[0] = ((ip6[0] << 24) | (ip6[1] << 16) | 376 (ip6[2] << 8) | (ip6[3] << 0)); 377 soc_mem_field_set(unit, mem, entry, IP_ADDR1_UPRf, ip6_field); 378 } 379 380 /* 381 * Function: 382 * _bcm_th_alpm_lpm128_mask_init 383 * Purpose: 384 * Set IP6 mask field in memory from ip6 addr type. 385 * Parameters: 386 * unit - (IN) BCM device number. 387 * mem - (IN) Memory id. 388 * entry - (IN) HW entry buffer. 389 * ip6 - (IN) SW ip6 address buffer. 390 * Returns: void 391 */ 392 STATIC void 393 _bcm_th_alpm_lpm128_mask_init(int unit, soc_mem_t mem, uint32 *entry, 394 const ip6_addr_t ip6) 395 { 396 uint32 ip6_field[4]; 397 ip6_field[3] = ((ip6[12] << 24)| (ip6[13] << 16) | 398 (ip6[14] << 8) | (ip6[15] << 0)); 399 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK0_LWRf, &ip6_field[3]); 400 ip6_field[2] = ((ip6[8] << 24) | (ip6[9] << 16) | 401 (ip6[10] << 8) | (ip6[11] << 0)); 402 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK1_LWRf, &ip6_field[2]); 403 ip6_field[1] = ((ip6[4] << 24) | (ip6[5] << 16) | 404 (ip6[6] << 8) | (ip6[7] << 0)); 405 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK0_UPRf, &ip6_field[1]); 406 ip6_field[0] = ((ip6[0] << 24) | (ip6[1] << 16) | 407 (ip6[2] << 8) | (ip6[3] << 0)); 408 soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK1_UPRf, ip6_field); 409 } 410 411 STATIC int 412 _bcm_th_alpm_lpm128_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 413 defip_pair_128_entry_t *lpm_entry, int nh_ecmp_idx, uint32 *flags) 414 { 415 int vrf_id; 416 int vrf_mask; 417 bcm_ip6_t mask; /* Subnet mask. */ 418 419 /* Extract entry vrf id & vrf mask. */ 420 BCM_IF_ERROR_RETURN 421 (_bcm_th_alpm_lpm_vrf_init(unit, lpm_cfg, &vrf_id, &vrf_mask)); 422 423 /* Zero buffers. */ 424 sal_memset(lpm_entry, 0, sizeof(*lpm_entry)); 425 426 /* Set hit bit. */ 427 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 428 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, HITf, 1); 429 } 430 431 /* Set priority override bit. */ 432 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 433 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, RPEf, 1); 434 } 435 436 /* Write priority field. */ 437 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, PRIf, lpm_cfg->defip_prio); 438 439 /* Fill next hop information. */ 440 if (soc_feature(unit, soc_feature_generic_dest)) { 441 uint32 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 442 uint32 dest_val = 0; 443 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 444 dest_type = SOC_MEM_FIF_DEST_ECMP; 445 dest_val = nh_ecmp_idx; 446 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 447 dest_type = SOC_MEM_FIF_DEST_NEXTHOP; 448 dest_val = nh_ecmp_idx; 449 } else { 450 dest_type = SOC_MEM_FIF_DEST_INVALID; 451 } 452 453 if (dest_type != SOC_MEM_FIF_DEST_INVALID) { 454 soc_mem_field32_dest_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 455 DESTINATIONf, dest_type, dest_val); 456 } 457 } else { 458 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 459 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, ECMPf, 1); 460 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, NEXT_HOP_INDEXf, 461 nh_ecmp_idx); 462 } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) { 463 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, NEXT_HOP_INDEXf, 464 nh_ecmp_idx); 465 } 466 } 467 468 /* Set destination discard flag. */ 469 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 470 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, DST_DISCARDf, 1); 471 } 472 473 /* remember src discard flag */ 474 if (lpm_cfg->defip_flags & BCM_L3_SRC_DISCARD) { 475 *flags |= SOC_ALPM_RPF_SRC_DISCARD; 476 } 477 478 if (soc_feature(unit, soc_feature_alpm_flex_stat)) { 479 *flags |= SOC_ALPM_STAT_FLEX; 480 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_VIEWf, 481 _soc_th_alpm_lpm_entry_view_get(unit, L3_DEFIP_MODE_128, 0x1)); 482 } 483 484 /* Set classification group id. */ 485 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, CLASS_IDf, 486 lpm_cfg->defip_lookup_class); 487 488 /* Set Global route flag. */ 489 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 490 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_ROUTEf, 0x1); 491 } 492 493 /* Indicate this is an override entry */ 494 if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) { 495 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_HIGHf, 0x1); 496 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_ROUTEf, 0x1); 497 } 498 499 if (soc_feature(unit, soc_feature_ipmc_defip) && 500 (lpm_cfg->defip_flags & BCM_L3_IPMC)) { 501 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 502 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 503 MULTICAST_ROUTEf, 1); 504 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 505 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 506 DATA_TYPEf, 2); 507 } 508 509 if (soc_feature(unit, soc_feature_generic_dest)) { 510 if (lpm_cfg->defip_mc_group > 0) { 511 soc_mem_field32_dest_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 512 DESTINATIONf, SOC_MEM_FIF_DEST_IPMC, 513 lpm_cfg->defip_mc_group); 514 } 515 } else { 516 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, L3MC_INDEXf, 517 lpm_cfg->defip_mc_group); 518 } 519 520 /* 521 * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, 522 * Now it wil fit in EXPECTED_L3_IIFf 523 */ 524 if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) { 525 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 526 EXPECTED_L3_IIFf, _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp)); 527 } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 528 (lpm_cfg->defip_expected_intf != 0)) { 529 530 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 531 EXPECTED_L3_IIFf, lpm_cfg->defip_expected_intf); 532 533 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) { 534 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 535 IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf, 1); 536 } 537 if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 538 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 539 IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf, 1); 540 } 541 } 542 } 543 544 /* Create mask from prefix length. */ 545 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 546 547 /* Apply mask on address. */ 548 bcm_xgs3_l3_mask6_apply(mask, lpm_cfg->defip_ip6_addr); 549 550 /* Set prefix ip address & mask. */ 551 _bcm_th_alpm_lpm128_addr_init(unit, L3_DEFIP_PAIR_128m, 552 (uint32 *)lpm_entry, 553 lpm_cfg->defip_ip6_addr); 554 555 _bcm_th_alpm_lpm128_mask_init(unit, L3_DEFIP_PAIR_128m, 556 (uint32 *)lpm_entry, mask); 557 558 /* Set Virtual Router id */ 559 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_0_LWRf, vrf_id); 560 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_1_LWRf, vrf_id); 561 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_0_UPRf, vrf_id); 562 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_1_UPRf, vrf_id); 563 564 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK0_LWRf, 565 vrf_mask); 566 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK1_LWRf, 567 vrf_mask); 568 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK0_UPRf, 569 vrf_mask); 570 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK1_UPRf, 571 vrf_mask); 572 573 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID0_LWRf, 1); 574 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID1_LWRf, 1); 575 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID0_UPRf, 1); 576 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID1_UPRf, 1); 577 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, DWf)) { 578 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, DWf, 1); 579 } 580 581 /* Set mode to ipv6-128 */ 582 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE0_LWR_f(unit), 3); 583 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE1_LWR_f(unit), 3); 584 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE0_UPR_f(unit), 3); 585 soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE1_UPR_f(unit), 3); 586 587 /* Set Mode Masks */ 588 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK0_LWR_f(unit), 589 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK0_LWR_f(unit))) - 1); 590 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK1_LWR_f(unit), 591 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK1_LWR_f(unit))) - 1); 592 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK0_UPR_f(unit), 593 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK0_UPR_f(unit))) - 1); 594 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK1_UPR_f(unit), 595 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK1_UPR_f(unit))) - 1); 596 597 /* Set Entry Type Masks */ 598 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE0_LWR_f(unit), 599 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE0_LWR_f(unit))) - 1); 600 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE1_LWR_f(unit), 601 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE1_LWR_f(unit))) - 1); 602 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE0_UPR_f(unit), 603 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE0_UPR_f(unit))) - 1); 604 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE1_UPR_f(unit), 605 (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE1_UPR_f(unit))) - 1); 606 607 /* Base counter index. */ 608 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_BASE_COUNTER_IDXf, 609 lpm_cfg->defip_flex_ctr_base_id); 610 /* Counter offset mode. */ 611 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_OFFSET_MODEf, 612 lpm_cfg->defip_flex_ctr_mode); 613 /* Counter pool number. */ 614 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_POOL_NUMBERf, 615 lpm_cfg->defip_flex_ctr_pool); 616 return (BCM_E_NONE); 617 } 618 619 /* 620 * Function: 621 * _bcm_th_alpm_lpm64_key_parse 622 * Purpose: 623 * Set an IP6 address field in L3_DEFIPm 624 * Note: 625 * See soc_mem_ip6_addr_set() 626 */ 627 STATIC void 628 _bcm_th_alpm_lpm64_key_parse(int unit, const void *lpm_key, 629 _bcm_defip_cfg_t *lpm_cfg) 630 { 631 uint8 *ip6; /* Ip6 address. */ 632 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 633 uint32 ip6_word; /* Temp storage. */ 634 635 sal_memset(mask, 0, sizeof (bcm_ip6_t)); 636 637 /* Just to keep variable name short. */ 638 ip6 = lpm_cfg->defip_ip6_addr; 639 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 640 641 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word); 642 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 643 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 644 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 645 ip6[3] = (uint8) (ip6_word & 0xff); 646 647 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word); 648 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 649 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 650 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 651 ip6[7] = (uint8) (ip6_word & 0xff); 652 653 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word); 654 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 655 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 656 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 657 mask[3] = (uint8) (ip6_word & 0xff); 658 659 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word); 660 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 661 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 662 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 663 mask[7] = (uint8) (ip6_word & 0xff); 664 665 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 666 } 667 668 /* 669 * Function: 670 * _bcm_th_alpm_lpm_key_parse 671 * Purpose: 672 * Parse entry key from DEFIP table. 673 * Parameters: 674 * unit - (IN)SOC unit number. 675 * lpm_cfg - (OUT)Buffer to fill defip information. 676 * lpm_entry - (IN) Buffer read from hw. 677 * Returns: 678 * void 679 */ 680 STATIC void 681 _bcm_th_alpm_lpm_key_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 682 defip_entry_t *lpm_entry) 683 { 684 bcm_ip_t v4_mask; 685 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6, tmp; 686 687 /* Set prefix ip address & mask. */ 688 if (ipv6) { 689 _bcm_th_alpm_lpm64_key_parse(unit, lpm_entry, lpm_cfg); 690 } else { 691 /* Get ipv4 address. */ 692 lpm_cfg->defip_ip_addr = 693 soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR0f); 694 695 /* Get subnet mask. */ 696 v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_MASK0f); 697 698 /* Fill mask length. */ 699 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 700 } 701 702 /* Get Virtual Router id */ 703 (void)soc_th_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf, &tmp); 704 705 return; 706 } 707 708 709 /* 710 * Function: 711 * _bcm_th_alpm_lpm_data_parse 712 * Purpose: 713 * Parse an entry from DEFIP table. 714 * Parameters: 715 * unit - (IN)SOC unit number. 716 * lpm_cfg - (OUT)Buffer to fill defip information. 717 * nh_ecmp_idx - (OUT)Next hop index or ecmp group id. 718 * lpm_entry - (IN) Buffer read from hw. 719 * Returns: 720 * void 721 */ 722 STATIC INLINE void 723 _bcm_th_alpm_lpm_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 724 int *p_nh_ecmp_idx, defip_entry_t *lpm_entry) 725 { 726 int is_ecmp = 0; 727 uint32 nh_ecmp_idx = 0; 728 int ipv6 = soc_L3_DEFIPm_field32_get(unit, lpm_entry, MODE0_f(unit)); 729 730 /* Reset entry flags first. */ 731 lpm_cfg->defip_flags = 0; 732 733 /* Check if entry points to ecmp group. */ 734 if (soc_feature(unit, soc_feature_generic_dest)) { 735 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 736 nh_ecmp_idx = soc_mem_field32_dest_get(unit, L3_DEFIPm, lpm_entry, 737 DESTINATION0f, &dest_type); 738 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 739 is_ecmp = 1; 740 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 741 nh_ecmp_idx = 0; 742 } 743 } else { 744 is_ecmp = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f); 745 if (is_ecmp) { 746 nh_ecmp_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f); 747 } else { 748 nh_ecmp_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f); 749 } 750 } 751 752 /* Check if entry points to ecmp group. */ 753 if (is_ecmp) { 754 /* Mark entry as ecmp */ 755 lpm_cfg->defip_ecmp = 1; 756 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 757 758 /* Get ecmp group id. */ 759 if (p_nh_ecmp_idx) { 760 *p_nh_ecmp_idx = nh_ecmp_idx; 761 } 762 } else { 763 /* Mark entry as non-ecmp. */ 764 lpm_cfg->defip_ecmp = 0; 765 766 /* Reset ecmp group next hop count. */ 767 lpm_cfg->defip_ecmp_count = 0; 768 769 /* Get next hop index. */ 770 if (p_nh_ecmp_idx) { 771 *p_nh_ecmp_idx = nh_ecmp_idx; 772 } 773 } 774 /* Get entry priority. */ 775 lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f); 776 777 /* Get hit bit. */ 778 if (!ALPM_CTRL(unit).hit_bits_skip && 779 soc_L3_DEFIPm_field32_get(unit, lpm_entry, HIT0f)) { 780 lpm_cfg->defip_flags |= BCM_L3_HIT; 781 } 782 783 /* Get priority override bit. */ 784 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE0f)) { 785 lpm_cfg->defip_flags |= BCM_L3_RPE; 786 } 787 788 /* Get destination discard flag. */ 789 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) { 790 if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) { 791 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 792 } 793 } 794 795 #if defined(BCM_TRX_SUPPORT) 796 /* Set classification group id. */ 797 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) { 798 lpm_cfg->defip_lookup_class = 799 soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f); 800 } 801 #endif /* BCM_TRX_SUPPORT */ 802 803 804 if (ipv6) { 805 lpm_cfg->defip_flags |= BCM_L3_IP6; 806 /* Get hit bit from the second part of the entry. */ 807 if (!ALPM_CTRL(unit).hit_bits_skip && 808 soc_L3_DEFIPm_field32_get(unit, lpm_entry, HIT1f)) { 809 lpm_cfg->defip_flags |= BCM_L3_HIT; 810 } 811 812 /* Get priority override bit from the second part of the entry. */ 813 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE1f)) { 814 lpm_cfg->defip_flags |= BCM_L3_RPE; 815 } 816 } 817 818 if (soc_feature(unit, soc_feature_ipmc_defip)) { 819 int ipmc_route = 0; 820 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 821 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 822 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 823 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 824 ipmc_route = 1; 825 } else { 826 ipmc_route = 0; 827 } 828 } 829 830 if (ipmc_route) { 831 int val; 832 lpm_cfg->defip_flags |= BCM_L3_IPMC; 833 834 if (p_nh_ecmp_idx) { 835 *p_nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; 836 } 837 if (soc_L3_DEFIPm_field32_get(unit, 838 lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f)) { 839 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP; 840 } 841 if (soc_L3_DEFIPm_field32_get(unit, 842 lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f)) { 843 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 844 } 845 /* 846 * RP ID and ExpectedIIF are overlaid. 847 */ 848 val = soc_L3_DEFIPm_field32_get(unit, 849 lpm_entry, EXPECTED_L3_IIF0f); 850 if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) { 851 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIPm, RPA_ID0f)) - 1; 852 /* 853 * 1) If value is more than RPA_ID field then its l3_iif. 854 * N/A for TD3/MV2/HX5 to support warmboot. 855 * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid 856 */ 857 if ((lpm_cfg->defip_ipmc_flags & 858 (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) || 859 (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) || 860 SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) { 861 lpm_cfg->defip_expected_intf = val; 862 if (0 != lpm_cfg->defip_expected_intf) { 863 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 864 } 865 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 866 } else { 867 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE; 868 lpm_cfg->defip_l3a_rp = val & rpa_id_mask; 869 lpm_cfg->defip_expected_intf = val; 870 } 871 } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) { 872 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val); 873 } else { 874 lpm_cfg->defip_expected_intf = val; 875 876 if (0 != lpm_cfg->defip_expected_intf) { 877 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 878 } 879 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 880 } 881 882 if (soc_feature(unit, soc_feature_generic_dest)) { 883 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 884 uint32 dest_value = 0; 885 dest_value = soc_mem_field32_dest_get(unit, 886 L3_DEFIPm, lpm_entry, 887 DESTINATION0f, &dest_type); 888 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 889 lpm_cfg->defip_mc_group = dest_value; 890 } else { 891 lpm_cfg->defip_mc_group = 0; 892 } 893 } else { 894 lpm_cfg->defip_mc_group = soc_mem_field32_get(unit, L3_DEFIPm, 895 lpm_entry, L3MC_INDEX0f); 896 } 897 } 898 } 899 900 /* Read base counter index. */ 901 lpm_cfg->defip_flex_ctr_base_id = 902 soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f); 903 /* Read counter offset mode. */ 904 lpm_cfg->defip_flex_ctr_mode = 905 soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_OFFSET_MODE0f); 906 /* Read counter pool number. */ 907 lpm_cfg->defip_flex_ctr_pool = 908 soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_POOL_NUMBER0f); 909 910 911 return; 912 } 913 914 /* 915 * Function: 916 * _bcm_th_alpm_lpm128_mask_parse 917 * Purpose: 918 * Read IP6 mask field from memory field to ip6_addr_t buffer. 919 * Parameters: 920 * unit - (IN) BCM device number. 921 * mem - (IN) Memory id. 922 * entry - (IN) HW entry buffer. 923 * ip6 - (OUT) SW ip6 address buffer. 924 * Returns: void 925 */ 926 STATIC void 927 _bcm_th_alpm_lpm128_mask_parse(int unit, soc_mem_t mem, const void *entry, 928 ip6_addr_t ip6) 929 { 930 uint32 ip6_field[4]; 931 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK0_LWRf, (uint32 *)&ip6_field[3]); 932 ip6[12] = (uint8) (ip6_field[3] >> 24); 933 ip6[13] = (uint8) (ip6_field[3] >> 16 & 0xff); 934 ip6[14] = (uint8) (ip6_field[3] >> 8 & 0xff); 935 ip6[15] = (uint8) (ip6_field[3] & 0xff); 936 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK1_LWRf, (uint32 *)&ip6_field[2]); 937 ip6[8] = (uint8) (ip6_field[2] >> 24); 938 ip6[9] = (uint8) (ip6_field[2] >> 16 & 0xff); 939 ip6[10] = (uint8) (ip6_field[2] >> 8 & 0xff); 940 ip6[11] = (uint8) (ip6_field[2] & 0xff); 941 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK0_UPRf, (uint32 *)&ip6_field[1]); 942 ip6[4] = (uint8) (ip6_field[1] >> 24); 943 ip6[5] = (uint8) (ip6_field[1] >> 16 & 0xff); 944 ip6[6] =(uint8) (ip6_field[1] >> 8 & 0xff); 945 ip6[7] =(uint8) (ip6_field[1] & 0xff); 946 soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK1_UPRf, ip6_field); 947 ip6[0] =(uint8) (ip6_field[0] >> 24); 948 ip6[1] =(uint8) (ip6_field[0] >> 16 & 0xff); 949 ip6[2] =(uint8) (ip6_field[0] >> 8 & 0xff); 950 ip6[3] =(uint8) (ip6_field[0] & 0xff); 951 } 952 953 /* 954 * Function: 955 * _bcm_th_alpm_lpm128_addr_parse 956 * Purpose: 957 * Read IP6 address field from memory field to ip6_addr_t buffer. 958 * Parameters: 959 * unit - (IN) BCM device number. 960 * mem - (IN) Memory id. 961 * entry - (IN) HW entry buffer. 962 * ip6 - (OUT) SW ip6 address buffer. 963 * Returns: void 964 */ 965 STATIC void 966 _bcm_th_alpm_lpm128_addr_parse(int unit, soc_mem_t mem, const void *entry, 967 ip6_addr_t ip6) 968 { 969 uint32 ip6_field[4]; 970 soc_mem_field_get(unit, mem, entry, IP_ADDR0_LWRf, (uint32 *)&ip6_field[3]); 971 ip6[12] = (uint8) (ip6_field[3] >> 24); 972 ip6[13] = (uint8) (ip6_field[3] >> 16 & 0xff); 973 ip6[14] = (uint8) (ip6_field[3] >> 8 & 0xff); 974 ip6[15] = (uint8) (ip6_field[3] & 0xff); 975 soc_mem_field_get(unit, mem, entry, IP_ADDR1_LWRf, (uint32 *)&ip6_field[2]); 976 ip6[8] = (uint8) (ip6_field[2] >> 24); 977 ip6[9] = (uint8) (ip6_field[2] >> 16 & 0xff); 978 ip6[10] = (uint8) (ip6_field[2] >> 8 & 0xff); 979 ip6[11] = (uint8) (ip6_field[2] & 0xff); 980 soc_mem_field_get(unit, mem, entry, IP_ADDR0_UPRf, (uint32 *)&ip6_field[1]); 981 ip6[4] = (uint8) (ip6_field[1] >> 24); 982 ip6[5] = (uint8) (ip6_field[1] >> 16 & 0xff); 983 ip6[6] =(uint8) (ip6_field[1] >> 8 & 0xff); 984 ip6[7] =(uint8) (ip6_field[1] & 0xff); 985 soc_mem_field_get(unit, mem, entry, IP_ADDR1_UPRf, ip6_field); 986 ip6[0] =(uint8) (ip6_field[0] >> 24); 987 ip6[1] =(uint8) (ip6_field[0] >> 16 & 0xff); 988 ip6[2] =(uint8) (ip6_field[0] >> 8 & 0xff); 989 ip6[3] =(uint8) (ip6_field[0] & 0xff); 990 } 991 992 993 /* 994 * Function: 995 * _bcm_th_alpm_lpm128_key_parse 996 * Purpose: 997 * Parse route entry key from L3_DEFIP_PAIR_128 table. 998 * Parameters: 999 * unit - (IN)SOC unit number. 1000 * entry - (IN)Hw entry buffer. 1001 * lpm_cfg - (IN/OUT)Buffer to fill defip information. 1002 * Returns: 1003 * BCM_E_XXX 1004 */ 1005 STATIC int 1006 _bcm_th_alpm_lpm128_key_parse(int unit, uint32 *hw_entry, 1007 _bcm_defip_cfg_t *lpm_cfg) 1008 { 1009 soc_mem_t mem = L3_DEFIP_PAIR_128m; /* Route table memory. */ 1010 bcm_ip6_t mask; /* Subnet mask. */ 1011 1012 /* Input parameters check. */ 1013 if ((lpm_cfg == NULL) || (hw_entry == NULL)) { 1014 return (BCM_E_PARAM); 1015 } 1016 1017 /* Extract ip6 address. */ 1018 _bcm_th_alpm_lpm128_addr_parse(unit, mem, hw_entry, 1019 lpm_cfg->defip_ip6_addr); 1020 1021 /* Extract subnet mask. */ 1022 _bcm_th_alpm_lpm128_mask_parse(unit, mem, hw_entry, mask); 1023 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 1024 1025 /* Extract vrf id & vrf mask. */ 1026 if(!soc_mem_field32_get(unit, mem, hw_entry, VRF_ID_MASK0_LWRf)) { 1027 lpm_cfg->defip_vrf = BCM_L3_VRF_OVERRIDE; 1028 } else { 1029 lpm_cfg->defip_vrf = soc_mem_field32_get(unit, mem, hw_entry, 1030 VRF_ID_0_LWRf); 1031 } 1032 return (BCM_E_NONE); 1033 } 1034 1035 STATIC INLINE void 1036 _bcm_th_alpm_lpm128_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 1037 int *p_nh_ecmp_idx, defip_pair_128_entry_t *lpm_entry) 1038 { 1039 int is_ecmp = 0; 1040 uint32 nh_ecmp_idx = 0; 1041 soc_mem_t mem = L3_DEFIP_PAIR_128m; 1042 int ipv6 = soc_mem_field32_get(unit, mem, lpm_entry, MODE0_LWR_f(unit)); 1043 1044 /* Reset entry flags first. */ 1045 lpm_cfg->defip_flags = 0; 1046 1047 if (soc_feature(unit, soc_feature_generic_dest)) { 1048 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1049 nh_ecmp_idx = soc_mem_field32_dest_get(unit, mem, lpm_entry, 1050 DESTINATIONf, &dest_type); 1051 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 1052 is_ecmp = 1; 1053 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 1054 nh_ecmp_idx = 0; 1055 } 1056 } else { 1057 is_ecmp = soc_mem_field32_get(unit, mem, lpm_entry, ECMPf); 1058 if (is_ecmp) { 1059 nh_ecmp_idx = soc_mem_field32_get(unit, mem, lpm_entry, ECMP_PTRf); 1060 } else { 1061 nh_ecmp_idx = soc_mem_field32_get(unit, mem, lpm_entry, NEXT_HOP_INDEXf); 1062 } 1063 } 1064 1065 /* Check if entry points to ecmp group. */ 1066 if (is_ecmp) { 1067 /* Mark entry as ecmp */ 1068 lpm_cfg->defip_ecmp = 1; 1069 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 1070 1071 /* Get ecmp group id. */ 1072 if (p_nh_ecmp_idx) { 1073 *p_nh_ecmp_idx = nh_ecmp_idx; 1074 } 1075 } else { 1076 /* Mark entry as non-ecmp. */ 1077 lpm_cfg->defip_ecmp = 0; 1078 1079 /* Reset ecmp group next hop count. */ 1080 lpm_cfg->defip_ecmp_count = 0; 1081 1082 /* Get next hop index. */ 1083 if (p_nh_ecmp_idx) { 1084 *p_nh_ecmp_idx = nh_ecmp_idx; 1085 } 1086 } 1087 /* Get entry priority. */ 1088 lpm_cfg->defip_prio = 1089 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, PRIf); 1090 1091 /* Get hit bit. */ 1092 if (!ALPM_CTRL(unit).hit_bits_skip && 1093 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, HITf)) { 1094 lpm_cfg->defip_flags |= BCM_L3_HIT; 1095 } 1096 1097 /* Get priority override bit. */ 1098 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, RPEf)) { 1099 lpm_cfg->defip_flags |= BCM_L3_RPE; 1100 } 1101 1102 /* Get destination discard flag. */ 1103 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, DST_DISCARDf)) { 1104 if(soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, DST_DISCARDf)) { 1105 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 1106 } 1107 } 1108 1109 #if defined(BCM_TRX_SUPPORT) 1110 /* Set classification group id. */ 1111 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, CLASS_IDf)) { 1112 lpm_cfg->defip_lookup_class = 1113 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, CLASS_IDf); 1114 } 1115 #endif /* BCM_TRX_SUPPORT */ 1116 1117 if (ipv6) { 1118 lpm_cfg->defip_flags |= BCM_L3_IP6; 1119 /* Get hit bit from the second part of the entry. */ 1120 if (!ALPM_CTRL(unit).hit_bits_skip && 1121 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, HITf)) { 1122 lpm_cfg->defip_flags |= BCM_L3_HIT; 1123 } 1124 1125 /* Get priority override bit from the second part of the entry. */ 1126 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, RPEf)) { 1127 lpm_cfg->defip_flags |= BCM_L3_RPE; 1128 } 1129 } 1130 1131 if (soc_feature(unit, soc_feature_ipmc_defip)) { 1132 int ipmc_route = 0; 1133 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 1134 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 1135 lpm_entry, MULTICAST_ROUTEf); 1136 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 1137 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 1138 lpm_entry, DATA_TYPEf) == 2) { 1139 ipmc_route = 1; 1140 } else { 1141 ipmc_route = 0; 1142 } 1143 } 1144 1145 if (ipmc_route) { 1146 int val; 1147 lpm_cfg->defip_flags |= BCM_L3_IPMC; 1148 1149 if (p_nh_ecmp_idx) { 1150 *p_nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; 1151 } 1152 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, 1153 lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf)) { 1154 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP; 1155 } 1156 if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, 1157 lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf)) { 1158 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU; 1159 } 1160 /* 1161 * RP ID and ExpectedIIF are overlaid. 1162 */ 1163 val = soc_L3_DEFIP_PAIR_128m_field32_get(unit, 1164 lpm_entry, EXPECTED_L3_IIFf); 1165 1166 if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) { 1167 int rpa_id_mask = 1168 (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, RPA_IDf)) - 1; 1169 /* 1170 * 1) If value is more than RPA_ID field then its l3_iif. 1171 * N/A for TD3/MV2/HX5 to support warmboot. 1172 * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid 1173 */ 1174 if ((lpm_cfg->defip_ipmc_flags & 1175 (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) || 1176 (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) || 1177 SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) { 1178 lpm_cfg->defip_expected_intf = val; 1179 if (0 != lpm_cfg->defip_expected_intf) { 1180 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 1181 } 1182 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 1183 } else { 1184 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE; 1185 lpm_cfg->defip_l3a_rp = val & rpa_id_mask; 1186 lpm_cfg->defip_expected_intf = val; 1187 } 1188 } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) { 1189 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val); 1190 } else { 1191 lpm_cfg->defip_expected_intf = val; 1192 1193 if (0 != lpm_cfg->defip_expected_intf) { 1194 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 1195 } 1196 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID; 1197 } 1198 1199 if (soc_feature(unit, soc_feature_generic_dest)) { 1200 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1201 uint32 dest_value = 0; 1202 dest_value = soc_mem_field32_dest_get(unit, 1203 L3_DEFIP_PAIR_128m, lpm_entry, 1204 DESTINATIONf, &dest_type); 1205 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 1206 lpm_cfg->defip_mc_group = dest_value; 1207 } else { 1208 lpm_cfg->defip_mc_group = 0; 1209 } 1210 } else { 1211 lpm_cfg->defip_mc_group = 1212 soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 1213 lpm_entry, L3MC_INDEXf); 1214 } 1215 } 1216 } 1217 1218 /* Read base counter index. */ 1219 lpm_cfg->defip_flex_ctr_base_id = 1220 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_BASE_COUNTER_IDXf); 1221 /* Read counter offset mode. */ 1222 lpm_cfg->defip_flex_ctr_mode = 1223 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_OFFSET_MODEf); 1224 /* Read counter pool number. */ 1225 lpm_cfg->defip_flex_ctr_pool = 1226 soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_POOL_NUMBERf); 1227 1228 return; 1229 } 1230 1231 1232 1233 /* 1234 * Function: 1235 * _bcm_th_alpm_ent64_key_parse 1236 * Purpose: 1237 * Set an IP6 address field in an ALPM memory 1238 * Note: 1239 * See soc_mem_ip6_addr_set() 1240 */ 1241 STATIC void 1242 _bcm_th_alpm_ent64_key_parse(int unit, const void *alpm_key, soc_mem_t mem, 1243 _bcm_defip_cfg_t *lpm_cfg) 1244 { 1245 uint8 *ip6; /* Ip6 address. */ 1246 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 1247 uint32 ip6_word[2]; /* Temp storage. */ 1248 1249 sal_memset(mask, 0, sizeof (bcm_ip6_t)); 1250 1251 /* Just to keep variable name short. */ 1252 ip6 = lpm_cfg->defip_ip6_addr; 1253 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 1254 1255 soc_mem_field_get(unit, mem, alpm_key, KEYf, &ip6_word[0]); 1256 ip6[0] = (uint8) ((ip6_word[1] >> 24) & 0xff); 1257 ip6[1] = (uint8) ((ip6_word[1] >> 16) & 0xff); 1258 ip6[2] = (uint8) ((ip6_word[1] >> 8) & 0xff); 1259 ip6[3] = (uint8) (ip6_word[1] & 0xff); 1260 1261 ip6[4] = (uint8) ((ip6_word[0] >> 24) & 0xff); 1262 ip6[5] = (uint8) ((ip6_word[0] >> 16) & 0xff); 1263 ip6[6] = (uint8) ((ip6_word[0] >> 8) & 0xff); 1264 ip6[7] = (uint8) (ip6_word[0] & 0xff); 1265 1266 lpm_cfg->defip_sub_len = soc_mem_field32_get(unit, mem, alpm_key, LENGTHf); 1267 } 1268 1269 /* 1270 * Function: 1271 * _bcm_th_alpm_ent_key_parse 1272 * Purpose: 1273 * Parse entry key from ALPM table. 1274 * Parameters: 1275 * unit - (IN) SOC unit number. 1276 * lpm_cfg - (OUT)Buffer to fill defip information. 1277 * *lpm_entry - (IN) Pointer to lpm buffer read from hw. 1278 * alpm_mem - (IN) ALPM memory type. 1279 * *alpm_entry - (IN) Pointer to alpm entry read from SRAM bank. 1280 * Returns: 1281 * void 1282 */ 1283 STATIC void 1284 _bcm_th_alpm_ent_key_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, 1285 defip_entry_t *lpm_entry, soc_mem_t alpm_mem, 1286 void *alpm_entry) 1287 { 1288 bcm_ip_t v4_mask; 1289 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 1290 1291 /* Set prefix ip address & mask. */ 1292 if (ipv6) { 1293 _bcm_th_alpm_ent64_key_parse(unit, alpm_entry, alpm_mem, lpm_cfg); 1294 } else { 1295 /* Get ipv4 address. */ 1296 lpm_cfg->defip_ip_addr = soc_mem_field32_get(unit, alpm_mem, 1297 alpm_entry, KEYf); 1298 1299 /* Get subnet mask. */ 1300 v4_mask = soc_mem_field32_get(unit, alpm_mem, alpm_entry, LENGTHf); 1301 if (v4_mask) { 1302 v4_mask = ~((1 << (32 - v4_mask)) - 1); 1303 } 1304 1305 /* Fill mask length. */ 1306 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 1307 } 1308 1309 /* Get Virtual Router id */ 1310 (void)soc_th_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf, &ipv6); 1311 1312 return; 1313 } 1314 1315 1316 /* 1317 * Function: 1318 * _bcm_th_alpm_ent_data_parse 1319 * Purpose: 1320 * Parse an entry from DEFIP table. 1321 * Parameters: 1322 * unit - (IN)SOC unit number. 1323 * lpm_cfg - (OUT)Buffer to fill defip information. 1324 * nh_ecmp_idx - (OUT)Next hop index or ecmp group id. 1325 * lpm_entry - (IN) Buffer read from hw. 1326 * Returns: 1327 * void 1328 */ 1329 STATIC void 1330 _bcm_th_alpm_ent_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx, 1331 soc_mem_t alpm_mem, void *alpm_entry) 1332 { 1333 int is_ecmp = 0; 1334 uint32 nh_ecmp_idx = 0; 1335 1336 /* Check if entry points to ecmp group. */ 1337 if (soc_feature(unit, soc_feature_generic_dest)) { 1338 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1339 nh_ecmp_idx = soc_mem_field32_dest_get(unit, alpm_mem, alpm_entry, 1340 DESTINATIONf, &dest_type); 1341 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 1342 is_ecmp = 1; 1343 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 1344 nh_ecmp_idx = 0; 1345 } 1346 } else { 1347 is_ecmp = soc_mem_field32_get(unit, alpm_mem, alpm_entry, ECMPf); 1348 if (is_ecmp) { 1349 nh_ecmp_idx = 1350 soc_mem_field32_get(unit, alpm_mem, alpm_entry, ECMP_PTRf); 1351 } else { 1352 nh_ecmp_idx = 1353 soc_mem_field32_get(unit, alpm_mem, alpm_entry, 1354 NEXT_HOP_INDEXf); 1355 } 1356 } 1357 1358 /* Reset entry flags first. */ 1359 lpm_cfg->defip_flags = 0; 1360 1361 /* Check if entry points to ecmp group. */ 1362 if (is_ecmp) { 1363 /* Mark entry as ecmp */ 1364 lpm_cfg->defip_ecmp = 1; 1365 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 1366 1367 /* Get ecmp group id. */ 1368 if (p_nh_ecmp_idx) { 1369 *p_nh_ecmp_idx = nh_ecmp_idx; 1370 } 1371 } else { 1372 /* Mark entry as non-ecmp. */ 1373 lpm_cfg->defip_ecmp = 0; 1374 1375 /* Reset ecmp group next hop count. */ 1376 lpm_cfg->defip_ecmp_count = 0; 1377 1378 /* Get next hop index. */ 1379 if (p_nh_ecmp_idx) { 1380 *p_nh_ecmp_idx = nh_ecmp_idx; 1381 } 1382 } 1383 /* Get entry priority. */ 1384 lpm_cfg->defip_prio = soc_mem_field32_get(unit, alpm_mem, alpm_entry, 1385 PRIf); 1386 1387 /* Get hit bit. */ 1388 if (!ALPM_CTRL(unit).hit_bits_skip && 1389 soc_mem_field32_get(unit, alpm_mem, alpm_entry, HITf)) { 1390 lpm_cfg->defip_flags |= BCM_L3_HIT; 1391 } 1392 /* Get priority override bit. */ 1393 if (soc_mem_field32_get(unit, alpm_mem, alpm_entry, RPEf)) { 1394 lpm_cfg->defip_flags |= BCM_L3_RPE; 1395 } 1396 1397 /* Get destination discard flag. */ 1398 if (SOC_MEM_FIELD_VALID(unit, alpm_mem, DST_DISCARDf)) { 1399 if(soc_mem_field32_get(unit, alpm_mem, alpm_entry, DST_DISCARDf)) { 1400 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 1401 } 1402 } 1403 1404 /* Set classification group id. */ 1405 lpm_cfg->defip_lookup_class = soc_mem_field32_get(unit, alpm_mem, 1406 alpm_entry, CLASS_IDf); 1407 1408 if (alpm_mem == L3_DEFIP_ALPM_IPV6_64m || 1409 alpm_mem == L3_DEFIP_ALPM_IPV6_64_1m || 1410 alpm_mem == L3_DEFIP_ALPM_IPV6_128m) { 1411 lpm_cfg->defip_flags |= BCM_L3_IP6; 1412 } 1413 return; 1414 } 1415 1416 1417 STATIC int 1418 _bcm_th_alpm_ent128_key_parse(int unit, soc_mem_t mem, uint32 *alpm_entry, 1419 _bcm_defip_cfg_t *lpm_cfg) 1420 { 1421 uint32 ip6_word[4]; 1422 1423 uint8 *ip6; 1424 1425 ip6 = lpm_cfg->defip_ip6_addr; 1426 1427 soc_mem_field_get(unit, mem, alpm_entry, KEYf, ip6_word); 1428 ip6[0] = (ip6_word[3] >> 24); 1429 ip6[1] = (ip6_word[3] >> 16) & 0xff; 1430 ip6[2] = (ip6_word[3] >> 8) & 0xff; 1431 ip6[3] = ip6_word[3]; 1432 1433 ip6[4] = ip6_word[2] >> 24; 1434 ip6[5] = (ip6_word[2] >> 16) & 0xff; 1435 ip6[6] = (ip6_word[2] >> 8) & 0xff; 1436 ip6[7] = ip6_word[2]; 1437 1438 ip6[8] = ip6_word[1] >> 24; 1439 ip6[9] = (ip6_word[1] >> 16) & 0xff; 1440 ip6[10] = (ip6_word[1] >> 8) & 0xff; 1441 ip6[11] = ip6_word[1]; 1442 1443 ip6[12] = ip6_word[0] >> 24; 1444 ip6[13] = (ip6_word[0] >> 16) & 0xff; 1445 ip6[14] = (ip6_word[0] >> 8) & 0xff; 1446 ip6[15] = ip6_word[0]; 1447 1448 lpm_cfg->defip_sub_len = 1449 soc_mem_field32_get(unit, mem, alpm_entry, LENGTHf); 1450 1451 return SOC_E_NONE; 1452 } 1453 1454 STATIC int 1455 _bcm_th_alpm_ent128_data_parse(int unit, soc_mem_t mem, uint32 *hw_entry, 1456 _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx) 1457 { 1458 int is_ecmp = 0; 1459 uint32 nh_ecmp_idx = 0; 1460 1461 /* Input parameters check. */ 1462 if ((lpm_cfg == NULL) || (hw_entry == NULL)) { 1463 return (BCM_E_PARAM); 1464 } 1465 1466 /* Check if entry points to ecmp group. */ 1467 if (soc_feature(unit, soc_feature_generic_dest)) { 1468 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1469 nh_ecmp_idx = soc_mem_field32_dest_get(unit, mem, hw_entry, 1470 DESTINATIONf, &dest_type); 1471 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 1472 is_ecmp = 1; 1473 } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) { 1474 nh_ecmp_idx = 0; 1475 } 1476 } else { 1477 is_ecmp = soc_mem_field32_get(unit, mem, hw_entry, ECMPf); 1478 if (is_ecmp) { 1479 nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, ECMP_PTRf); 1480 } else { 1481 nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, NEXT_HOP_INDEXf); 1482 } 1483 } 1484 1485 /* Reset entry flags first. */ 1486 lpm_cfg->defip_flags = 0; 1487 1488 /* Check if entry points to ecmp group. */ 1489 if (is_ecmp) { 1490 /* Mark entry as ecmp */ 1491 lpm_cfg->defip_ecmp = TRUE; 1492 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 1493 1494 /* Get ecmp group id. */ 1495 if (p_nh_ecmp_idx != NULL) { 1496 *p_nh_ecmp_idx = nh_ecmp_idx; 1497 } 1498 } else { 1499 /* Mark entry as non-ecmp. */ 1500 lpm_cfg->defip_ecmp = 0; 1501 1502 /* Reset ecmp group next hop count. */ 1503 lpm_cfg->defip_ecmp_count = 0; 1504 1505 /* Get next hop index. */ 1506 if (p_nh_ecmp_idx != NULL) { 1507 *p_nh_ecmp_idx = nh_ecmp_idx; 1508 } 1509 } 1510 1511 /* Mark entry as IPv6 */ 1512 lpm_cfg->defip_flags |= BCM_L3_IP6; 1513 1514 /* Get entry priority. */ 1515 lpm_cfg->defip_prio = soc_mem_field32_get(unit, mem, hw_entry, PRIf); 1516 1517 /* Get classification group id. */ 1518 lpm_cfg->defip_lookup_class = 1519 soc_mem_field32_get(unit, mem, hw_entry, CLASS_IDf); 1520 /* Get hit bit. */ 1521 if (!ALPM_CTRL(unit).hit_bits_skip && 1522 soc_mem_field32_get(unit, mem, hw_entry, HITf)) { 1523 lpm_cfg->defip_flags |= BCM_L3_HIT; 1524 } 1525 1526 /* Get priority override bit. */ 1527 if (soc_mem_field32_get(unit, mem, hw_entry, RPEf)) { 1528 lpm_cfg->defip_flags |= BCM_L3_RPE; 1529 } 1530 1531 /* Get destination discard field. */ 1532 if(soc_mem_field32_get(unit, mem, hw_entry, DST_DISCARDf)) { 1533 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 1534 } 1535 return (BCM_E_NONE); 1536 } 1537 1538 /* As part of ALPM VRF WAR */ 1539 STATIC int 1540 _bcm_th_alpm_warmboot_db_type_update(int unit) 1541 { 1542 int rv = BCM_E_NONE; 1543 1544 #if 0 1545 int i, defip_table_size = 0; 1546 char *aux_tbl_ptr = NULL; 1547 defip_aux_table_entry_t *aux_entry; 1548 int is_urpf_entry, urpf = 0; 1549 uint32 vrf, valid, db_type, ndb_type, nent_type; 1550 soc_mem_t mem = L3_DEFIP_AUX_TABLEm; 1551 int updated = 0; 1552 1553 if (!SOC_IS_TOMAHAWKX(unit)) { 1554 return rv; 1555 } 1556 #endif 1557 1558 return rv; 1559 #if 0 1560 if (SOC_URPF_STATUS_GET(unit)) { 1561 urpf = 1; 1562 } 1563 1564 rv = bcm_xgs3_l3_tbl_dma(unit, mem, 1565 sizeof(defip_aux_table_entry_t), "aux_tbl", 1566 &aux_tbl_ptr, &defip_table_size); 1567 if (BCM_FAILURE(rv)) { 1568 goto cleanup; 1569 } 1570 1571 for (i = 0; i < defip_table_size; i++) { 1572 aux_entry = soc_mem_table_idx_to_pointer(unit, mem, 1573 defip_aux_table_entry_t *, aux_tbl_ptr, i); 1574 if (urpf && i >= defip_table_size / 2) { 1575 is_urpf_entry = 1; 1576 } else { 1577 is_urpf_entry = 0; 1578 } 1579 1580 /* Entry 0 */ 1581 valid = soc_mem_field32_get(unit, mem, aux_entry, VALID0f); 1582 if (valid) { 1583 vrf = soc_mem_field32_get(unit, mem, aux_entry, VRF0f); 1584 db_type = soc_mem_field32_get(unit, mem, aux_entry, DB_TYPE0f); 1585 if (db_type > 0) { /* > 0 means Private routes */ 1586 soc_alpm_db_ent_type_encoding(unit, vrf, &ndb_type, &nent_type); 1587 if (is_urpf_entry) { 1588 ndb_type ++; 1589 } 1590 /* Old value is only 2(3), new value could be 4(5), 6(7) */ 1591 if (db_type != ndb_type) { 1592 soc_mem_field32_set(unit, mem, aux_entry, DB_TYPE0f, ndb_type); 1593 soc_mem_field32_set(unit, mem, aux_entry, ENTRY_TYPE0_f(unit), nent_type); 1594 updated = 1; 1595 } 1596 } 1597 } 1598 1599 /* Entry 1 */ 1600 valid = soc_mem_field32_get(unit, mem, aux_entry, VALID1f); 1601 if (valid) { 1602 vrf = soc_mem_field32_get(unit, mem, aux_entry, VRF1f); 1603 db_type = soc_mem_field32_get(unit, mem, aux_entry, DB_TYPE1f); 1604 if (db_type > 0) { /* > 0 means Private routes */ 1605 soc_alpm_db_ent_type_encoding(unit, vrf, &ndb_type, &nent_type); 1606 if (is_urpf_entry) { 1607 ndb_type ++; 1608 } 1609 /* Old value is only 2(3), new value could be 4(5), 6(7) */ 1610 if (db_type != ndb_type) { 1611 soc_mem_field32_set(unit, mem, aux_entry, DB_TYPE1f, ndb_type); 1612 soc_mem_field32_set(unit, mem, aux_entry, ENTRY_TYPE1_f(unit), nent_type); 1613 updated = 1; 1614 } 1615 } 1616 } 1617 } 1618 1619 if (updated) { 1620 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL, 1621 soc_mem_index_min(unit, mem), 1622 soc_mem_index_max(unit, mem), aux_tbl_ptr); 1623 } 1624 1625 cleanup: 1626 if (aux_tbl_ptr) { 1627 soc_cm_sfree(unit, aux_tbl_ptr); 1628 } 1629 return rv; 1630 #endif 1631 } 1632 1633 /* 1634 * Function: 1635 * _bcm_th_alpm_warmboot_walk 1636 * Purpose: 1637 * Recover LPM and ALPM entries 1638 * Parameters: 1639 * unit - (IN)SOC unit number. 1640 * trv_data - (IN)pattern + compare,act,notify routines. 1641 * Returns: 1642 * BCM_E_XXX 1643 */ 1644 STATIC int 1645 _bcm_th_alpm_warmboot_walk(int unit, _bcm_l3_trvrs_data_t *trv_data) 1646 { 1647 int ipv6; /* IPv6 flag. */ 1648 int idx; /* Iteration index. */ 1649 int tmp_idx; /* IPv4 entries iterator. */ 1650 int vrf, vrf_id; /* */ 1651 int idx_end; /* */ 1652 int bkt_addr; /* */ 1653 int bkt_count; /* */ 1654 int bkti = 0; /* */ 1655 int bkt_ptr2, bkt_ptr = 0; /* Bucket pointer */ 1656 int sub_bkt_idx = 0; /* Sub bucket pointer */ 1657 int bank_num = 0; /* Number of active SRAM banks */ 1658 int pivot_idx = 0; /* Pivot Index */ 1659 int entry_num = 0; /* ALPM entry number in bucket */ 1660 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 1661 int entry_count; /* ALPM entry count in bucket */ 1662 int bank_count; /* SRAM bank count */ 1663 int step_count; /* */ 1664 int cmp_result; /* Test routine result. */ 1665 int rv = BCM_E_FAIL; /* Operation return status. */ 1666 int defip_table_size = 0; /* Defip table size. */ 1667 char *lpm_tbl_ptr = NULL; /* DMA table pointer. */ 1668 void *alpm_entry = NULL; /* */ 1669 soc_mem_t alpm_mem; /* */ 1670 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 1671 defip_entry_t *lpm_entry; /* Hw entry buffer. */ 1672 int bank_bits; /* 2 bank mode, or 4 bank mode */ 1673 uint32 bank_disable; /* Bank disable mask */ 1674 int ipmc_route = 0; /* Route is ip multicast type */ 1675 int flex = 0; /* Route can be with stat flex */ 1676 int alpm_bkt_bits = ALPM_CTRL(unit).bkt_bits; 1677 1678 defip_alpm_ipv4_1_entry_t alpm_entry_v4; 1679 defip_alpm_ipv6_64_1_entry_t alpm_entry_v6_64; 1680 defip_entry_t local_lpm_entry; 1681 int bkt_ptr_tmp = 0; 1682 uint8 bkt_occupied = 0; 1683 1684 _bcm_th_alpm_warmboot_db_type_update(unit); 1685 1686 /* DMA LPM table to software copy */ 1687 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 1688 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 1689 &lpm_tbl_ptr, &defip_table_size); 1690 if (BCM_FAILURE(rv)) { 1691 goto free_lpm_table; 1692 } 1693 1694 if (SOC_URPF_STATUS_GET(unit)) { 1695 defip_table_size >>= 1; 1696 } 1697 1698 idx_end = defip_table_size; 1699 bank_count = ALPM_CTRL(unit).num_banks; 1700 bank_bits = ALPM_CTRL(unit).bank_bits; 1701 1702 /* Walk all lpm entries */ 1703 for (idx = 0; idx < idx_end; idx++) { 1704 /* Calculate entry ofset */ 1705 lpm_entry = 1706 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 1707 defip_entry_t *, lpm_tbl_ptr, idx); 1708 1709 /* Avoid to modify the Hw entry buffer*/ 1710 sal_memcpy(&local_lpm_entry, lpm_entry, sizeof(defip_entry_t)); 1711 1712 lpm_entry = &local_lpm_entry; 1713 1714 ipv6 = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit)); 1715 1716 /* Calculate LPM table traverse step count */ 1717 step_count = ipv6 ? 1 : 2; 1718 1719 /* Insert LPM entry into HASH table and init LPM trackers */ 1720 if (soc_th_alpm_warmboot_lpm_reinit(unit, ipv6, idx, lpm_entry) < 0) { 1721 goto free_lpm_table; 1722 } 1723 1724 bkt_occupied = 0; 1725 1726 /* 1727 * This loop is used for two purposes 1728 * 1. IPv4, DEFIP entry has two IPv4 entries. 1729 * 2. IPv6 double wide mode, walk next bucket. 1730 */ 1731 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 1732 if (tmp_idx) { /* If index == 1 */ 1733 /* Copy upper half of lpm entry to lower half */ 1734 soc_th_alpm_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE); 1735 1736 /* Invalidate upper half */ 1737 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 0); 1738 } 1739 1740 /* Make sure entry is valid. */ 1741 if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) { 1742 continue; 1743 } 1744 1745 /* Extract bucket pointer from LPM entry */ 1746 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 1747 ALG_BKT_PTR0f); 1748 bkt_ptr_tmp = bkt_ptr; 1749 1750 if (ALPM_CTRL(unit).bkt_sharing) { 1751 sub_bkt_idx = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 1752 ALG_SUB_BKT_PTR0f); 1753 } 1754 1755 if (soc_feature(unit, soc_feature_ipmc_defip)) { 1756 /* Skip reserved ipmc entry */ 1757 int ipmc_index = 0; 1758 ipmc_route = 0; 1759 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 1760 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 1761 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 1762 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 1763 ipmc_route = 1; 1764 } else { 1765 ipmc_route = 0; 1766 } 1767 } 1768 1769 if (soc_feature(unit, soc_feature_generic_dest)) { 1770 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1771 uint32 dest_value = 0; 1772 dest_value = soc_mem_field32_dest_get(unit, 1773 L3_DEFIPm, lpm_entry, 1774 DESTINATION0f, &dest_type); 1775 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 1776 ipmc_index = dest_value; 1777 } else { 1778 ipmc_index = 0; 1779 } 1780 } else { 1781 ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm, 1782 lpm_entry, L3MC_INDEX0f); 1783 } 1784 1785 if (ipmc_route && (ipmc_index == 0)) { 1786 continue; 1787 } 1788 } 1789 1790 /* Extract VRF from LPM entry*/ 1791 if (soc_th_alpm_lpm_vrf_get(unit, lpm_entry, &vrf_id, &vrf) < 0) { 1792 goto free_lpm_table; 1793 } 1794 bank_disable = 1795 ALPM_CTRL(unit).bank_disable_bmp_8b[vrf != (SOC_VRF_MAX(unit) + 1)]; 1796 1797 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 1798 * resides in TCAM */ 1799 if (bkt_ptr == 0) { 1800 VRF_TRIE_ROUTES_INC(unit, vrf_id, vrf, ipv6); 1801 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 1802 _bcm_th_alpm_lpm_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 1803 lpm_entry); 1804 _bcm_th_alpm_lpm_key_parse(unit, &lpm_cfg, lpm_entry); 1805 lpm_cfg.defip_index = idx; 1806 1807 if (!!ipv6 == !!(lpm_cfg.defip_flags & BCM_L3_IP6)) { 1808 if (trv_data->op_cb) { 1809 (void) (*trv_data->op_cb)(unit, (void *)trv_data, 1810 (void *)&lpm_cfg, 1811 (void *)&nh_ecmp_idx, 1812 &cmp_result); 1813 } 1814 } 1815 continue; 1816 } 1817 1818 pivot_idx = (idx << 1) + tmp_idx; 1819 1820 /* TCAM pivot recovery */ 1821 if (soc_th_alpm_warmboot_pivot_add(unit, ipv6, lpm_entry, 1822 pivot_idx, ALPM_LOG_BKT(bkt_ptr, sub_bkt_idx)) < 0) { 1823 goto free_lpm_table; 1824 } 1825 1826 /* Set bucket bitmap */ 1827 if (soc_th_alpm_warmboot_bucket_bitmap_set(unit, vrf, ipv6, bkt_ptr) < 0) { 1828 goto free_lpm_table; 1829 } 1830 1831 flex = _soc_th_alpm_lpm_flex_get(unit, ipv6, 1832 soc_mem_field32_get(unit, L3_DEFIPm, 1833 lpm_entry, ENTRY_VIEW0f)); 1834 if (ipv6) { 1835 if (flex) { 1836 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m; 1837 entry_count = 3; 1838 alpm_entry = &alpm_entry_v6_64; 1839 } else { 1840 alpm_mem = L3_DEFIP_ALPM_IPV6_64m; 1841 entry_count = 4; 1842 alpm_entry = &alpm_entry_v6_64; 1843 } 1844 1845 } else { 1846 if (flex) { 1847 alpm_mem = L3_DEFIP_ALPM_IPV4_1m; 1848 entry_count = 4; 1849 alpm_entry = &alpm_entry_v4; 1850 } else { 1851 alpm_mem = L3_DEFIP_ALPM_IPV4m; 1852 entry_count = 6; 1853 alpm_entry = &alpm_entry_v4; 1854 } 1855 } 1856 bkt_count = _soc_th_alpm_bkt_entry_cnt(unit, alpm_mem); 1857 1858 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 1859 1860 /* Get the bucket pointer from lpm entry */ 1861 bkt_ptr2 = bkt_ptr; 1862 entry_num = 0; 1863 for (bkti = 0; bkti < bkt_count; bkti++) { 1864 /* Calculate bucket memory address */ 1865 /* Increment so next bucket address can be calculated */ 1866 bkt_addr = (entry_num << (bank_bits + alpm_bkt_bits)) | 1867 (bkt_ptr2 << bank_bits) | 1868 (bank_num & ((1U << bank_bits) - 1)); 1869 1870 entry_num++; 1871 if (entry_num == entry_count) { 1872 entry_num = 0; 1873 ALPM_NEXT_AVAIL_BANK(bank_num, bank_count, bank_disable); 1874 if (bank_num == bank_count) { 1875 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 1876 bkt_ptr2 ++; 1877 } 1878 } 1879 1880 /* Read entry from bucket memory */ 1881 if (soc_mem_read_no_cache(unit, 0, alpm_mem, 0, MEM_BLOCK_ANY, 1882 bkt_addr, alpm_entry) < 0) { 1883 goto free_lpm_table; 1884 } 1885 1886 bkt_occupied = 1; 1887 1888 /* Check if ALPM entry is valid */ 1889 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 1890 continue; 1891 } 1892 1893 if (ALPM_CTRL(unit).bkt_sharing && sub_bkt_idx != 1894 soc_mem_field32_get(unit, alpm_mem, alpm_entry, SUB_BKT_PTRf)) { 1895 continue; 1896 } 1897 1898 /* Zero destination buffer first. */ 1899 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 1900 1901 /* Parse the entry. */ 1902 _bcm_th_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 1903 alpm_mem, alpm_entry); 1904 1905 /* Execute operation routine if any. */ 1906 if (trv_data->op_cb) { 1907 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 1908 (void *)&lpm_cfg, 1909 (void *)&nh_ecmp_idx, &cmp_result); 1910 #ifdef BCM_CB_ABORT_ON_ERR 1911 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 1912 continue; 1913 } 1914 #endif 1915 } 1916 1917 if (soc_th_alpm_warmboot_prefix_insert(unit, ipv6, flex, lpm_entry, 1918 alpm_entry, pivot_idx, 1919 ALPM_LOG_BKT(bkt_ptr, sub_bkt_idx), 1920 bkt_addr) < 0) { 1921 continue; 1922 } 1923 1924 } /* End of bucket walk loop*/ 1925 if (bkt_occupied) { 1926 /* If double wide, two alpm bkt views should be set */ 1927 if (SOC_TH_ALPM_SCALE_CHECK(unit, ipv6)) { 1928 soc_alpm_cmn_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 1929 soc_alpm_cmn_bkt_view_set(unit, (bkt_ptr_tmp + 1) << 2, alpm_mem); 1930 } else { 1931 soc_alpm_cmn_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 1932 } 1933 } 1934 } /* End of lpm entry upper/lower half traversal */ 1935 } /* End of lpm table traversal */ 1936 1937 1938 /* Update bpm_len of pivot after perfix trie is restored */ 1939 for (idx = 0; idx < idx_end; idx++) { 1940 /* Calculate entry ofset */ 1941 lpm_entry = 1942 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 1943 defip_entry_t *, lpm_tbl_ptr, idx); 1944 1945 ipv6 = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit)); 1946 1947 /* Calculate LPM table traverse step count */ 1948 step_count = ipv6 ? 1 : 2; 1949 1950 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 1951 if (tmp_idx) { 1952 /* Copy upper half of lpm entry to lower half */ 1953 (void) soc_th_alpm_lpm_ip4entry1_to_0(unit, lpm_entry, 1954 lpm_entry, TRUE); 1955 /* Invalidate upper half */ 1956 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 0); 1957 } 1958 1959 /* Make sure entry is valid. */ 1960 if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) { 1961 continue; 1962 } 1963 1964 if (soc_feature(unit, soc_feature_ipmc_defip)) { 1965 /* Skip reserved ipmc entry */ 1966 int ipmc_index = 0; 1967 ipmc_route = 0; 1968 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 1969 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f); 1970 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 1971 if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) { 1972 ipmc_route = 1; 1973 } else { 1974 ipmc_route = 0; 1975 } 1976 } 1977 1978 if (soc_feature(unit, soc_feature_generic_dest)) { 1979 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1980 uint32 dest_value = 0; 1981 dest_value = soc_mem_field32_dest_get(unit, 1982 L3_DEFIPm, lpm_entry, 1983 DESTINATION0f, &dest_type); 1984 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 1985 ipmc_index = dest_value; 1986 } else { 1987 ipmc_index = 0; 1988 } 1989 } else { 1990 ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm, 1991 lpm_entry, L3MC_INDEX0f); 1992 } 1993 1994 if (ipmc_route && (ipmc_index == 0)) { 1995 continue; 1996 } 1997 } 1998 1999 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 2000 * resides in TCAM */ 2001 if(soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 2002 ALG_BKT_PTR0f) == 0) { 2003 continue; 2004 } 2005 2006 pivot_idx = (idx << 1) + tmp_idx; 2007 2008 /* TCAM pivot recovery */ 2009 if (soc_th_alpm_warmboot_pivot_bmp_len_update( 2010 unit, ipv6, lpm_entry, pivot_idx) < 0) { 2011 goto free_lpm_table; 2012 } 2013 } 2014 } 2015 2016 if (soc_th_alpm_warmboot_lpm_reinit_done(unit) < 0) { 2017 goto free_lpm_table; 2018 } 2019 2020 #ifdef ALPM_WARM_BOOT_DEBUG 2021 soc_alpm_lpm_sw_dump(unit); 2022 #endif /* ALPM_WARM_BOOT_DEBUG */ 2023 2024 rv = BCM_E_NONE; 2025 2026 free_lpm_table: 2027 if (lpm_tbl_ptr) { 2028 soc_cm_sfree(unit, lpm_tbl_ptr); 2029 } 2030 2031 return (rv); 2032 } 2033 2034 /* 2035 * Function: 2036 * _bcm_th_alpm_128_warmboot_walk 2037 * Purpose: 2038 * Recover IPv6-128Bit LPM and ALPM entries 2039 * Parameters: 2040 * unit - (IN)SOC unit number. 2041 * trv_data - (IN)pattern + compare,act,notify routines. 2042 * Returns: 2043 * BCM_E_XXX 2044 */ 2045 STATIC int 2046 _bcm_th_alpm_128_warmboot_walk(int unit, _bcm_l3_trvrs_data_t *trv_data) 2047 { 2048 int ipv6 = 2; /* IPv6 flag. */ 2049 int idx; /* Iteration index. */ 2050 int tmp_idx; /* IPv4 entries iterator. */ 2051 int vrf, vrf_id; /* */ 2052 int idx_end; /* */ 2053 int bkt_addr; /* */ 2054 int bkt_count; /* */ 2055 int bkti = 0; /* */ 2056 int bkt_ptr2, bkt_ptr = 0; /* Bucket pointer */ 2057 int sub_bkt_idx = 0; /* Sub bucket pointer */ 2058 int bank_num = 0; /* Number of active SRAM banks */ 2059 int entry_num = 0; /* ALPM entry number in bucket */ 2060 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 2061 int entry_count; /* ALPM entry count in bucket */ 2062 int bank_count; /* SRAM bank count */ 2063 int step_count = 1; /* */ 2064 int cmp_result; /* Test routine result. */ 2065 int rv = BCM_E_FAIL; /* Operation return status. */ 2066 int defip_table_size = 0; /* Defip table size. */ 2067 char *lpm_tbl_ptr = NULL; /* DMA table pointer. */ 2068 void *alpm_entry = NULL; /* */ 2069 uint32 rval; /* */ 2070 soc_mem_t alpm_mem; /* */ 2071 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 2072 int bank_bits; /* 2 bank mode, or 4 bank mode */ 2073 uint32 bank_disable; /* Bank disable mask */ 2074 int alpm_bkt_bits = ALPM_CTRL(unit).bkt_bits; 2075 2076 defip_pair_128_entry_t *lpm_entry; /* Hw entry buffer. */ 2077 defip_alpm_ipv6_128_entry_t alpm_entry_v6_128; /* ALPM 128 */ 2078 int ipmc_route = 0; /* Route is ip multicast type */ 2079 int bkt_ptr_tmp = 0; 2080 uint8 bkt_occupied = 0; 2081 2082 /* DMA LPM table to software copy */ 2083 rv = bcm_xgs3_l3_tbl_dma(unit, L3_DEFIP_PAIR_128m, 2084 WORDS2BYTES(soc_mem_entry_words(unit, L3_DEFIP_PAIR_128m)), 2085 "lpm_128_warmboot_tbl", 2086 &lpm_tbl_ptr, &defip_table_size); 2087 if (BCM_FAILURE(rv)) { 2088 goto free_lpm_table; 2089 } 2090 2091 if(BCM_FAILURE(READ_L3_DEFIP_RPF_CONTROLr(unit, &rval))) { 2092 goto free_lpm_table; 2093 } 2094 2095 if (SOC_URPF_STATUS_GET(unit)) { 2096 defip_table_size >>= 1; 2097 } 2098 2099 idx_end = defip_table_size; 2100 alpm_mem = L3_DEFIP_ALPM_IPV6_128m; 2101 alpm_entry = &alpm_entry_v6_128; 2102 entry_count = 2; 2103 bank_count = ALPM_CTRL(unit).num_banks; 2104 bank_bits = ALPM_CTRL(unit).bank_bits; 2105 bkt_count = _soc_th_alpm_bkt_entry_cnt(unit, alpm_mem); 2106 2107 /* Walk all lpm entries */ 2108 for (idx = 0; idx < idx_end; idx++) { 2109 /* Calculate entry ofset */ 2110 lpm_entry = 2111 soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 2112 defip_pair_128_entry_t *, lpm_tbl_ptr, idx); 2113 2114 /* Verify if read LPM entry is IPv6-128 entry */ 2115 if (0x03 != soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2116 MODE1_UPR_f(unit))) { 2117 continue; 2118 }; 2119 2120 /* Verify if LPM entry is valid */ 2121 if (!soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2122 VALID1_LWRf) || 2123 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2124 VALID0_LWRf) || 2125 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2126 VALID1_UPRf) || 2127 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2128 VALID0_UPRf)) { 2129 continue; 2130 }; 2131 2132 /* Insert LPM entry into HASH table and init LPM trackers */ 2133 if (soc_th_alpm_128_warmboot_lpm_reinit(unit, ipv6, idx, lpm_entry) < 0) { 2134 goto free_lpm_table; 2135 } 2136 2137 bkt_occupied = 0; 2138 2139 /* If IPv6 double wide mode, walk next bucket.*/ 2140 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 2141 /* Extract bucket pointer from LPM entry */ 2142 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2143 ALG_BKT_PTRf); 2144 bkt_ptr_tmp = bkt_ptr; 2145 if (ALPM_CTRL(unit).bkt_sharing) { 2146 sub_bkt_idx = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2147 lpm_entry, ALG_SUB_BKT_PTRf); 2148 } else { 2149 sub_bkt_idx = 0; 2150 } 2151 2152 if (soc_feature(unit, soc_feature_ipmc_defip)) { 2153 /* Skip reserved ipmc entry */ 2154 int ipmc_index = 0; 2155 ipmc_route = 0; 2156 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 2157 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2158 lpm_entry, MULTICAST_ROUTEf); 2159 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 2160 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2161 lpm_entry, DATA_TYPEf) == 2) { 2162 ipmc_route = 1; 2163 } else { 2164 ipmc_route = 0; 2165 } 2166 } 2167 2168 if (soc_feature(unit, soc_feature_generic_dest)) { 2169 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 2170 uint32 dest_value = 0; 2171 dest_value = soc_mem_field32_dest_get(unit, 2172 L3_DEFIP_PAIR_128m, lpm_entry, 2173 DESTINATIONf, &dest_type); 2174 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 2175 ipmc_index = dest_value; 2176 } else { 2177 ipmc_index = 0; 2178 } 2179 } else { 2180 ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2181 lpm_entry, L3MC_INDEXf); 2182 } 2183 2184 if (ipmc_route && ipmc_index == 0) { 2185 continue; 2186 } 2187 } 2188 2189 /* Extract VRF from LPM entry*/ 2190 if (soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, &vrf_id, &vrf) < 0) { 2191 goto free_lpm_table; 2192 } 2193 2194 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 2195 * resides in TCAM */ 2196 if (bkt_ptr == 0) { 2197 VRF_TRIE_ROUTES_INC(unit, vrf_id, vrf, ipv6); 2198 2199 /* TCAM Routes Processing */ 2200 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 2201 (void) _bcm_th_alpm_lpm128_key_parse(unit, (uint32 *)lpm_entry, 2202 &lpm_cfg); 2203 (void) soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, 2204 &lpm_cfg.defip_vrf, &nh_ecmp_idx); 2205 _bcm_th_alpm_lpm128_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 2206 lpm_entry); 2207 lpm_cfg.defip_index = idx; 2208 if (trv_data->op_cb) { 2209 (void) (*trv_data->op_cb)(unit, (void *)trv_data, 2210 (void *)&lpm_cfg, 2211 (void *)&nh_ecmp_idx, &cmp_result); 2212 } 2213 continue; 2214 } 2215 2216 bank_disable = 2217 ALPM_CTRL(unit).bank_disable_bmp_8b[vrf != (SOC_VRF_MAX(unit) + 1)]; 2218 2219 /* TCAM pivot recovery */ 2220 if (soc_th_alpm_128_warmboot_pivot_add(unit, ipv6, lpm_entry, 2221 idx, ALPM_LOG_BKT(bkt_ptr, sub_bkt_idx)) < 0) { 2222 goto free_lpm_table; 2223 } 2224 2225 /* Set bucket bitmap */ 2226 if (soc_th_alpm_128_warmboot_bucket_bitmap_set(unit, vrf, ipv6, 2227 bkt_ptr) < 0) { 2228 goto free_lpm_table; 2229 } 2230 2231 2232 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 2233 2234 entry_num = 0; 2235 bkt_ptr2 = bkt_ptr; 2236 /* Get the bucket pointer from lpm entry */ 2237 for (bkti = 0; bkti < bkt_count; bkti++) { 2238 /* calculate bucket memory address */ 2239 /* also increment so next bucket address can be calculated */ 2240 bkt_addr = (entry_num << (bank_bits + alpm_bkt_bits)) | 2241 (bkt_ptr2 << bank_bits) | 2242 (bank_num & ((1U << bank_bits) - 1)); 2243 2244 entry_num++; 2245 if (entry_num == entry_count) { 2246 entry_num = 0; 2247 ALPM_NEXT_AVAIL_BANK(bank_num, bank_count, bank_disable); 2248 if (bank_num == bank_count) { 2249 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 2250 bkt_ptr2 ++; 2251 } 2252 } 2253 2254 /* Read entry from bucket memory */ 2255 if (soc_mem_read_no_cache(unit, 0, alpm_mem, 0, MEM_BLOCK_ANY, 2256 bkt_addr, alpm_entry) < 0) { 2257 goto free_lpm_table; 2258 } 2259 2260 /* 2261 * In Tomahawk URPF mode, valid bits will make sure 2262 * SIP entries in buckets are included in this walk 2263 */ 2264 2265 /* Check if ALPM entry is valid */ 2266 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 2267 continue; 2268 } 2269 if (ALPM_CTRL(unit).bkt_sharing && sub_bkt_idx != 2270 soc_mem_field32_get(unit, alpm_mem, alpm_entry, SUB_BKT_PTRf)) { 2271 continue; 2272 } 2273 2274 bkt_occupied = 1; 2275 2276 /* Zero destination buffer first. */ 2277 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 2278 2279 2280 /* Fill entry IP address and subnet mask. */ 2281 _bcm_th_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, 2282 &lpm_cfg); 2283 2284 (void)soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, &vrf); 2285 /* get associated data */ 2286 _bcm_th_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, 2287 &lpm_cfg, &nh_ecmp_idx); 2288 2289 /* Execute operation routine if any. */ 2290 if (trv_data->op_cb) { 2291 rv = (*trv_data->op_cb)(unit, (void *)trv_data, 2292 (void *)&lpm_cfg, 2293 (void *)&nh_ecmp_idx, &cmp_result); 2294 #ifdef BCM_CB_ABORT_ON_ERR 2295 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2296 continue; 2297 } 2298 #endif 2299 } 2300 2301 if (soc_th_alpm_128_warmboot_prefix_insert(unit, ipv6, lpm_entry, 2302 alpm_entry, idx, ALPM_LOG_BKT(bkt_ptr, sub_bkt_idx), 2303 bkt_addr) < 0) { 2304 continue; 2305 } 2306 2307 } /* End of bucket walk loop*/ 2308 if (bkt_occupied) { 2309 /* If double wide, two alpm bkt views should be set */ 2310 if (SOC_TH_ALPM_SCALE_CHECK(unit, ipv6)) { 2311 soc_alpm_cmn_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 2312 soc_alpm_cmn_bkt_view_set(unit, (bkt_ptr_tmp + 1) << 2, alpm_mem); 2313 } else { 2314 soc_alpm_cmn_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem); 2315 } 2316 } 2317 } /* End of lpm entry upper/lower half traversal */ 2318 } /* End of lpm table traversal */ 2319 2320 /* Update bpm_len of pivot after perfix trie is restored */ 2321 for (idx = 0; idx < idx_end; idx++) { 2322 /* Calculate entry ofset */ 2323 lpm_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 2324 defip_pair_128_entry_t *, 2325 lpm_tbl_ptr, idx); 2326 2327 /* Verify if read LPM entry is IPv6-128 entry */ 2328 if (0x03 != soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2329 lpm_entry, MODE1_UPR_f(unit))) { 2330 continue; 2331 } 2332 2333 /* Verify if LPM entry is valid */ 2334 if (!soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2335 lpm_entry, VALID1_LWRf) || 2336 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2337 lpm_entry, VALID0_LWRf) || 2338 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2339 lpm_entry, VALID1_UPRf) || 2340 !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2341 lpm_entry, VALID0_UPRf)) { 2342 continue; 2343 } 2344 2345 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 2346 if (soc_feature(unit, soc_feature_ipmc_defip)) { 2347 /* Skip reserved ipmc entry */ 2348 int ipmc_index = 0; 2349 ipmc_route = 0; 2350 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 2351 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2352 lpm_entry, MULTICAST_ROUTEf); 2353 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 2354 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2355 lpm_entry, DATA_TYPEf) == 2) { 2356 ipmc_route = 1; 2357 } else { 2358 ipmc_route = 0; 2359 } 2360 } 2361 2362 if (soc_feature(unit, soc_feature_generic_dest)) { 2363 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 2364 uint32 dest_value = 0; 2365 dest_value = soc_mem_field32_dest_get(unit, 2366 L3_DEFIP_PAIR_128m, lpm_entry, 2367 DESTINATIONf, &dest_type); 2368 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 2369 ipmc_index = dest_value; 2370 } else { 2371 ipmc_index = 0; 2372 } 2373 } else { 2374 ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2375 lpm_entry, L3MC_INDEXf); 2376 } 2377 2378 if ((ipmc_route) && ipmc_index == 0) { 2379 continue; 2380 } 2381 } 2382 2383 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 2384 * resides in TCAM */ 2385 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 2386 ALG_BKT_PTRf) == 0) { 2387 continue; 2388 } 2389 2390 /* TCAM pivot recovery */ 2391 if (soc_th_alpm_128_warmboot_pivot_bmp_len_update( 2392 unit, ipv6, lpm_entry, idx) < 0) { 2393 goto free_lpm_table; 2394 } 2395 } 2396 } 2397 2398 if (soc_th_alpm_128_warmboot_lpm_reinit_done(unit) < 0) { 2399 goto free_lpm_table; 2400 } 2401 2402 #ifdef ALPM_WARM_BOOT_DEBUG 2403 soc_alpm_lpm_sw_dump(unit); 2404 #endif /* ALPM_WARM_BOOT_DEBUG */ 2405 2406 rv = BCM_E_NONE; 2407 free_lpm_table: 2408 if (lpm_tbl_ptr) { 2409 soc_cm_sfree(unit, lpm_tbl_ptr); 2410 } 2411 2412 return (rv); 2413 } 2414 2415 STATIC int 2416 _bcm_th_alpm_128_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 2417 { 2418 uint32 ipv6; /* Iterate over ipv6 only flag. */ 2419 int idx; /* Iteration index. */ 2420 int tmp_idx; /* ipv4 entries iterator. */ 2421 char *lpm_tbl_ptr; /* Dma table pointer. */ 2422 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 2423 int cmp_result; /* Test routine result. */ 2424 defip_pair_128_entry_t *lpm_entry = NULL; /* Hw entry buffer. */ 2425 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 2426 int defip_table_size; /* Defip table size. */ 2427 int rv = BCM_E_NONE; /* Operation return status. */ 2428 int idx_start = 0; 2429 int idx_end = 0, bkt_idx, bkt_count, bkt_ptr = 0, bkt_addr; 2430 int entry_num, bank_num, entry_count, bank_count, bank_bits; 2431 defip_alpm_ipv6_128_entry_t alpm_entry_v6_128; 2432 void *alpm_entry; 2433 soc_mem_t alpm_mem, pivot_mem = L3_DEFIP_PAIR_128m; 2434 int step_count = 1; 2435 int def_arr_idx = 0; 2436 int def_rte_arr_sz; 2437 typedef struct _alpm_def_route_info_s { 2438 int idx; 2439 int bkt_addr; 2440 } _alpm_def_route_info_t; 2441 _alpm_def_route_info_t *def_rte_arr = NULL; 2442 int sub_bkt = 0; 2443 uint32 bank_disable; 2444 int alpm_bkt_bits = ALPM_CTRL(unit).bkt_bits; 2445 2446 ipv6 = (trv_data->flags & BCM_L3_IP6); 2447 if (!ipv6) { 2448 return SOC_E_NONE; 2449 } 2450 2451 /* LPM table DMA to software copy if callback is not for 'delete all' */ 2452 rv = bcm_xgs3_l3_tbl_dma(unit, L3_DEFIP_PAIR_128m, 2453 WORDS2BYTES(soc_mem_entry_words(unit, L3_DEFIP_PAIR_128m)), 2454 "lpm_128_tbl", &lpm_tbl_ptr, &defip_table_size); 2455 if (BCM_FAILURE(rv)) { 2456 goto cleanup; 2457 } 2458 2459 /* Allocate memory to store default route meta data*/ 2460 def_rte_arr_sz = SOC_VRF_MAX(unit) * sizeof(_alpm_def_route_info_t); 2461 def_rte_arr = sal_alloc(def_rte_arr_sz, "alpm_def_rte_arry"); 2462 if (NULL == def_rte_arr) { 2463 rv = BCM_E_MEMORY; 2464 goto cleanup; 2465 } 2466 sal_memset(def_rte_arr, 0, def_rte_arr_sz); 2467 2468 if (SOC_URPF_STATUS_GET(unit)) { 2469 defip_table_size >>= 1; 2470 } 2471 2472 idx_end = defip_table_size; 2473 alpm_mem = L3_DEFIP_ALPM_IPV6_128m; 2474 idx_start = 0; 2475 bank_num = 0; 2476 entry_num = 0; 2477 bank_count = ALPM_CTRL(unit).num_banks; 2478 entry_count = 2; 2479 alpm_entry = &alpm_entry_v6_128; 2480 bank_bits = ALPM_CTRL(unit).bank_bits; 2481 bkt_count = _soc_th_alpm_bkt_entry_cnt(unit, alpm_mem); 2482 2483 /* if v6 loop twice once with with defip and once with defip_pair */ 2484 for (idx = (idx_end - 1); idx >= idx_start; idx--) { 2485 2486 /* Calculate entry ofset. */ 2487 lpm_entry = 2488 soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 2489 defip_pair_128_entry_t *, lpm_tbl_ptr, idx); 2490 2491 /* Make sure entry is valid. */ 2492 if (!soc_mem_field32_get(unit, pivot_mem, lpm_entry, VALID0_LWRf)) { 2493 continue; 2494 } 2495 2496 /* Skip reserved ipmc entry */ 2497 if (soc_feature(unit, soc_feature_ipmc_defip)) { 2498 /* Skip reserved ipmc entry */ 2499 int ipmc_route = 0; 2500 int ipmc_index = 0; 2501 if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) { 2502 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2503 lpm_entry, MULTICAST_ROUTEf); 2504 } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) { 2505 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2506 lpm_entry, DATA_TYPEf) == 2) { 2507 ipmc_route = 1; 2508 } else { 2509 ipmc_route = 0; 2510 } 2511 } 2512 2513 if (soc_feature(unit, soc_feature_generic_dest)) { 2514 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 2515 uint32 dest_value = 0; 2516 dest_value = soc_mem_field32_dest_get(unit, 2517 L3_DEFIP_PAIR_128m, lpm_entry, 2518 DESTINATIONf, &dest_type); 2519 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 2520 ipmc_index = dest_value; 2521 } else { 2522 ipmc_index = 0; 2523 } 2524 } else { 2525 ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, 2526 lpm_entry, L3MC_INDEXf); 2527 } 2528 2529 if (ipmc_route && ipmc_index == 0) { 2530 continue; 2531 } 2532 } 2533 for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) { 2534 bkt_ptr = soc_mem_field32_get(unit, pivot_mem, lpm_entry, ALG_BKT_PTRf); 2535 if (ALPM_CTRL(unit).bkt_sharing) { 2536 sub_bkt = soc_mem_field32_get(unit, pivot_mem, lpm_entry, ALG_SUB_BKT_PTRf); 2537 } 2538 (void)soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 2539 &cmp_result); 2540 bank_disable = 2541 ALPM_CTRL(unit).bank_disable_bmp_8b[cmp_result != (SOC_VRF_MAX(unit) + 1)]; 2542 2543 if (bkt_ptr == 0) { 2544 2545 /* OVERRIDE VRF Processing */ 2546 2547 (void) _bcm_th_alpm_lpm128_key_parse(unit, (uint32 *) lpm_entry, 2548 &lpm_cfg); 2549 /* defip_vrf adjust */ 2550 (void) soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, 2551 &lpm_cfg.defip_vrf, &nh_ecmp_idx); 2552 _bcm_th_alpm_lpm128_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 2553 lpm_entry); 2554 2555 lpm_cfg.defip_index = idx; 2556 2557 if (trv_data->op_cb) { 2558 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 2559 (void *)&lpm_cfg, 2560 (void *)&nh_ecmp_idx, &cmp_result); 2561 #ifdef BCM_CB_ABORT_ON_ERR 2562 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2563 break; 2564 } 2565 #endif 2566 } 2567 2568 continue; 2569 } 2570 2571 entry_num = 0; 2572 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 2573 2574 /* get the bucket pointer from lpm mem entry */ 2575 for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) { 2576 /* calculate bucket memory address */ 2577 /* also increment so next bucket address can be calculated */ 2578 bkt_addr = (entry_num << (bank_bits + alpm_bkt_bits)) | 2579 (bkt_ptr << bank_bits) | 2580 (bank_num & ((1U << bank_bits) - 1)); 2581 2582 entry_num++; 2583 if (entry_num == entry_count) { 2584 entry_num = 0; 2585 ALPM_NEXT_AVAIL_BANK(bank_num, bank_count, bank_disable); 2586 if (bank_num == bank_count) { 2587 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 2588 bkt_ptr ++; 2589 } 2590 } 2591 2592 /* read entry from bucket memory */ 2593 rv = soc_mem_read_no_cache(unit, 0, alpm_mem, 0, MEM_BLOCK_ANY, 2594 bkt_addr, alpm_entry); 2595 if (SOC_FAILURE(rv)) { 2596 break; 2597 } 2598 2599 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 2600 continue; 2601 } 2602 2603 if (ALPM_CTRL(unit).bkt_sharing && sub_bkt != 2604 soc_mem_field32_get(unit, alpm_mem, alpm_entry, SUB_BKT_PTRf)) { 2605 continue; 2606 } 2607 2608 /* Zero destination buffer first. */ 2609 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 2610 2611 /* Parse the entry. */ 2612 /* Fill entry ip address & subnet mask. */ 2613 _bcm_th_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, 2614 &lpm_cfg); 2615 2616 (void)soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 2617 &cmp_result); 2618 2619 /* get associated data */ 2620 _bcm_th_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, 2621 &lpm_cfg, &nh_ecmp_idx); 2622 /* If protocol doesn't match skip the entry. */ 2623 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 2624 continue; 2625 } 2626 2627 lpm_cfg.defip_index = bkt_addr; 2628 2629 /* Check if this is default route */ 2630 /* Subnet length zero will indicate default route */ 2631 if (0 == lpm_cfg.defip_sub_len) { 2632 if (def_arr_idx < SOC_VRF_MAX(unit)) { 2633 def_rte_arr[def_arr_idx].bkt_addr = bkt_addr; 2634 def_rte_arr[def_arr_idx].idx = idx; 2635 def_arr_idx ++; 2636 } 2637 } else { 2638 /* Execute operation routine if any. */ 2639 if (trv_data->op_cb) { 2640 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 2641 (void *)&lpm_cfg, 2642 (void *)&nh_ecmp_idx, &cmp_result); 2643 #ifdef BCM_CB_ABORT_ON_ERR 2644 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2645 break; 2646 } 2647 #endif 2648 } 2649 } 2650 } 2651 } 2652 } 2653 2654 /* Process Default routes */ 2655 for (idx = 0; idx < def_arr_idx; idx++) { 2656 2657 /* Calculate entry offset. */ 2658 lpm_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m, 2659 defip_pair_128_entry_t *, lpm_tbl_ptr, 2660 def_rte_arr[idx].idx); 2661 2662 /* Make sure entry is valid. */ 2663 if (!soc_mem_field32_get(unit, pivot_mem, lpm_entry, VALID0_LWRf)) { 2664 continue; 2665 } 2666 2667 bkt_addr = def_rte_arr[idx].bkt_addr; 2668 2669 /* read entry from bucket memory */ 2670 rv = soc_mem_read_no_cache(unit, 0, alpm_mem, 0, MEM_BLOCK_ANY, 2671 bkt_addr, alpm_entry); 2672 if (SOC_FAILURE(rv)) { 2673 break; 2674 } 2675 2676 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 2677 continue; 2678 } 2679 2680 /* Zero destination buffer first. */ 2681 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 2682 2683 /* Fill entry ip address & subnet mask. */ 2684 _bcm_th_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, &lpm_cfg); 2685 /* Parse the entry. */ 2686 (void)soc_th_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 2687 &cmp_result); 2688 _bcm_th_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, &lpm_cfg, 2689 &nh_ecmp_idx); 2690 2691 /* If protocol doesn't match skip the entry. */ 2692 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 2693 continue; 2694 } 2695 2696 /* Execute operation routine if any. */ 2697 if (trv_data->op_cb) { 2698 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 2699 (void *)&lpm_cfg, 2700 (void *)&nh_ecmp_idx, &cmp_result); 2701 #ifdef BCM_CB_ABORT_ON_ERR 2702 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2703 break; 2704 } 2705 #endif 2706 } 2707 } 2708 2709 cleanup: 2710 if (def_rte_arr) { 2711 sal_free(def_rte_arr); 2712 } 2713 if (lpm_tbl_ptr) { 2714 soc_cm_sfree(unit, lpm_tbl_ptr); 2715 } 2716 2717 return (rv); 2718 } 2719 2720 /* 2721 * Function: 2722 * _bcm_th_alpm_update_match 2723 * Purpose: 2724 * Update/Delete all entries in defip table matching a certain rule. 2725 * Parameters: 2726 * unit - (IN)SOC unit number. 2727 * trv_data - (IN)Delete pattern + compare,act,notify routines. 2728 * Returns: 2729 * BCM_E_XXX 2730 */ 2731 int 2732 _bcm_th_alpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 2733 { 2734 uint32 ipv6 = 0; /* Iterate over ipv6 only flag. */ 2735 int idx; /* Iteration index. */ 2736 int tmp_idx; /* ipv4 entries iterator. */ 2737 int tmp_start; /* Iteration start. */ 2738 int tmp_end; /* Iteration end. */ 2739 int tmp_delta; /* Iteration delta. */ 2740 char *lpm_tbl_ptr; /* Dma table pointer. */ 2741 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 2742 int cmp_result; /* Test routine result. */ 2743 defip_entry_t *lpm_entry; /* Hw entry buffer. */ 2744 defip_entry_t lpm_entry_data; /* Hw entry buffer. */ 2745 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 2746 int defip_table_size; /* Defip table size. */ 2747 int rv = BCM_E_NONE; /* Operation return status. */ 2748 int idx_start = 0; 2749 int idx_end = 0, bkt_idx, bkt_count, bkt_ptr = 0, bkt_addr; 2750 int entry_num, bank_num, entry_count, bank_count; 2751 defip_alpm_ipv4_1_entry_t alpm_entry_v4; 2752 defip_alpm_ipv6_64_1_entry_t alpm_entry_v6_64; 2753 void *alpm_entry; 2754 soc_mem_t alpm_mem; 2755 int step_count; 2756 int def_arr_idx = 0; 2757 int def_rte_arr_sz; 2758 int bank_bits; 2759 int sub_bkt = 0; 2760 uint32 bank_disable; 2761 int alpm_bkt_bits = ALPM_CTRL(unit).bkt_bits; 2762 typedef struct _alpm_def_route_info_s { 2763 int idx; 2764 int bkt_addr; 2765 defip_entry_t lpm_entry; 2766 } _alpm_def_route_info_t; 2767 2768 _alpm_def_route_info_t *def_rte_arr = NULL; 2769 int flex; 2770 int size = 0; 2771 2772 2773 #ifdef BCM_WARM_BOOT_SUPPORT 2774 if (SOC_WARM_BOOT(unit)) { 2775 if (soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)) != 0) { 2776 rv = _bcm_th_alpm_warmboot_walk(unit, trv_data); 2777 if (rv < 0) { 2778 LOG_ERROR(BSL_LS_SOC_ALPM, 2779 (BSL_META_U(unit, 2780 "ERROR! ALPM Warmboot recovery failed"))); 2781 return (rv); 2782 } 2783 } 2784 2785 if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) != 0) { 2786 /* v6-128 entries */ 2787 rv = _bcm_th_alpm_128_warmboot_walk(unit, trv_data); 2788 if (rv < 0) { 2789 LOG_ERROR(BSL_LS_SOC_ALPM, 2790 (BSL_META_U(unit, 2791 "ERROR! ALPM Warmboot V6-128 recovery failed"))); 2792 } 2793 } 2794 return (rv); 2795 } 2796 #endif 2797 2798 ipv6 = trv_data->flags & BCM_L3_IP6; 2799 2800 if (ipv6 && soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) != 0) { 2801 /* first get v6-128 entries */ 2802 rv = _bcm_th_alpm_128_update_match(unit, trv_data); 2803 #ifdef BCM_CB_ABORT_ON_ERR 2804 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2805 return rv; 2806 } 2807 #endif 2808 } 2809 2810 if (soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)) == 0) { 2811 return BCM_E_NONE; 2812 } 2813 2814 /* Table DMA the LPM table to software copy */ 2815 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip), 2816 BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl", 2817 &lpm_tbl_ptr, &defip_table_size); 2818 if (BCM_FAILURE(rv)) { 2819 goto cleanup; 2820 } 2821 2822 /* Allocate memory to store default route meta data*/ 2823 def_rte_arr_sz = SOC_VRF_MAX(unit) * sizeof(_alpm_def_route_info_t); 2824 def_rte_arr = sal_alloc(def_rte_arr_sz, "alpm_def_rte_arry"); 2825 if (NULL == def_rte_arr) { 2826 rv = BCM_E_MEMORY; 2827 goto cleanup; 2828 } 2829 sal_memset(def_rte_arr, 0, def_rte_arr_sz); 2830 2831 if (SOC_URPF_STATUS_GET(unit)) { 2832 defip_table_size >>= 1; 2833 } 2834 2835 idx_end = defip_table_size; 2836 bank_num = 0; 2837 entry_num = 0; 2838 bank_count = ALPM_CTRL(unit).num_banks; 2839 bank_bits = ALPM_CTRL(unit).bank_bits; 2840 2841 step_count = ipv6 ? 1 : 2; 2842 2843 /* Walk all lpm entries */ 2844 for (idx = (idx_end - 1); idx >= idx_start; idx--) { 2845 /* Calculate entry ofset. */ 2846 lpm_entry = 2847 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip), 2848 defip_entry_t *, lpm_tbl_ptr, idx); 2849 sal_memcpy (&lpm_entry_data, lpm_entry, sizeof (lpm_entry_data)); 2850 2851 if (ipv6 && (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit)) == 0)) { 2852 /* 2853 * Function called for IPv6 LPM/ALPM walk and LPM entry is IPv4; Continue; 2854 */ 2855 continue; 2856 } 2857 2858 /* Each LPM index has two IPv4 entries*/ 2859 if (ipv6) { 2860 tmp_start = 0; 2861 tmp_end = step_count; 2862 tmp_delta = 1; 2863 } else { 2864 tmp_start = step_count - 1; 2865 tmp_end = -1; 2866 tmp_delta = -1; 2867 } 2868 2869 for (tmp_idx = tmp_start; tmp_idx != tmp_end; tmp_idx += tmp_delta) { 2870 if (!ipv6) { 2871 if (tmp_idx) { 2872 /* Check second part of the entry. */ 2873 soc_th_alpm_lpm_ip4entry1_to_0(unit, &lpm_entry_data, lpm_entry, TRUE); 2874 } else { 2875 soc_th_alpm_lpm_ip4entry0_to_0(unit, &lpm_entry_data, lpm_entry, TRUE); 2876 } 2877 } 2878 2879 /* Make sure entry is valid. */ 2880 if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) { 2881 continue; 2882 } 2883 2884 if (soc_feature(unit, soc_feature_ipmc_defip)) { 2885 /* Skip reserved ipmc entry */ 2886 int ipmc_index = 0; 2887 int ipmc_route = 0; 2888 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) { 2889 ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, 2890 lpm_entry, MULTICAST_ROUTE0f); 2891 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) { 2892 if (soc_mem_field32_get(unit, L3_DEFIPm, 2893 lpm_entry, DATA_TYPE0f) == 2) { 2894 ipmc_route = 1; 2895 } else { 2896 ipmc_route = 0; 2897 } 2898 } 2899 2900 if (soc_feature(unit, soc_feature_generic_dest)) { 2901 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 2902 uint32 dest_value = 0; 2903 dest_value = soc_mem_field32_dest_get(unit, 2904 L3_DEFIPm, lpm_entry, 2905 DESTINATION0f, &dest_type); 2906 if (dest_type == SOC_MEM_FIF_DEST_IPMC) { 2907 ipmc_index = dest_value; 2908 } else { 2909 ipmc_index = 0; 2910 } 2911 } else { 2912 ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm, 2913 lpm_entry, L3MC_INDEX0f); 2914 } 2915 2916 if (ipmc_route && (ipmc_index == 0)) { 2917 continue; 2918 } 2919 } 2920 2921 cmp_result = ipv6 ? 1 : 0; 2922 if (cmp_result != (soc_mem_field32_get(unit, L3_DEFIPm, 2923 lpm_entry, MODE0_f(unit)))) { 2924 continue; 2925 } 2926 2927 (void)soc_th_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 2928 &cmp_result); 2929 bank_disable = 2930 ALPM_CTRL(unit).bank_disable_bmp_8b[cmp_result != (SOC_VRF_MAX(unit) + 1)]; 2931 2932 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 2933 ALG_BKT_PTR0f); 2934 if (ALPM_CTRL(unit).bkt_sharing) { 2935 sub_bkt = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 2936 ALG_SUB_BKT_PTR0f); 2937 } 2938 2939 if (bkt_ptr == 0) { 2940 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 2941 _bcm_th_alpm_lpm_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 2942 lpm_entry); 2943 _bcm_th_alpm_lpm_key_parse(unit, &lpm_cfg, lpm_entry); 2944 2945 lpm_cfg.defip_index = idx; 2946 2947 if (ipv6 == (lpm_cfg.defip_flags & BCM_L3_IP6)) { 2948 if (trv_data->op_cb) { 2949 rv = (*trv_data->op_cb)(unit, (void *)trv_data, 2950 (void *)&lpm_cfg, 2951 (void *)&nh_ecmp_idx, &cmp_result); 2952 #ifdef BCM_CB_ABORT_ON_ERR 2953 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 2954 break; 2955 } 2956 #endif 2957 } 2958 } 2959 continue; 2960 } 2961 2962 flex = _soc_th_alpm_lpm_flex_get(unit, ipv6 ? L3_DEFIP_MODE_64 : 0, 2963 soc_mem_field32_get(unit, L3_DEFIPm, 2964 lpm_entry, ENTRY_VIEW0f)); 2965 if (ipv6) { 2966 if (flex) { 2967 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m; 2968 entry_count = 3; 2969 alpm_entry = &alpm_entry_v6_64; 2970 size = sizeof(alpm_entry_v6_64); 2971 } else { 2972 alpm_mem = L3_DEFIP_ALPM_IPV6_64m; 2973 entry_count = 4; 2974 alpm_entry = &alpm_entry_v6_64; 2975 size = sizeof(alpm_entry_v6_64); 2976 } 2977 2978 } else { 2979 if (flex) { 2980 alpm_mem = L3_DEFIP_ALPM_IPV4_1m; 2981 entry_count = 4; 2982 alpm_entry = &alpm_entry_v4; 2983 size = sizeof(alpm_entry_v4); 2984 } else { 2985 alpm_mem = L3_DEFIP_ALPM_IPV4m; 2986 entry_count = 6; 2987 alpm_entry = &alpm_entry_v4; 2988 size = sizeof(alpm_entry_v4); 2989 } 2990 } 2991 2992 entry_num = 0; 2993 bkt_count = _soc_th_alpm_bkt_entry_cnt(unit, alpm_mem); 2994 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 2995 2996 /* Get the bucket pointer from lpm mem entry */ 2997 for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) { 2998 /* Calculate bucket memory address */ 2999 /* Increment so next bucket address can be calculated */ 3000 bkt_addr = (entry_num << (bank_bits + alpm_bkt_bits)) | 3001 (bkt_ptr << bank_bits) | 3002 (bank_num & ((1U << bank_bits) - 1)); 3003 entry_num++; 3004 if (entry_num == entry_count) { 3005 entry_num = 0; 3006 ALPM_NEXT_AVAIL_BANK(bank_num, bank_count, bank_disable); 3007 if (bank_num == bank_count) { 3008 ALPM_FIRST_AVAIL_BANK(bank_num, bank_count, bank_disable); 3009 bkt_ptr ++; 3010 } 3011 } 3012 3013 sal_memset(alpm_entry, 0x00, size); 3014 /* Read entry from bucket memory */ 3015 rv = soc_mem_read_no_cache(unit, 0, alpm_mem, 0, MEM_BLOCK_ANY, 3016 bkt_addr, alpm_entry); 3017 if (SOC_FAILURE(rv)) { 3018 break; 3019 } 3020 3021 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 3022 continue; 3023 } 3024 3025 if (ALPM_CTRL(unit).bkt_sharing && sub_bkt != 3026 soc_mem_field32_get(unit, alpm_mem, alpm_entry, SUB_BKT_PTRf)) { 3027 continue; 3028 } 3029 3030 /* Zero destination buffer first. */ 3031 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 3032 3033 /* Parse the entry. */ 3034 _bcm_th_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 3035 alpm_mem, alpm_entry); 3036 3037 /* If protocol doesn't match skip the entry. */ 3038 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 3039 continue; 3040 } 3041 3042 /* Fill entry IP address and subnet mask. */ 3043 _bcm_th_alpm_ent_key_parse(unit, &lpm_cfg, lpm_entry, 3044 alpm_mem, alpm_entry); 3045 3046 lpm_cfg.defip_index = bkt_addr; 3047 3048 /* Check if this is default route */ 3049 /* Subnet length zero will indicate default route */ 3050 if (0 == lpm_cfg.defip_sub_len) { 3051 if (def_arr_idx < SOC_VRF_MAX(unit)) { 3052 def_rte_arr[def_arr_idx].bkt_addr = bkt_addr; 3053 def_rte_arr[def_arr_idx].idx = idx; 3054 sal_memcpy(&def_rte_arr[def_arr_idx].lpm_entry, 3055 lpm_entry, sizeof(*lpm_entry)); 3056 def_arr_idx ++; 3057 } 3058 } else { 3059 /* Execute operation routine if any. */ 3060 if (trv_data->op_cb) { 3061 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 3062 (void *)&lpm_cfg, 3063 (void *)&nh_ecmp_idx, &cmp_result); 3064 #ifdef BCM_CB_ABORT_ON_ERR 3065 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 3066 break; 3067 } 3068 #endif 3069 } 3070 } 3071 } 3072 } 3073 } 3074 3075 /* Process Default routes */ 3076 for (idx = 0; idx < def_arr_idx; idx++) { 3077 3078 /* Calculate entry ofset. */ 3079 lpm_entry = &def_rte_arr[idx].lpm_entry; 3080 3081 cmp_result = ipv6 ? 1 : 0; 3082 if (cmp_result != (soc_mem_field32_get(unit, L3_DEFIPm, 3083 lpm_entry, MODE0_f(unit)))) { 3084 /* 3085 * Function called for IPv6 LPM/ALPM walk and LPM entry is IPv4; 3086 * Continue; 3087 */ 3088 continue; 3089 } 3090 bkt_addr = def_rte_arr[idx].bkt_addr; 3091 3092 flex = _soc_th_alpm_lpm_flex_get(unit, ipv6 ? L3_DEFIP_MODE_64 : 0, 3093 soc_mem_field32_get(unit, L3_DEFIPm, 3094 lpm_entry, ENTRY_VIEW0f)); 3095 if (ipv6) { 3096 if (flex) { 3097 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m; 3098 alpm_entry = &alpm_entry_v6_64; 3099 size = sizeof(alpm_entry_v6_64); 3100 } else { 3101 alpm_mem = L3_DEFIP_ALPM_IPV6_64m; 3102 alpm_entry = &alpm_entry_v6_64; 3103 size = sizeof(alpm_entry_v6_64); 3104 } 3105 3106 } else { 3107 if (flex) { 3108 alpm_mem = L3_DEFIP_ALPM_IPV4_1m; 3109 alpm_entry = &alpm_entry_v4; 3110 size = sizeof(alpm_entry_v4); 3111 } else { 3112 alpm_mem = L3_DEFIP_ALPM_IPV4m; 3113 alpm_entry = &alpm_entry_v4; 3114 size = sizeof(alpm_entry_v4); 3115 } 3116 } 3117 sal_memset(alpm_entry, 0x00, size); 3118 /* read entry from bucket memory */ 3119 rv = soc_mem_read_no_cache(unit, 0, alpm_mem, 0, MEM_BLOCK_ANY, 3120 bkt_addr, alpm_entry); 3121 if (SOC_FAILURE(rv)) { 3122 break; 3123 } 3124 3125 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) { 3126 continue; 3127 } 3128 3129 /* Zero destination buffer first. */ 3130 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 3131 3132 (void)soc_th_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, 3133 &cmp_result); 3134 /* Parse the entry. */ 3135 _bcm_th_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, 3136 alpm_mem, alpm_entry); 3137 3138 /* If protocol doesn't match skip the entry. */ 3139 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 3140 continue; 3141 } 3142 3143 /* Fill entry ip address & subnet mask. */ 3144 _bcm_th_alpm_ent_key_parse(unit, &lpm_cfg, lpm_entry, 3145 alpm_mem, alpm_entry); 3146 3147 /* Execute operation routine if any. */ 3148 if (trv_data->op_cb) { 3149 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 3150 (void *)&lpm_cfg, 3151 (void *)&nh_ecmp_idx, &cmp_result); 3152 #ifdef BCM_CB_ABORT_ON_ERR 3153 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 3154 break; 3155 } 3156 #endif 3157 } 3158 } 3159 3160 #ifdef ALPM_WARM_BOOT_DEBUG 3161 soc_alpm_lpm_sw_dump(unit); 3162 #endif /* ALPM_WARM_BOOT_DEBUG */ 3163 3164 cleanup: 3165 if (def_rte_arr != NULL) { 3166 sal_free(def_rte_arr); 3167 } 3168 if (lpm_tbl_ptr != NULL) { 3169 soc_cm_sfree(unit, lpm_tbl_ptr); 3170 } 3171 3172 return (rv); 3173 } 3174 3175 /* 3176 * Function: 3177 * _bcm_th_alpm_find 3178 * Purpose: 3179 * Get an entry from DEFIP table. 3180 * Parameters: 3181 * unit - (IN)SOC unit number. 3182 * lpm_cfg - (IN)Buffer to fill defip information. 3183 * nh_ecmp_idx - (IN)Next hop or ecmp group index 3184 * Returns: 3185 * BCM_E_XXX 3186 */ 3187 int 3188 _bcm_th_alpm_find(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 3189 { 3190 defip_entry_t lpm_key; /* Route lookup key. */ 3191 defip_entry_t lpm_entry; /* Search result buffer. */ 3192 defip_pair_128_entry_t lpm_128_key; 3193 defip_pair_128_entry_t lpm_128_entry; 3194 int do_urpf = 0; /* Find uRPF region */ 3195 int rv; /* Operation return status. */ 3196 uint32 flags = 0; 3197 soc_mem_t mem; 3198 int lpm_mode, tmp; 3199 uint32 rval; 3200 3201 /* Input parameters check */ 3202 if (NULL == lpm_cfg) { 3203 return (BCM_E_PARAM); 3204 } 3205 3206 SOC_IF_ERROR_RETURN(READ_L3_DEFIP_RPF_CONTROLr(unit, &rval)); 3207 lpm_mode = soc_reg_field_get(unit, L3_DEFIP_RPF_CONTROLr, rval, LPM_MODEf); 3208 /* Not supported in Legacy LPM mode */ 3209 if (lpm_mode == 0) { 3210 return (BCM_E_UNAVAIL); 3211 } 3212 3213 /* Zero buffers. */ 3214 sal_memset(&lpm_entry, 0, sizeof(defip_entry_t)); 3215 sal_memset(&lpm_key, 0, sizeof(defip_entry_t)); 3216 sal_memset(&lpm_128_entry, 0, sizeof(defip_pair_128_entry_t)); 3217 sal_memset(&lpm_128_key, 0, sizeof(defip_pair_128_entry_t)); 3218 3219 /* Default value */ 3220 mem = L3_DEFIPm; 3221 if ((lpm_cfg->defip_flags & BCM_L3_IP6)) { 3222 if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) > 0) { 3223 mem = L3_DEFIP_PAIR_128m; 3224 } 3225 } 3226 3227 switch (mem) { 3228 case L3_DEFIP_PAIR_128m: 3229 /* Initialize lkup key. */ 3230 BCM_IF_ERROR_RETURN(_bcm_th_alpm_lpm128_init(unit, lpm_cfg, 3231 &lpm_128_key, 0, &flags)); 3232 /* Perform hw lookup. */ 3233 rv = soc_th_alpm_128_find_best_match(unit, &lpm_128_key, &lpm_128_entry, 3234 &lpm_cfg->defip_index, do_urpf); 3235 BCM_IF_ERROR_RETURN(rv); 3236 3237 /* Parse hw buffer to defip entry. */ 3238 _bcm_th_alpm_lpm128_data_parse(unit, lpm_cfg, nh_ecmp_idx, 3239 &lpm_128_entry); 3240 /* OVERRIDE VRF Processing */ 3241 _bcm_th_alpm_lpm128_key_parse(unit, (uint32 *)&lpm_128_entry, lpm_cfg); 3242 soc_th_alpm_128_lpm_vrf_get(unit, &lpm_128_entry, &lpm_cfg->defip_vrf, &tmp); 3243 3244 break; 3245 default: 3246 /* Initialize lkup key. */ 3247 BCM_IF_ERROR_RETURN(_bcm_th_alpm_lpm_init(unit, lpm_cfg, &lpm_key, 0, 3248 &flags)); 3249 /* Perform hw lookup. */ 3250 rv = soc_th_alpm_find_best_match(unit, &lpm_key, &lpm_entry, 3251 &lpm_cfg->defip_index, do_urpf); 3252 BCM_IF_ERROR_RETURN(rv); 3253 3254 /* Parse hw buffer to defip entry. */ 3255 _bcm_th_alpm_lpm_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_entry); 3256 _bcm_th_alpm_lpm_key_parse(unit, lpm_cfg, &lpm_entry); 3257 3258 break; 3259 } 3260 3261 return (BCM_E_NONE); 3262 } 3263 3264 #endif /* defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT) */ 3265 #endif /* INCLUDE_L3 && ALPM_ENABLE */ 3266