hashing.c (56611B)
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: hashing.c 8 * Purpose: Hash calcualtions for trunk and ECMP packets. 9 */ 10 11 #include <soc/debug.h> 12 #include <soc/drv.h> 13 #include <soc/hash.h> 14 #include <bcm/switch.h> 15 #include <bcm/debug.h> 16 #include <bcm/error.h> 17 18 #include <bcm_int/esw_dispatch.h> 19 #include <bcm_int/esw/firebolt.h> 20 #include <bcm_int/esw/port.h> 21 #include <bcm_int/esw/stack.h> 22 #include <bcm_int/esw/switch.h> 23 24 typedef struct bcm_rtag7_base_hash_s { 25 uint32 rtag7_hash16_value_a_0; /* hash a0 result */ 26 uint32 rtag7_hash16_value_a_1; /* hash a1 result */ 27 uint32 rtag7_hash16_value_b_0; /* hash b0 result */ 28 uint32 rtag7_hash16_value_b_1; /* hash b1 result */ 29 uint32 rtag7_macro_flow_id; /* hash micro flow result */ 30 uint32 rtag7_port_lbn; /* port LBN value from the port table*/ 31 uint32 rtag7_lbid_hash; /* LBID hash calculation*/ 32 bcm_port_t dev_src_port; /* Local source port */ 33 bcm_port_t src_port; /* System source port */ 34 bcm_module_t src_modid; /* System source modid */ 35 uint8 is_nonuc; /* Non-unicast */ 36 uint8 hash_a_valid; /* Hash A result use valid input */ 37 uint8 hash_b_valid; /* Hash B result use valid input */ 38 uint8 lbid_hash_valid; /* LBID Hash value is valid */ 39 } bcm_rtag7_base_hash_t; 40 41 #define ETHERTYPE_IPV6 0x86dd /* ipv6 ethertype */ 42 #define ETHERTYPE_IPV4 0x0800 /* ipv4 ethertype */ 43 #define ETHERTYPE_MIN 0x0600 /* minimum ethertype for hashing */ 44 45 #define IP_PROT_TCP 0x6 /* TCP protocol number */ 46 #define IP_PROT_UDP 0x11 /* TCP protocol number */ 47 48 #define RTAG7_L2_ONLY 0x0 49 #define RTAG7_UNKNOWN_HIGIG 0x1 50 #define RTAG7_MPLS 0x2 51 #define RTAG7_MIM 0x3 52 #define RTAG7_IPV4 0x4 53 #define RTAG7_IPV6 0x5 54 #define RTAG7_FCOE 0x6 55 #define RTAG7_TRILL 0x7 56 57 /* fields from TRUNK_GROUPm */ 58 STATIC soc_field_t _xgs_portf[8] = { 59 PORT0f, PORT1f, PORT2f, PORT3f, 60 PORT4f, PORT5f, PORT6f, PORT7f 61 }; 62 63 STATIC soc_field_t _xgs_modulef[8] = { 64 MODULE0f, MODULE1f, MODULE2f, MODULE3f, 65 MODULE4f, MODULE5f, MODULE6f, MODULE7f 66 }; 67 68 STATIC soc_field_t _xgs_hg_portf[4] = { 69 HIGIG_TRUNK_PORT0f, HIGIG_TRUNK_PORT1f, 70 HIGIG_TRUNK_PORT2f, HIGIG_TRUNK_PORT3f 71 }; 72 73 STATIC int 74 main__en_do_rtag7_hashing(int unit, 75 bcm_switch_pkt_info_t *pkt_info, 76 bcm_rtag7_base_hash_t *hash_res) 77 { 78 /* regular var declaration */ 79 uint32 hash_src_port; 80 uint32 hash_src_modid; 81 uint32 rtag7_a_sel; 82 bcm_ip_t sip_a; /* Source IPv4 address. */ 83 bcm_ip_t dip_a; /* Destination IPv4 address. */ 84 uint32 rtag7_b_sel; 85 bcm_ip_t sip_b; /* Source IPv4 address. */ 86 bcm_ip_t dip_b; /* Destination IPv4 address. */ 87 uint32 hash_field_bmap_a; /* block A chosen bitmap*/ 88 uint32 hash_field_bmap_b; /* block B chosen bitmap*/ 89 90 uint32 hash_word[7]; 91 uint32 hash[13]; 92 int elem, elem_bit; 93 uint32 hash_element_valid_bits; 94 /* int ip6_addrs = FALSE, ip4_addrs = FALSE; */ 95 int sip_valid = FALSE, dip_valid = FALSE; 96 97 uint32 hash_crc16_bisync; 98 uint32 hash_xor8; 99 uint32 hash_xor4; 100 uint32 hash_xor2; 101 uint32 hash_xor1; 102 uint32 xor32; 103 104 /* register var declaration */ 105 uint8 rtag7_disable_hash_ipv4_a; 106 uint8 rtag7_disable_hash_ipv6_a; 107 108 uint8 rtag7_disable_hash_ipv4_b; 109 uint8 rtag7_disable_hash_ipv6_b; 110 uint32 rtag7_hash_seed_a; 111 uint32 rtag7_hash_seed_b; 112 uint32 rtag7_hash_a0_function_select; 113 uint32 rtag7_hash_b0_function_select; 114 115 uint64 rtag7_hash_control; 116 uint32 rtag7_hash_seed_a_reg, rtag7_hash_seed_b_reg; 117 soc_reg_t sc_reg; 118 soc_field_t sc_field; 119 uint32 sc_val; 120 121 SOC_IF_ERROR_RETURN 122 (READ_RTAG7_HASH_CONTROLr(unit, &rtag7_hash_control)); 123 SOC_IF_ERROR_RETURN 124 (READ_RTAG7_HASH_SEED_Ar(unit, &rtag7_hash_seed_a_reg)); 125 SOC_IF_ERROR_RETURN 126 (READ_RTAG7_HASH_SEED_Br(unit, &rtag7_hash_seed_b_reg)); 127 128 /* RTAG7 hash registers */ 129 rtag7_disable_hash_ipv4_a = 130 soc_reg64_field32_get(unit, RTAG7_HASH_CONTROLr, rtag7_hash_control, 131 DISABLE_HASH_IPV4_Af); 132 rtag7_disable_hash_ipv6_a = 133 soc_reg64_field32_get(unit, RTAG7_HASH_CONTROLr, rtag7_hash_control, 134 DISABLE_HASH_IPV6_Af); 135 rtag7_disable_hash_ipv4_b = 136 soc_reg64_field32_get(unit, RTAG7_HASH_CONTROLr, rtag7_hash_control, 137 DISABLE_HASH_IPV4_Bf); 138 rtag7_disable_hash_ipv6_b = 139 soc_reg64_field32_get(unit, RTAG7_HASH_CONTROLr, rtag7_hash_control, 140 DISABLE_HASH_IPV6_Bf); 141 142 rtag7_hash_a0_function_select = 143 soc_reg64_field32_get(unit, RTAG7_HASH_CONTROLr, rtag7_hash_control, 144 HASH_MODE_Af); 145 rtag7_hash_b0_function_select = 146 soc_reg64_field32_get(unit, RTAG7_HASH_CONTROLr, rtag7_hash_control, 147 HASH_MODE_Bf); 148 149 rtag7_hash_seed_a = 150 soc_reg_field_get(unit, RTAG7_HASH_SEED_Ar, rtag7_hash_seed_a_reg, 151 HASH_SEED_Af); 152 rtag7_hash_seed_b = 153 soc_reg_field_get(unit, RTAG7_HASH_SEED_Br, rtag7_hash_seed_b_reg, 154 HASH_SEED_Bf); 155 156 /* RTAG7 tables */ 157 /* the first step is to choose the paket type and to fold the ipv6 158 * addresses in case of IPv6 packet*/ 159 160 /* option A ip folding for rtag 7 */ 161 if ((_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, ETHERTYPE) && 162 (pkt_info->ethertype == ETHERTYPE_IPV6)) && 163 (rtag7_disable_hash_ipv6_a == 0)) { 164 165 /* ip6_addrs = TRUE; */ 166 rtag7_a_sel = RTAG7_IPV6; 167 168 /* This section will fold the Ipv6 address to single 32 bit address 169 * by using of of the method of xor */ 170 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_IPV6)) { 171 sip_a = 172 ((pkt_info->sip6[12] << 24) | 173 (pkt_info->sip6[13] << 16) | 174 (pkt_info->sip6[14] << 8) | 175 (pkt_info->sip6[15])) ^ 176 ((pkt_info->sip6[8] << 24) | 177 (pkt_info->sip6[9] << 16) | 178 (pkt_info->sip6[10] << 8) | 179 (pkt_info->sip6[11])) ^ 180 ((pkt_info->sip6[4] << 24) | 181 (pkt_info->sip6[5] << 16) | 182 (pkt_info->sip6[6] << 8) | 183 (pkt_info->sip6[7])) ^ 184 ((pkt_info->sip6[0] << 24) | 185 (pkt_info->sip6[1] << 16) | 186 (pkt_info->sip6[2] << 8) | 187 (pkt_info->sip6[3])); 188 sip_valid = TRUE; 189 } else { 190 sip_a = 0; 191 } 192 193 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_IPV6)) { 194 dip_a = 195 ((pkt_info->dip6[12] << 24) | 196 (pkt_info->dip6[13] << 16) | 197 (pkt_info->dip6[14] << 8) | 198 (pkt_info->dip6[15])) ^ 199 ((pkt_info->dip6[8] << 24) | 200 (pkt_info->dip6[9] << 16) | 201 (pkt_info->dip6[10] << 8) | 202 (pkt_info->dip6[11])) ^ 203 ((pkt_info->dip6[4] << 24) | 204 (pkt_info->dip6[5] << 16) | 205 (pkt_info->dip6[6] << 8) | 206 (pkt_info->dip6[7])) ^ 207 ((pkt_info->dip6[0] << 24) | 208 (pkt_info->dip6[1] << 16) | 209 (pkt_info->dip6[2] << 8) | 210 (pkt_info->dip6[3])); 211 dip_valid = TRUE; 212 } else { 213 dip_a = 0; 214 } 215 } else if ((_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, ETHERTYPE) && 216 (pkt_info->ethertype == ETHERTYPE_IPV4)) && 217 (rtag7_disable_hash_ipv4_a == 0)) { 218 219 /* ip4_addrs = TRUE; */ 220 rtag7_a_sel = RTAG7_IPV4; 221 222 /* only one IPv4 hdr */ 223 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_IP)) { 224 sip_a = pkt_info->sip; 225 sip_valid = TRUE; 226 } else { 227 sip_a = 0; 228 } 229 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_IP)) { 230 dip_a = pkt_info->dip; 231 dip_valid = TRUE; 232 } else { 233 dip_a = 0; 234 } 235 } else { 236 rtag7_a_sel = RTAG7_L2_ONLY; 237 sip_a = dip_a = 0; 238 } 239 240 /* End of option A ip folding for rtag 7 */ 241 242 /* option B ip folding for rtag 7 */ 243 if ((_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, ETHERTYPE) && 244 (pkt_info->ethertype == ETHERTYPE_IPV6)) && 245 (rtag7_disable_hash_ipv6_b == 0)) { 246 247 /* ip6_addrs = TRUE; */ 248 rtag7_b_sel = RTAG7_IPV6; 249 250 /* This section will fold the Ipv6 address to single 32 bit address 251 * by using of of the method of xor */ 252 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_IPV6)) { 253 sip_b = 254 ((pkt_info->sip6[12] << 24) | 255 (pkt_info->sip6[13] << 16) | 256 (pkt_info->sip6[14] << 8) | 257 (pkt_info->sip6[15])) ^ 258 ((pkt_info->sip6[8] << 24) | 259 (pkt_info->sip6[9] << 16) | 260 (pkt_info->sip6[10] << 8) | 261 (pkt_info->sip6[11])) ^ 262 ((pkt_info->sip6[4] << 24) | 263 (pkt_info->sip6[5] << 16) | 264 (pkt_info->sip6[6] << 8) | 265 (pkt_info->sip6[7])) ^ 266 ((pkt_info->sip6[0] << 24) | 267 (pkt_info->sip6[1] << 16) | 268 (pkt_info->sip6[2] << 8) | 269 (pkt_info->sip6[3])); 270 sip_valid = TRUE; 271 } else { 272 sip_b = 0; 273 } 274 275 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_IPV6)) { 276 dip_b = 277 ((pkt_info->dip6[12] << 24) | 278 (pkt_info->dip6[13] << 16) | 279 (pkt_info->dip6[14] << 8) | 280 (pkt_info->dip6[15])) ^ 281 ((pkt_info->dip6[8] << 24) | 282 (pkt_info->dip6[9] << 16) | 283 (pkt_info->dip6[10] << 8) | 284 (pkt_info->dip6[11])) ^ 285 ((pkt_info->dip6[4] << 24) | 286 (pkt_info->dip6[5] << 16) | 287 (pkt_info->dip6[6] << 8) | 288 (pkt_info->dip6[7])) ^ 289 ((pkt_info->dip6[0] << 24) | 290 (pkt_info->dip6[1] << 16) | 291 (pkt_info->dip6[2] << 8) | 292 (pkt_info->dip6[3])); 293 dip_valid = TRUE; 294 } else { 295 dip_b = 0; 296 } 297 } else if ((_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, ETHERTYPE) && 298 (pkt_info->ethertype == ETHERTYPE_IPV4)) && 299 (rtag7_disable_hash_ipv4_b == 0)) { 300 301 /* ip4_addrs = TRUE; */ 302 rtag7_b_sel = RTAG7_IPV4; 303 304 /* only one IPv4 hdr */ 305 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_IP)) { 306 sip_b = pkt_info->sip; 307 sip_valid = TRUE; 308 } else { 309 sip_b = 0; 310 } 311 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_IP)) { 312 dip_b = pkt_info->dip; 313 dip_valid = TRUE; 314 } else { 315 dip_b = 0; 316 } 317 } else { 318 rtag7_b_sel = RTAG7_L2_ONLY; 319 sip_b = dip_b = 0; 320 } 321 /* End of option B ip folding for rtag 7 */ 322 323 /* 324 * ============= 325 * RTAG7 HASHING 326 * ============= 327 */ 328 329 /* The inputs to the RTAG7 hash function were reduced in the begining 330 * of this function. 331 * This logic takes the hash inputs and computes both A and B RTAG7 332 * hash values. 333 */ 334 335 /* Change source modid/port to PORT32 space for hashing */ 336 hash_src_port = hash_res->src_port; 337 hash_src_modid = hash_res->src_modid; 338 339 /* Only if the packet was sourced by this chip, make sure to use 340 * PORT32 space modid and port if dual modid is enabled 341 * Need to do this because of front panel ports. 342 * 343 * Already handled by API gport resolve */ 344 345 /* initialize the variables */ 346 sal_memset(hash,0x0,(sizeof(uint32))*13); 347 sal_memset(hash_word,0x0,(sizeof(uint32))*7); 348 349 hash_crc16_bisync = 0; 350 hash_xor8 = 0; 351 hash_xor4 = 0; 352 hash_xor2 = 0; 353 hash_xor1 = 0; 354 xor32 = 0; 355 356 hash[12] = 0; 357 hash[3] = hash_src_port; 358 hash[2] = hash_src_modid & 0xff; 359 hash[1] = 0; 360 hash[0] = 0; 361 362 hash_element_valid_bits = 0x1fff; /* Init to valid fields above */ 363 364 /* option A hash calculation for rtag 7 */ 365 366 if ((rtag7_a_sel == RTAG7_IPV6) || (rtag7_a_sel == RTAG7_IPV4)) { 367 368 if (sip_valid) { 369 hash[11] = (sip_a >> 16) & 0xffff; 370 hash[10] = sip_a & 0xffff; 371 } else { 372 hash_element_valid_bits &= ~0xc00; 373 } 374 if (dip_valid) { 375 hash[9] = (dip_a >> 16) & 0xffff; 376 hash[8] = dip_a & 0xffff; 377 } else { 378 hash_element_valid_bits &= ~0x300; 379 } 380 381 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, VLAN)) { 382 hash[7] = pkt_info->vid & 0xfff; 383 } else { 384 hash_element_valid_bits &= ~0x80; 385 } 386 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_L4_PORT)) { 387 hash[6] = pkt_info->src_l4_port; 388 } else { 389 hash_element_valid_bits &= ~0x40; 390 } 391 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_L4_PORT)) { 392 hash[5] = pkt_info->dst_l4_port; 393 } else { 394 hash_element_valid_bits &= ~0x20; 395 } 396 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, PROTOCOL)) { 397 hash[4] = pkt_info->protocol; 398 } else { 399 hash_element_valid_bits &= ~0x10; 400 } 401 402 if (rtag7_a_sel == RTAG7_IPV4) { /* Use IPv4 BITMAPs */ 403 sc_reg = RTAG7_HASH_FIELD_BMAP_1r; 404 sc_field = IPV4_FIELD_BITMAP_Af; 405 LOG_VERBOSE(BSL_LS_BCM_COMMON, 406 (BSL_META_U(unit, 407 "Unit %d - Hash calculation: Bitmap is block A IPv4 \n"), 408 unit)); 409 } else { /* Use IPv6 BITMAPs */ 410 sc_reg = RTAG7_HASH_FIELD_BMAP_2r; 411 sc_field = IPV6_FIELD_BITMAP_Af; 412 LOG_VERBOSE(BSL_LS_BCM_COMMON, 413 (BSL_META_U(unit, 414 "Unit %d - Hash calculation: Bitmap is block A IPv6 \n"), 415 unit)); 416 } 417 418 } else { /* Catch-all for RTAG7_L2_ONLY */ 419 420 /* L2 only hash key */ 421 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_MAC)) { 422 hash[11] = (pkt_info->src_mac[0] << 8) | pkt_info->src_mac[1]; 423 hash[10] = (pkt_info->src_mac[2] << 8) | pkt_info->src_mac[3]; 424 hash[9] = (pkt_info->src_mac[4] << 8) | pkt_info->src_mac[5]; 425 } else { 426 hash_element_valid_bits &= ~0xe00; 427 } 428 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_MAC)) { 429 hash[8] = (pkt_info->dst_mac[0] << 8) | pkt_info->dst_mac[1]; 430 hash[7] = (pkt_info->dst_mac[2] << 8) | pkt_info->dst_mac[3]; 431 hash[6] = (pkt_info->dst_mac[4] << 8) | pkt_info->dst_mac[5]; 432 } else { 433 hash_element_valid_bits &= ~0x1c0; 434 } 435 436 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, ETHERTYPE)) { 437 hash[5] = (pkt_info->ethertype >= ETHERTYPE_MIN) ? 438 pkt_info->ethertype : 0; 439 } else { 440 hash_element_valid_bits &= ~0x20; 441 } 442 443 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, VLAN)) { 444 hash[4] = pkt_info->vid & 0xfff; 445 } else { 446 hash_element_valid_bits &= ~0x10; 447 } 448 449 sc_reg = RTAG7_HASH_FIELD_BMAP_3r; 450 sc_field = L2_FIELD_BITMAP_Af; 451 LOG_VERBOSE(BSL_LS_BCM_COMMON, 452 (BSL_META_U(unit, 453 "Unit %d - Hash calculation: Bitmap is block A L2\n"), 454 unit)); 455 } 456 457 BCM_IF_ERROR_RETURN 458 (soc_reg32_get(unit, sc_reg, REG_PORT_ANY, 0, &sc_val)); 459 hash_field_bmap_a = soc_reg_field_get(unit, sc_reg, sc_val, sc_field); 460 461 hash_word[6] = rtag7_hash_seed_a; 462 463 hash_res->hash_a_valid = TRUE; 464 for (elem = 11; elem >= 0; elem--) { 465 elem_bit = 1 << elem; 466 if (0 != (hash_field_bmap_a & elem_bit)) { 467 if (0 != (hash_element_valid_bits & elem_bit)) { 468 hash_word[elem/2] |= 469 ((hash[elem] & 0xffff) << (16 * (elem % 2))); 470 } else { 471 hash_res->hash_a_valid = FALSE; 472 break; 473 } 474 } 475 } 476 477 /*Calculation*/ 478 xor32 = hash_word[6] ^ hash_word[5] ^ hash_word[4] ^ hash_word[3] ^ 479 hash_word[2] ^ hash_word[1] ^ hash_word[0]; 480 481 hash_xor8 = (xor32 & 0xff) ^ ((xor32 >> 8) & 0xff) ^ ((xor32 >> 16) & 0xff) ^ ((xor32 >> 24) & 0xff); 482 hash_xor4 = (hash_xor8 & 0xf) ^ ((hash_xor8 >> 4) & 0xf); 483 hash_xor2 = (hash_xor4 & 0x3) ^ ((hash_xor4 >> 2) & 0x3); 484 hash_xor1 = (hash_xor2 & 0x1) ^ ((hash_xor2 >> 1) & 0x1); 485 486 487 hash_crc16_bisync = _shr_crc16_draco_array(hash_word, 28); 488 489 switch (rtag7_hash_a0_function_select) { 490 case 0: /* reserved */ 491 hash_res->rtag7_hash16_value_a_0 = 0; 492 break; 493 case 1: /* reserved */ 494 hash_res->rtag7_hash16_value_a_0 = 0; 495 break; 496 case 2: /* reserved */ 497 hash_res->rtag7_hash16_value_a_0 = 0; 498 break; 499 case 3: /* CRC16 BISYNC */ 500 hash_res->rtag7_hash16_value_a_0 = hash_crc16_bisync; 501 break; 502 case 4: /* CRC16_XOR1 */ 503 hash_res->rtag7_hash16_value_a_0 = hash_xor1 & 0x1; 504 hash_res->rtag7_hash16_value_a_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 505 break; 506 case 5: /* CRC16_XOR2 */ 507 hash_res->rtag7_hash16_value_a_0 = hash_xor2 & 0x3; 508 hash_res->rtag7_hash16_value_a_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 509 break; 510 case 6: /* CRC16_XOR4 */ 511 hash_res->rtag7_hash16_value_a_0 = hash_xor4 & 0xf; 512 hash_res->rtag7_hash16_value_a_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 513 break; 514 case 7: /* CRC16_XOR8 */ 515 hash_res->rtag7_hash16_value_a_0 = hash_xor8 & 0xff; 516 hash_res->rtag7_hash16_value_a_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 517 break; 518 default: /* reserved */ 519 hash_res->rtag7_hash16_value_a_0 = 0; 520 break; 521 } 522 523 hash_res->rtag7_hash16_value_a_1 = 0; 524 525 /* End of option A hash calculation for rtag 7 */ 526 527 hash_res->rtag7_macro_flow_id = 0; 528 529 /* option B hash calculation for rtag 7 */ 530 531 /* initialize the variables */ 532 533 sal_memset(hash,0x0,(sizeof(uint32))*13); 534 sal_memset(hash_word,0x0,(sizeof(uint32))*7); 535 536 hash_crc16_bisync = 0; 537 hash_xor8 = 0; 538 hash_xor4 = 0; 539 hash_xor2 = 0; 540 hash_xor1 = 0; 541 xor32 = 0; 542 543 hash[12] = 0; 544 hash[3] = hash_src_port; 545 hash[2] = hash_src_modid & 0xff; 546 hash[1] = 0; 547 hash[0] = 0; 548 549 hash_element_valid_bits = 0x1fff; /* Init to valid fields above */ 550 551 /* option B hash calculation for rtag 7 */ 552 553 if ((rtag7_b_sel == RTAG7_IPV6) || (rtag7_b_sel == RTAG7_IPV4)) { 554 if (sip_valid) { 555 hash[11] = (sip_b >> 16) & 0xffff; 556 hash[10] = sip_b & 0xffff; 557 } else { 558 hash_element_valid_bits &= ~0xc00; 559 } 560 if (dip_valid) { 561 hash[9] = (dip_b >> 16) & 0xffff; 562 hash[8] = dip_b & 0xffff; 563 } else { 564 hash_element_valid_bits &= ~0x300; 565 } 566 567 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, VLAN)) { 568 hash[7] = pkt_info->vid & 0xfff; 569 } else { 570 hash_element_valid_bits &= ~0x80; 571 } 572 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_L4_PORT)) { 573 hash[6] = pkt_info->src_l4_port; 574 } else { 575 hash_element_valid_bits &= ~0x40; 576 } 577 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_L4_PORT)) { 578 hash[5] = pkt_info->dst_l4_port; 579 } else { 580 hash_element_valid_bits &= ~0x20; 581 } 582 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, PROTOCOL)) { 583 hash[4] = pkt_info->protocol; 584 } else { 585 hash_element_valid_bits &= ~0x10; 586 } 587 588 if (rtag7_b_sel == RTAG7_IPV4) { /* Use IPv4 BITMAPs */ 589 sc_reg = RTAG7_HASH_FIELD_BMAP_1r; 590 sc_field = IPV4_FIELD_BITMAP_Bf; 591 LOG_VERBOSE(BSL_LS_BCM_COMMON, 592 (BSL_META_U(unit, 593 "Unit %d - Hash calculation: Bitmap is block B IPv4\n"), 594 unit)); 595 } else { /* Use IPv6 BITMAPs */ 596 sc_reg = RTAG7_HASH_FIELD_BMAP_2r; 597 sc_field = IPV6_FIELD_BITMAP_Bf; 598 LOG_VERBOSE(BSL_LS_BCM_COMMON, 599 (BSL_META_U(unit, 600 "Unit %d - Hash calculation: Bitmap is block B IPv6\n"), 601 unit)); 602 } 603 } else { /* Catch-all for RTAG7_L2_ONLY */ 604 605 /* L2 only hash key */ 606 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_MAC)) { 607 hash[11] = (pkt_info->src_mac[0] << 8) | pkt_info->src_mac[1]; 608 hash[10] = (pkt_info->src_mac[2] << 8) | pkt_info->src_mac[3]; 609 hash[9] = (pkt_info->src_mac[4] << 8) | pkt_info->src_mac[5]; 610 } else { 611 hash_element_valid_bits &= ~0xe00; 612 } 613 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, DST_MAC)) { 614 hash[8] = (pkt_info->dst_mac[0] << 8) | pkt_info->dst_mac[1]; 615 hash[7] = (pkt_info->dst_mac[2] << 8) | pkt_info->dst_mac[3]; 616 hash[6] = (pkt_info->dst_mac[4] << 8) | pkt_info->dst_mac[5]; 617 } else { 618 hash_element_valid_bits &= ~0x1c0; 619 } 620 621 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, ETHERTYPE)) { 622 hash[5] = (pkt_info->ethertype >= ETHERTYPE_MIN) ? 623 pkt_info->ethertype : 0; 624 } else { 625 hash_element_valid_bits &= ~0x20; 626 } 627 628 if (_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, VLAN)) { 629 hash[4] = pkt_info->vid & 0xfff; 630 } else { 631 hash_element_valid_bits &= ~0x10; 632 } 633 634 sc_reg = RTAG7_HASH_FIELD_BMAP_3r; 635 sc_field = L2_FIELD_BITMAP_Bf; 636 LOG_VERBOSE(BSL_LS_BCM_COMMON, 637 (BSL_META_U(unit, 638 "Unit %d - Hash calculation: Bitmap is block B L2\n"), 639 unit)); 640 } 641 642 BCM_IF_ERROR_RETURN 643 (soc_reg32_get(unit, sc_reg, REG_PORT_ANY, 0, &sc_val)); 644 hash_field_bmap_b = soc_reg_field_get(unit, sc_reg, sc_val, sc_field); 645 646 hash_word[6] = rtag7_hash_seed_b; 647 648 hash_res->hash_b_valid = TRUE; 649 for (elem = 11; elem >= 0; elem--) { 650 elem_bit = 1 << elem; 651 if (0 != (hash_field_bmap_b & elem_bit)) { 652 if (0 != (hash_element_valid_bits & elem_bit)) { 653 hash_word[elem/2] |= 654 ((hash[elem] & 0xffff) << (16 * (elem % 2))); 655 } else { 656 hash_res->hash_b_valid = FALSE; 657 break; 658 } 659 } 660 } 661 662 xor32 = hash_word[6] ^ hash_word[5] ^ hash_word[4] ^ hash_word[3] ^ 663 hash_word[2] ^ hash_word[1] ^ hash_word[0]; 664 665 hash_xor8 = (xor32 & 0xff) ^ ((xor32 >> 8) & 0xff) ^ ((xor32 >> 16) & 0xff) ^ ((xor32 >> 24) & 0xff); 666 hash_xor4 = (hash_xor8 & 0xf) ^ ((hash_xor8 >> 4) & 0xf); 667 hash_xor2 = (hash_xor4 & 0x3) ^ ((hash_xor4 >> 2) & 0x3); 668 hash_xor1 = (hash_xor2 & 0x1) ^ ((hash_xor2 >> 1) & 0x1); 669 670 hash_crc16_bisync = _shr_crc16_draco_array(hash_word, 28); 671 672 switch (rtag7_hash_b0_function_select) { 673 case 0: /* reserved */ 674 hash_res->rtag7_hash16_value_b_0 = 0; 675 break; 676 case 1: /* reserved */ 677 hash_res->rtag7_hash16_value_b_0 = 0; 678 break; 679 case 2: /* reserved */ 680 hash_res->rtag7_hash16_value_b_0 = 0; 681 break; 682 case 3: /* CRC16 BISYNC */ 683 hash_res->rtag7_hash16_value_b_0 = hash_crc16_bisync; 684 break; 685 case 4: /* CRC16_XOR1 */ 686 hash_res->rtag7_hash16_value_b_0 = hash_xor1 & 0x1; 687 hash_res->rtag7_hash16_value_b_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 688 break; 689 case 5: /* CRC16_XOR2 */ 690 hash_res->rtag7_hash16_value_b_0 = hash_xor2 & 0x3; 691 hash_res->rtag7_hash16_value_b_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 692 break; 693 case 6: /* CRC16_XOR4 */ 694 hash_res->rtag7_hash16_value_b_0 = hash_xor4 & 0xf; 695 hash_res->rtag7_hash16_value_b_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 696 break; 697 case 7: /* CRC16_XOR8 */ 698 hash_res->rtag7_hash16_value_b_0 = hash_xor8 & 0xff; 699 hash_res->rtag7_hash16_value_b_0 |= (((hash_crc16_bisync >> 8) & 0xff) << 8); 700 break; 701 default: /* reserved */ 702 hash_res->rtag7_hash16_value_b_0 = 0; 703 break; 704 } 705 706 hash_res->rtag7_hash16_value_b_1 = 0; 707 708 /* End of option B hash calculation for rtag 7 */ 709 return BCM_E_NONE; 710 } 711 712 /*----------------------------------------------------------------*/ 713 714 715 716 STATIC int 717 select_en_hash_subfield(int hash_sub_sel, uint32 *selected_subfield, 718 bcm_rtag7_base_hash_t *hash_Base) 719 { 720 int rv = BCM_E_NONE; 721 *selected_subfield = 0; 722 723 switch (hash_sub_sel) { 724 case 0: /* select pkt hash A */ 725 *selected_subfield = hash_Base->rtag7_hash16_value_a_0; 726 if (!hash_Base->hash_a_valid) { 727 /* Missing paramter in input */ 728 rv = BCM_E_PARAM; 729 } 730 break; 731 732 case 1: /* select pkt hash B */ 733 *selected_subfield = hash_Base->rtag7_hash16_value_b_0; 734 if (!hash_Base->hash_b_valid) { 735 /* Missing paramter in input */ 736 rv = BCM_E_PARAM; 737 } 738 break; 739 740 case 2: /* select port LBN */ 741 *selected_subfield = hash_Base->rtag7_port_lbn; 742 break; 743 744 case 3: /* select destination port id or hash A */ 745 746 *selected_subfield = hash_Base->rtag7_hash16_value_a_0; 747 if (!hash_Base->hash_a_valid) { 748 /* Missing paramter in input */ 749 rv = BCM_E_PARAM; 750 } 751 break; 752 753 case 4: /* select LBID from module header or from SW1 stage */ 754 *selected_subfield = hash_Base->rtag7_lbid_hash; 755 if (!hash_Base->lbid_hash_valid) { 756 /* LBID setting isn't RTAG7 */ 757 rv = BCM_E_CONFIG; 758 } 759 break; 760 761 case 5: /* select LBID from SW1 stage */ 762 *selected_subfield = hash_Base->rtag7_lbid_hash; 763 if (!hash_Base->lbid_hash_valid) { 764 /* LBID setting isn't RTAG7 */ 765 rv = BCM_E_CONFIG; 766 } 767 break; 768 769 case 6: 770 case 7: 771 break; 772 } 773 774 return rv; 775 } 776 777 778 STATIC int 779 main__en_compute_lbid(int unit, bcm_rtag7_base_hash_t *hash_Base) 780 { 781 /*regular var declaration*/ 782 uint32 lbid_hash_sub_sel; 783 uint32 lbid_hash_offset; 784 uint32 lbid_hash_value = 0; 785 786 /*register var declaration*/ 787 int lbid_rtag; 788 uint8 rtag7_hash_cfg_sel_lbid; 789 uint32 rtag7_hash_lbid_reg; 790 int pc_out, sc_val, lbid_idx, rv = BCM_E_NONE; 791 792 /*register read*/ 793 BCM_IF_ERROR_RETURN 794 (bcm_esw_port_control_get(unit, hash_Base->dev_src_port, 795 bcmPortControlLoadBalancingNumber, 796 &pc_out)); 797 rtag7_hash_cfg_sel_lbid = pc_out; 798 BCM_IF_ERROR_RETURN 799 (bcm_esw_switch_control_get(unit, bcmSwitchLoadBalanceHashSelect, 800 &sc_val)); 801 lbid_rtag = sc_val; 802 803 /* ******************* LBID computation ************************* */ 804 805 if (lbid_rtag == 7) { 806 lbid_idx = (0 != rtag7_hash_cfg_sel_lbid) ? 1 : 0; 807 SOC_IF_ERROR_RETURN 808 (READ_RTAG7_HASH_LBIDr(unit, lbid_idx, &rtag7_hash_lbid_reg)); 809 if (hash_Base->is_nonuc) { 810 lbid_hash_sub_sel = 811 soc_reg_field_get(unit, RTAG7_HASH_LBIDr, 812 rtag7_hash_lbid_reg, SUB_SEL_NONUCf); 813 lbid_hash_offset = 814 soc_reg_field_get(unit, RTAG7_HASH_LBIDr, 815 rtag7_hash_lbid_reg, OFFSET_NONUCf); 816 } else { 817 lbid_hash_sub_sel = 818 soc_reg_field_get(unit, RTAG7_HASH_LBIDr, 819 rtag7_hash_lbid_reg, SUB_SEL_UCf); 820 lbid_hash_offset = 821 soc_reg_field_get(unit, RTAG7_HASH_LBIDr, 822 rtag7_hash_lbid_reg, OFFSET_UCf); 823 } 824 /* Only UC hash selects apply to ECMP */ 825 switch (lbid_hash_sub_sel) { 826 827 case 0: /* use pkt hash A */ 828 lbid_hash_value = hash_Base->rtag7_hash16_value_a_0; 829 if (!hash_Base->hash_a_valid) { 830 /* Missing paramter in input */ 831 rv = BCM_E_PARAM; 832 } 833 break; 834 835 case 1: /* use pkt hash B */ 836 lbid_hash_value = hash_Base->rtag7_hash16_value_b_0; 837 if (!hash_Base->hash_b_valid) { 838 /* Missing paramter in input */ 839 rv = BCM_E_PARAM; 840 } 841 break; 842 843 case 2: /* Use LBN */ 844 lbid_hash_value = hash_Base->rtag7_port_lbn; 845 break; 846 847 case 3: /* Use Destination PORTID or hash A */ 848 lbid_hash_value = hash_Base->rtag7_hash16_value_a_0; 849 if (!hash_Base->hash_a_valid) { 850 /* Missing paramter in input */ 851 rv = BCM_E_PARAM; 852 } 853 break; 854 855 case 4: /* Use LBID */ 856 /* Higig lookup use mh_higig2_lbid */ 857 858 lbid_hash_value = 0; 859 break; 860 861 case 5: 862 case 6: 863 case 7: 864 lbid_hash_value = 0; 865 break; 866 } 867 868 /* 869 * set up the hash value so that the LSB bits are 870 * barrel shifted in case offset > 8. 871 */ 872 lbid_hash_value |= ((lbid_hash_value & 0xffff) << 16); 873 874 /* Only UC hash offsets apply to ECMP */ 875 lbid_hash_value = (lbid_hash_value >> lbid_hash_offset); 876 877 hash_Base->rtag7_lbid_hash = (lbid_hash_value & 0xff); 878 hash_Base->lbid_hash_valid = TRUE; 879 880 } else { /* LBID rtag is 0-6 */ 881 /* this function not support the rtag 0-6 */ 882 883 LOG_VERBOSE(BSL_LS_BCM_COMMON, 884 (BSL_META_U(unit, 885 "Unit %d - Hash calculation: This function doesn't support rtag 0 6 pls change register ING_CONFIG.LBID_RTAG to value 7\n"), 886 unit)); 887 hash_Base->rtag7_lbid_hash = 0; 888 hash_Base->lbid_hash_valid = FALSE; 889 } 890 return rv; 891 /* ******************* END of LBID computation ************************* */ 892 } 893 894 #ifdef INCLUDE_L3 895 STATIC int 896 compute_en_ecmp_hash(int unit, bcm_rtag7_base_hash_t *hash_Base, 897 uint32 *hash_val) 898 { 899 /*regular var declaration*/ 900 uint32 hash_sub_sel; 901 uint32 hash_offset; 902 uint32 hash_subfield; 903 uint32 rtag7_ecmp_hash_value; 904 uint8 rtag7_ecmp_use_macro_flow_hash; 905 uint8 ecmp_hash_use_rtag7; 906 uint32 rtag7_hash_ecmp; 907 uint32 hash_control; 908 int pc_out, ecmp_idx; 909 rtag7_flow_based_hash_entry_t rt7_fbh_entry; 910 911 /*register read*/ 912 BCM_IF_ERROR_RETURN 913 (bcm_esw_port_control_get(unit, hash_Base->dev_src_port, 914 bcmPortControlECMPHashSet, 915 &pc_out)); 916 ecmp_idx = (0 != pc_out) ? 1 : 0; 917 918 SOC_IF_ERROR_RETURN 919 (READ_RTAG7_HASH_ECMPr(unit, ecmp_idx, &rtag7_hash_ecmp)); 920 if (soc_reg_field_valid(unit, RTAG7_HASH_ECMPr, USE_FLOW_HASHf)) { 921 rtag7_ecmp_use_macro_flow_hash = 922 soc_reg_field_get(unit, RTAG7_HASH_ECMPr, 923 rtag7_hash_ecmp, USE_FLOW_HASHf); 924 } else { 925 /* A0 bincomp value */ 926 rtag7_ecmp_use_macro_flow_hash = 0; 927 } 928 929 SOC_IF_ERROR_RETURN 930 (READ_HASH_CONTROLr(unit, &hash_control)); 931 ecmp_hash_use_rtag7 = 932 soc_reg_field_get(unit, HASH_CONTROLr, hash_control, 933 ECMP_HASH_USE_RTAG7f); 934 935 /* RTAG7 hash computation */ 936 937 if (rtag7_ecmp_use_macro_flow_hash) { 938 SOC_IF_ERROR_RETURN 939 (soc_mem_read(unit, RTAG7_FLOW_BASED_HASHm, MEM_BLOCK_ANY, 940 (hash_Base->rtag7_macro_flow_id & 0xff), 941 &rt7_fbh_entry)); 942 943 /* Generating RTAG7 Macro Flow Based Hash Subsel and Offset for use in RSEL1 Stage */ 944 /* For future designs this logic can be placed in RSEL1 */ 945 946 hash_sub_sel = soc_mem_field32_get(unit, RTAG7_FLOW_BASED_HASHm, 947 &rt7_fbh_entry, SUB_SEL_ECMPf); 948 hash_offset = soc_mem_field32_get(unit, RTAG7_FLOW_BASED_HASHm, 949 &rt7_fbh_entry, OFFSET_ECMPf); 950 951 } else if (SOC_REG_IS_VALID(unit, RTAG7_HASH_ECMPr)) { 952 hash_sub_sel = 953 soc_reg_field_get(unit, RTAG7_HASH_ECMPr, 954 rtag7_hash_ecmp, SUB_SELf); 955 hash_offset = 956 soc_reg_field_get(unit, RTAG7_HASH_ECMPr, 957 rtag7_hash_ecmp, OFFSETf); 958 } else { 959 /* A0 bincomp values */ 960 hash_sub_sel = 0; 961 hash_offset = 0; 962 } 963 964 BCM_IF_ERROR_RETURN 965 (select_en_hash_subfield(hash_sub_sel, &hash_subfield, hash_Base)); 966 967 /* Barrel shift the hash subfield, then take the LSB 5 bits */ 968 rtag7_ecmp_hash_value = ((hash_subfield >> hash_offset) | (hash_subfield << (16 - hash_offset))) & 0x1f; 969 970 /* Select between non-RTAG7 hash value and RTAG7 hash value */ 971 972 if (ecmp_hash_use_rtag7 == 0) { 973 LOG_VERBOSE(BSL_LS_BCM_COMMON, 974 (BSL_META_U(unit, 975 "Unit %d - Hash calculation: non rtag7 calc not supported\n"), 976 unit)); 977 *hash_val = 0; 978 } else { 979 *hash_val = rtag7_ecmp_hash_value; 980 } 981 982 return BCM_E_NONE; 983 /* ***************** END of ECMP HASH CALCULATIONS. ************************ */ 984 } 985 #endif /* INCLUDE_L3 */ 986 987 STATIC int 988 compute_en_rtag7_hash_trunk(int unit , bcm_rtag7_base_hash_t *hash_Base, 989 uint32 *hash_value) 990 { 991 uint32 hash_sub_sel; 992 uint32 hash_offset; 993 uint32 hash_subfield; 994 uint32 rtag7_hash_trunk; 995 uint32 rtag7_hash_trunk_value; 996 int offset_shift; 997 int pc_out, trunk_idx; 998 uint32 hash_control; 999 uint32 nuc_trunk_hash_use_rtag7; 1000 1001 BCM_IF_ERROR_RETURN 1002 (bcm_esw_port_control_get(unit, hash_Base->dev_src_port, 1003 bcmPortControlTrunkHashSet, 1004 &pc_out)); 1005 trunk_idx = (0 != pc_out) ? 1 : 0; 1006 SOC_IF_ERROR_RETURN 1007 (READ_RTAG7_HASH_TRUNKr(unit, trunk_idx, &rtag7_hash_trunk)); 1008 1009 /* Compute RTAG7 hash for trunking */ 1010 if(hash_Base->is_nonuc) { 1011 hash_sub_sel = 1012 soc_reg_field_get(unit, RTAG7_HASH_TRUNKr, 1013 rtag7_hash_trunk, SUB_SEL_NONUCf); 1014 hash_offset = 1015 soc_reg_field_get(unit, RTAG7_HASH_TRUNKr, 1016 rtag7_hash_trunk, OFFSET_NONUCf); 1017 offset_shift = 0xff; 1018 } else { 1019 hash_sub_sel = 1020 soc_reg_field_get(unit, RTAG7_HASH_TRUNKr, 1021 rtag7_hash_trunk, SUB_SEL_UCf); 1022 hash_offset = 1023 soc_reg_field_get(unit, RTAG7_HASH_TRUNKr, 1024 rtag7_hash_trunk, OFFSET_UCf); 1025 offset_shift = 0xff; 1026 } 1027 1028 BCM_IF_ERROR_RETURN 1029 (select_en_hash_subfield(hash_sub_sel, &hash_subfield, hash_Base)); 1030 1031 /* Barrel shift the hash subfield, then take the LSB 8 bits */ 1032 rtag7_hash_trunk_value = ((hash_subfield >> hash_offset) | (hash_subfield << (16 - hash_offset))) & offset_shift; 1033 1034 /* Compute the trunk_member_table index 1035 * trunk_index = trunk_hash % (trunk_group_size + 1); 1036 * Irsel2_rsel2__trunk_member_table_index = 1037 * (trunk_base_ptr + trunk_index) & 0x7ff; 1038 */ 1039 1040 *hash_value = rtag7_hash_trunk_value; 1041 1042 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1043 (BSL_META_U(unit, 1044 "Unit %d - Trunk hash_value=%d\n"), 1045 unit, *hash_value)); 1046 1047 BCM_IF_ERROR_RETURN 1048 (READ_HASH_CONTROLr(unit, &hash_control)); 1049 nuc_trunk_hash_use_rtag7 = 1050 soc_reg_field_get(unit, HASH_CONTROLr, hash_control, 1051 NON_UC_TRUNK_HASH_USE_RTAG7f); 1052 1053 if (hash_Base->is_nonuc && nuc_trunk_hash_use_rtag7 == 0) { 1054 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1055 (BSL_META_U(unit, 1056 "Unit %d - NonUC trunk Hash calculation: non rtag7 calc not supported\n"), 1057 unit)); 1058 *hash_value = 0; 1059 } 1060 1061 return BCM_E_NONE; 1062 } 1063 1064 STATIC int 1065 get_en_hash_trunk(int unit, int tgid, uint32 hash_index, bcm_gport_t *dst_gport) 1066 { 1067 uint32 trunk_group_size; 1068 uint32 rtag; 1069 uint32 trunk_index; 1070 bcm_module_t mod_id; 1071 bcm_port_t port_id; 1072 int mod_is_local; 1073 trunk_group_entry_t tg_entry; 1074 _bcm_gport_dest_t dest; 1075 1076 BCM_IF_ERROR_RETURN 1077 (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tgid, &tg_entry)); 1078 1079 trunk_group_size = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 1080 TG_SIZEf); 1081 rtag = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, RTAGf); 1082 1083 if (rtag != 7){ 1084 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1085 (BSL_META_U(unit, 1086 "Unit %d - Hash calculation: uport only RTAG7 calc no support for rtag %d\n"), 1087 unit, rtag)); 1088 } 1089 1090 trunk_index = hash_index % (trunk_group_size + 1); 1091 1092 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1093 (BSL_META_U(unit, 1094 "\tTrunk HW index 0x%08x\n"), 1095 trunk_index)); 1096 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1097 (BSL_META_U(unit, 1098 "\tTrunk group size 0x%08x\n"), 1099 trunk_group_size)); 1100 1101 mod_id = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 1102 _xgs_modulef[trunk_index]); 1103 port_id = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 1104 _xgs_portf[trunk_index]); 1105 1106 BCM_IF_ERROR_RETURN 1107 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, mod_id, port_id, 1108 &(dest.modid), &(dest.port))); 1109 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 1110 1111 BCM_IF_ERROR_RETURN 1112 (_bcm_esw_modid_is_local(unit, dest.modid, 1113 &mod_is_local)); 1114 if (mod_is_local) { 1115 if (IS_ST_PORT(unit, dest.port)) { 1116 dest.gport_type = _SHR_GPORT_TYPE_DEVPORT; 1117 } 1118 } 1119 1120 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, dst_gport)); 1121 1122 return BCM_E_NONE; 1123 } 1124 1125 /* 1126 * Function: 1127 * get_en_hash_trunk_nuc 1128 * Description: 1129 * Compute non-unicast destination trunk member port 1130 * Parameters: 1131 * unit - StrataSwitch PCI device unit number (driver internal). 1132 * tgid - Trunk group id 1133 * fwd_reason - Flow foward reason. unicast, ipmc, l2mc, broadcast, dlf. 1134 * hash_index - Hash value calculated based on RTAG7 1135 * dst_gport - Where egress member port id is stored 1136 * 1137 * Returns: 1138 * BCM_E_xxxx 1139 */ 1140 STATIC int 1141 get_en_hash_trunk_nuc(int unit, int tgid, 1142 bcm_switch_pkt_hash_info_fwd_reason_t fwd_reason, 1143 uint32 hash_index, bcm_gport_t *dst_gport) 1144 { 1145 int nuc_type; 1146 int nonuc_trunk_block_mask_index; 1147 int region_size, i, all_local; 1148 int member_index, member_count; 1149 int modid, modid_tmp, port, tid, id, mod_is_local; 1150 int port_index, count; 1151 bcm_pbmp_t pbmp, local_pbmp; 1152 bcm_trunk_info_t t_add_info; 1153 bcm_trunk_member_t member_array[BCM_TRUNK_MAX_PORTCNT]; 1154 trunk_bitmap_entry_t trunk_bitmap_entry; 1155 1156 switch(fwd_reason) { 1157 case bcmSwitchPktHashInfoFwdReasonIpmc: 1158 nuc_type = TRUNK_BLOCK_MASK_TYPE_IPMC; 1159 break; 1160 case bcmSwitchPktHashInfoFwdReasonL2mc: 1161 nuc_type = TRUNK_BLOCK_MASK_TYPE_L2MC; 1162 break; 1163 case bcmSwitchPktHashInfoFwdReasonBcast: 1164 nuc_type = TRUNK_BLOCK_MASK_TYPE_BCAST; 1165 break; 1166 case bcmSwitchPktHashInfoFwdReasonDlf: 1167 nuc_type = TRUNK_BLOCK_MASK_TYPE_DLF; 1168 break; 1169 default: 1170 return BCM_E_PARAM; 1171 } 1172 nonuc_trunk_block_mask_index = (nuc_type << 4) | (hash_index & 0xf); 1173 1174 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1175 (BSL_META_U(unit, 1176 "Unit %d - Nonuc-trunk table index = %d\n"), 1177 unit, nonuc_trunk_block_mask_index)); 1178 1179 region_size = soc_mem_index_count(unit, NONUCAST_TRUNK_BLOCK_MASKm) / 4; 1180 1181 BCM_IF_ERROR_RETURN( 1182 bcm_esw_trunk_get(unit, tgid, &t_add_info, BCM_TRUNK_MAX_PORTCNT, 1183 member_array, &member_count)); 1184 1185 BCM_IF_ERROR_RETURN( 1186 READ_TRUNK_BITMAPm(unit, MEM_BLOCK_ANY, tgid, &trunk_bitmap_entry)); 1187 BCM_PBMP_CLEAR(pbmp); 1188 BCM_PBMP_CLEAR(local_pbmp); 1189 soc_mem_pbmp_field_get(unit, TRUNK_BITMAPm, &trunk_bitmap_entry, 1190 TRUNK_BITMAPf, &local_pbmp); 1191 BCM_PBMP_COUNT(local_pbmp, count); 1192 all_local = FALSE; 1193 if (count == member_count) { 1194 all_local = TRUE; 1195 } 1196 if (all_local || member_count > BCM_SWITCH_TRUNK_MAX_PORTCNT) { 1197 member_index = 1198 (nonuc_trunk_block_mask_index % region_size) % member_count; 1199 } else { 1200 member_index = 1201 (nonuc_trunk_block_mask_index % BCM_XGS3_TRUNK_MAX_PORTCNT) % member_count; 1202 } 1203 1204 BCM_IF_ERROR_RETURN 1205 (_bcm_esw_gport_resolve(unit, member_array[member_index].gport, 1206 &modid, &port, &tid, &id)); 1207 port_index = 0; 1208 for (i = 0; i < member_count; i++) { 1209 BCM_IF_ERROR_RETURN 1210 (_bcm_esw_gport_resolve(unit, member_array[i].gport, 1211 &modid_tmp, &port, &tid, &id)); 1212 if (modid_tmp == modid) { 1213 if (i <= member_index) { 1214 port_index++; 1215 } 1216 BCM_PBMP_PORT_ADD(pbmp, port); 1217 } 1218 } 1219 1220 count = 0; 1221 BCM_PBMP_ITER(pbmp, port) { 1222 count++; 1223 if (count == port_index) { 1224 break; 1225 } 1226 } 1227 1228 if (count != port_index) { 1229 return BCM_E_FAIL; 1230 } 1231 1232 BCM_IF_ERROR_RETURN 1233 (_bcm_esw_modid_is_local(unit, modid, &mod_is_local)); 1234 1235 if (mod_is_local && IS_ST_PORT(unit, port)) { 1236 BCM_GPORT_DEVPORT_SET(*dst_gport, unit, port); 1237 } else { 1238 BCM_GPORT_MODPORT_SET(*dst_gport, modid, port); 1239 } 1240 1241 return BCM_E_NONE; 1242 } 1243 1244 #ifdef INCLUDE_L3 1245 STATIC int 1246 get_en_hash_ecmp(int unit, int ecmp_group, uint32 hash_index, bcm_if_t *nh_id) 1247 { 1248 ecmp_count_entry_t ecmpc_entry; 1249 ecmp_entry_t ecmp_entry; 1250 uint32 ecmp_ptr = 0; 1251 uint32 ecmp_count = 0; 1252 1253 uint32 ecmp_mask; 1254 uint32 ecmp_offset; 1255 uint32 ecmp_index; 1256 1257 /* pick up the ecmp count */ 1258 BCM_IF_ERROR_RETURN 1259 (READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group, &ecmpc_entry)); 1260 1261 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1262 * A ECMP_COUNT value of 0 implies 1 entry 1263 * a value of 1 implies 2 entries etc... 1264 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1265 */ 1266 ecmp_mask = 0x7ff; 1267 ecmp_count = 1268 soc_L3_ECMP_COUNTm_field32_get(unit, &ecmpc_entry, 1269 COUNTf); 1270 ecmp_offset = (hash_index % (ecmp_count + 1)) & 0x1F; 1271 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1272 (BSL_META_U(unit, 1273 "\tECMP offset 0x%08x\n"), 1274 ecmp_offset)); 1275 if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) { 1276 ecmp_group *= BCM_XGS3_L3_ECMP_MAX_PATHS(unit); 1277 } 1278 ecmp_ptr = (ecmp_group & ecmp_mask); 1279 ecmp_index = (ecmp_ptr + ecmp_offset) & ecmp_mask; 1280 BCM_IF_ERROR_RETURN 1281 (READ_L3_ECMPm(unit, MEM_BLOCK_ANY, ecmp_index, &ecmp_entry)); 1282 1283 *nh_id = 1284 soc_L3_ECMPm_field32_get(unit, &ecmp_entry, 1285 NEXT_HOP_INDEXf) & 0x3fff; 1286 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1287 (BSL_META_U(unit, 1288 "\tECMP next hop HW index 0x%08x\n"), 1289 *nh_id)); 1290 1291 return BCM_E_NONE; 1292 } 1293 #endif /* INCLUDE_L3 */ 1294 1295 /* 1296 * Function: 1297 * compute_en_rtag7_hash_hg_trunk 1298 * Description: 1299 * get HGT hash value from RTAG7_PORT_BASED_HASHm 1300 * if unicast, SUB_SEL_TRUNK_UCf and OFFSET_TRUNK_UCf are used 1301 * if not unicast, SUB_SEL_TRUNK_NONUCf and OFFSET_TRUNK_NONUCf 1302 * if flow hash is used, get subsel and offset from RTAG7_FLOW_BASED_HASH 1303 * Parameters: 1304 * unit - StrataSwitch PCI device unit number (driver internal). 1305 * hash_Base - internal data where trunk hash value is storead 1306 * hash_value- result param 1307 * Returns: 1308 * BCM_E_xxxx 1309 */ 1310 STATIC int 1311 compute_en_rtag7_hash_hg_trunk(int unit , bcm_rtag7_base_hash_t *hash_Base, 1312 uint32 *hash_value) 1313 { 1314 uint32 hash_sub_sel; 1315 uint32 hash_offset; 1316 uint32 hash_subfield; 1317 uint32 rtag7_hash_hg_trunk; 1318 uint32 rtag7_hash_hg_trunk_value; 1319 int offset_shift; 1320 int pc_out, trunk_idx; 1321 1322 BCM_IF_ERROR_RETURN 1323 (bcm_esw_port_control_get(unit, hash_Base->dev_src_port, 1324 bcmPortControlFabricTrunkHashSet, 1325 &pc_out)); 1326 trunk_idx = (0 != pc_out) ? 1 : 0; 1327 SOC_IF_ERROR_RETURN 1328 (READ_RTAG7_HASH_HG_TRUNKr(unit, trunk_idx, &rtag7_hash_hg_trunk)); 1329 1330 /* Compute RTAG7 hash for trunking */ 1331 if(hash_Base->is_nonuc) { 1332 hash_sub_sel = 1333 soc_reg_field_get(unit, RTAG7_HASH_HG_TRUNKr, 1334 rtag7_hash_hg_trunk, SUB_SEL_NONUCf); 1335 hash_offset = 1336 soc_reg_field_get(unit, RTAG7_HASH_HG_TRUNKr, 1337 rtag7_hash_hg_trunk, OFFSET_NONUCf); 1338 offset_shift = 0xff; 1339 } else { 1340 hash_sub_sel = 1341 soc_reg_field_get(unit, RTAG7_HASH_TRUNKr, 1342 rtag7_hash_hg_trunk, SUB_SEL_UCf); 1343 hash_offset = 1344 soc_reg_field_get(unit, RTAG7_HASH_TRUNKr, 1345 rtag7_hash_hg_trunk, OFFSET_UCf); 1346 offset_shift = 0xff; 1347 } 1348 1349 BCM_IF_ERROR_RETURN 1350 (select_en_hash_subfield(hash_sub_sel, &hash_subfield, hash_Base)); 1351 1352 /* Barrel shift the hash subfield, then take the LSB 8 bits */ 1353 rtag7_hash_hg_trunk_value = ((hash_subfield >> hash_offset) | (hash_subfield << (16 - hash_offset))) & offset_shift; 1354 1355 /* Compute the trunk_member_table index 1356 * trunk_index = trunk_hash % (trunk_group_size + 1); 1357 * Irsel2_rsel2__trunk_member_table_index = 1358 * (trunk_base_ptr + trunk_index) & 0x7ff; 1359 */ 1360 1361 *hash_value = rtag7_hash_hg_trunk_value; 1362 1363 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1364 (BSL_META_U(unit, 1365 "Unit %d - HG Trunk hash_value=%d\n"), 1366 unit, *hash_value)); 1367 1368 return BCM_E_NONE; 1369 } 1370 1371 STATIC int 1372 get_en_hash_hg_trunk(int unit, int tgid, uint32 hash_index, bcm_gport_t *dst_gport) 1373 { 1374 uint64 hg_trunk_group; 1375 uint32 trunk_group_size; 1376 uint32 rtag; 1377 uint32 trunk_index; 1378 bcm_module_t mod_id; 1379 bcm_port_t port_id; 1380 _bcm_gport_dest_t dest; 1381 1382 COMPILER_64_ZERO(hg_trunk_group); 1383 BCM_IF_ERROR_RETURN 1384 (READ_HG_TRUNK_GROUPr(unit, tgid, &hg_trunk_group)); 1385 1386 trunk_group_size = soc_reg64_field32_get(unit, HG_TRUNK_GROUPr, 1387 hg_trunk_group, 1388 HIGIG_TRUNK_SIZEf); 1389 1390 rtag = soc_reg64_field32_get(unit, HG_TRUNK_GROUPr, 1391 hg_trunk_group, 1392 HIGIG_TRUNK_RTAGf); 1393 1394 if (rtag != 7){ 1395 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1396 (BSL_META_U(unit, 1397 "Unit %d - Hash calculation: support only RTAG7 calc no support for rtag %d\n"), 1398 unit, rtag)); 1399 } 1400 1401 trunk_index = hash_index % (trunk_group_size + 1); 1402 1403 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1404 (BSL_META_U(unit, 1405 "\tTrunk HW index 0x%08x\n"), 1406 trunk_index)); 1407 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1408 (BSL_META_U(unit, 1409 "\tTrunk group size 0x%08x\n"), 1410 trunk_group_size)); 1411 1412 port_id = soc_reg64_field32_get(unit, HG_TRUNK_GROUPr, 1413 hg_trunk_group, 1414 _xgs_hg_portf[trunk_index]); 1415 1416 if (BCM_FAILURE(bcm_esw_stk_my_modid_get(unit, &mod_id))) { 1417 mod_id = 0; 1418 } 1419 1420 BCM_IF_ERROR_RETURN 1421 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, mod_id, port_id, 1422 &(dest.modid), &(dest.port))); 1423 dest.gport_type = _SHR_GPORT_TYPE_DEVPORT; 1424 1425 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, dst_gport)); 1426 1427 return BCM_E_NONE; 1428 } 1429 1430 int 1431 _bcm_en_switch_pkt_info_hash_get(int unit, 1432 bcm_switch_pkt_info_t *pkt_info, 1433 bcm_gport_t *dst_gport, 1434 bcm_if_t *dst_intf) 1435 { 1436 bcm_rtag7_base_hash_t hash_res; 1437 int pc_out; 1438 bcm_gport_t port; 1439 bcm_trunk_t tid; 1440 int id; 1441 uint32 hash_value; 1442 1443 if (pkt_info == NULL) { 1444 return BCM_E_PARAM; 1445 } 1446 1447 if (!_BCM_SWITCH_PKT_INFO_FLAG_TEST(pkt_info, SRC_GPORT)) { 1448 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1449 (BSL_META_U(unit, 1450 "Unit %d - Hash calculation: source gport value missing\n"), 1451 unit)); 1452 return BCM_E_PARAM; 1453 } 1454 1455 BCM_IF_ERROR_RETURN 1456 (_bcm_esw_gport_resolve(unit, pkt_info->src_gport, 1457 &(hash_res.src_modid), 1458 &(hash_res.src_port), 1459 &tid, &id)); 1460 if ((-1 != id) || (-1 != tid)) { 1461 /* Must be single system port */ 1462 return BCM_E_PORT; 1463 } 1464 1465 /* Load balancing retrieval */ 1466 BCM_IF_ERROR_RETURN 1467 (bcm_esw_port_local_get(unit, pkt_info->src_gport, &port)); 1468 hash_res.dev_src_port = port; 1469 BCM_IF_ERROR_RETURN 1470 (bcm_esw_port_control_get(unit, port, 1471 bcmPortControlLoadBalancingNumber, 1472 &pc_out)); 1473 hash_res.rtag7_port_lbn = pc_out; 1474 1475 /* check if the foward reason of packet is all non-uc packet or bit 40 in the mac DA is one. */ 1476 hash_res.is_nonuc = pkt_info->fwd_reason || BCM_MAC_IS_MCAST(pkt_info->dst_mac); 1477 1478 BCM_IF_ERROR_RETURN 1479 (main__en_do_rtag7_hashing(unit, pkt_info, &hash_res)); 1480 BCM_IF_ERROR_RETURN 1481 (main__en_compute_lbid(unit, &hash_res)); 1482 1483 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1484 (BSL_META_U(unit, 1485 "Unit %d - Hash status: \n"), 1486 unit)); 1487 if (hash_res.hash_a_valid) { 1488 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1489 (BSL_META_U(unit, 1490 "\tRTAG7 A0 0x%08x\n"), 1491 hash_res.rtag7_hash16_value_a_0)); 1492 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1493 (BSL_META_U(unit, 1494 "\tRTAG7 A1 0x%08x\n"), 1495 hash_res.rtag7_hash16_value_a_1)); 1496 } else { 1497 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1498 (BSL_META_U(unit, 1499 "\tRTAG7 A hashes invalid due to missing packet info\n"))); 1500 } 1501 if (hash_res.hash_b_valid) { 1502 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1503 (BSL_META_U(unit, 1504 "\tRTAG7 B0 0x%08x\n"), 1505 hash_res.rtag7_hash16_value_b_0)); 1506 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1507 (BSL_META_U(unit, 1508 "\tRTAG7 B1 0x%08x\n"), 1509 hash_res.rtag7_hash16_value_b_1)); 1510 } else { 1511 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1512 (BSL_META_U(unit, 1513 "\tRTAG7 B hashes invalid due to missing packet info\n"))); 1514 } 1515 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1516 (BSL_META_U(unit, 1517 "\tRTAG7 LBN 0x%08x\n"), 1518 hash_res.rtag7_port_lbn)); 1519 if (hash_res.lbid_hash_valid){ 1520 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1521 (BSL_META_U(unit, 1522 "\tRTAG7 LBID 0x%08x\n"), 1523 hash_res.rtag7_lbid_hash)); 1524 } else { 1525 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1526 (BSL_META_U(unit, 1527 "\tRTAG7 LBID not valid due to non-RTAG7 configuration\n"))); 1528 } 1529 1530 #ifdef INCLUDE_L3 1531 if (0 != (pkt_info->flags & BCM_SWITCH_PKT_INFO_HASH_MULTIPATH)) { 1532 bcm_if_t nh_id; 1533 1534 if (dst_intf == NULL) { 1535 return BCM_E_PARAM; 1536 } 1537 1538 BCM_IF_ERROR_RETURN 1539 (compute_en_ecmp_hash(unit, &hash_res, &hash_value)); 1540 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1541 (BSL_META_U(unit, 1542 "\tECMP Hash value 0x%08x\n"), 1543 hash_value)); 1544 1545 BCM_IF_ERROR_RETURN 1546 (get_en_hash_ecmp(unit, 1547 pkt_info->mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), 1548 hash_value, &nh_id)); 1549 /* Convert to egress object format */ 1550 *dst_intf = nh_id + BCM_XGS3_EGRESS_IDX_MIN(unit); 1551 } else 1552 #endif /* INCLUDE_L3 */ 1553 if (0 != (pkt_info->flags & BCM_SWITCH_PKT_INFO_HASH_TRUNK)) { 1554 bcm_trunk_t trunk = BCM_TRUNK_INVALID; 1555 int member_count; 1556 bcm_trunk_chip_info_t ti; 1557 1558 if (dst_gport == NULL) { 1559 return BCM_E_PARAM; 1560 } 1561 1562 if (!BCM_GPORT_IS_TRUNK(pkt_info->trunk_gport)) { 1563 return BCM_E_PORT; 1564 } 1565 trunk = BCM_GPORT_TRUNK_GET(pkt_info->trunk_gport); 1566 BCM_IF_ERROR_RETURN 1567 (bcm_esw_trunk_get(unit, trunk, NULL, 0, NULL, &member_count)); 1568 if (0 == member_count) { 1569 /* Return failure for no trunk members */ 1570 return BCM_E_FAIL; 1571 } 1572 1573 BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &ti)); 1574 1575 if (trunk >= ti.trunk_id_min && trunk <= ti.trunk_id_max) { 1576 BCM_IF_ERROR_RETURN 1577 (compute_en_rtag7_hash_trunk(unit, &hash_res, &hash_value)); 1578 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1579 (BSL_META_U(unit, 1580 "\tTrunk Hash value 0x%08x\n"), 1581 hash_value)); 1582 if (hash_res.is_nonuc) { 1583 BCM_IF_ERROR_RETURN 1584 (get_en_hash_trunk_nuc(unit, trunk, pkt_info->fwd_reason, 1585 hash_value, dst_gport)); 1586 } else { 1587 BCM_IF_ERROR_RETURN 1588 (get_en_hash_trunk(unit, trunk, 1589 hash_value, dst_gport)); 1590 } 1591 } else if (trunk >= ti.trunk_fabric_id_min && trunk <= ti.trunk_fabric_id_max) { 1592 1593 BCM_IF_ERROR_RETURN 1594 (compute_en_rtag7_hash_hg_trunk(unit, &hash_res, &hash_value)); 1595 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1596 (BSL_META_U(unit, 1597 "\tHG-Trunk Hash value 0x%08x\n"), 1598 hash_value)); 1599 1600 BCM_IF_ERROR_RETURN 1601 (get_en_hash_hg_trunk(unit, trunk - ti.trunk_fabric_id_min, 1602 hash_value, dst_gport)); 1603 } else { 1604 return BCM_E_UNAVAIL; 1605 } 1606 } else if (pkt_info->flags & BCM_SWITCH_PKT_INFO_HASH_LBID) { 1607 /* LBID hashing resolution */ 1608 if (dst_intf == NULL || hash_res.lbid_hash_valid == 0) { 1609 return BCM_E_FAIL; 1610 } else { 1611 *dst_intf = hash_res.rtag7_lbid_hash; 1612 } 1613 } else { 1614 return BCM_E_PARAM; 1615 } 1616 1617 return BCM_E_NONE; 1618 } 1619