util.c (150606B)
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 * Diagnostic shell support utilities. 8 * These routines aren't necessary for the driver itself. 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <sal/core/libc.h> 14 #include <sal/appl/sal.h> 15 #include <sal/types.h> 16 #include <shared/bsl.h> 17 #include <soc/mem.h> 18 19 #include <bcm/pkt.h> 20 #include <bcm/field.h> 21 #include <bcm/stack.h> 22 #include <bcm/error.h> 23 #include <bcm/l3.h> 24 #include <bcm/tunnel.h> 25 #include <bcm/rx.h> 26 #if defined(BCM_ESW_SUPPORT) 27 #include <bcm_int/esw/l2.h> 28 #endif 29 30 #include <appl/diag/system.h> 31 #include <appl/diag/diag.h> 32 #include <appl/diag/dport.h> 33 #include <sal/appl/io.h> 34 35 #ifdef BCM_CMICM_SUPPORT 36 #include <soc/cmicm.h> 37 #endif 38 39 #if defined(BCM_ESW_SUPPORT) 40 #include <bcm_int/esw/port.h> 41 #endif 42 43 #if defined(BCM_PETRA_SUPPORT) 44 #include <soc/dpp/drv.h> 45 #endif 46 #if defined(BCM_DFE_SUPPORT) 47 #include <soc/dfe/cmn/dfe_drv.h> 48 #endif 49 50 #if defined(BCM_ESW_SUPPORT) 51 #include <bcm_int/esw/field.h> 52 #endif 53 54 #include <bcm_int/api_xlate_port.h> 55 56 typedef struct _bcm_util_gport_dest_s { 57 bcm_port_t port; 58 bcm_module_t modid; 59 bcm_trunk_t tgid; 60 int mpls_id; 61 int mim_id; 62 int wlan_id; 63 int subport_id; 64 int subport_group_id; 65 int vlan_port_id; 66 int vxlan_id; 67 int trill_id; 68 int niv_id; 69 int l2gre_id; 70 int extender_id; 71 int scheduker_id; 72 uint32 gport_type; 73 } _bcm_util_gport_dest_t; 74 75 /* 76 * strcaseindex: case insensitive substring search 77 * Find substring 'sub' within string 's'. 78 * Return pointer to substring within 's', NULL if not found. 79 */ 80 81 const char * 82 strcaseindex(const char *s, const char *sub) 83 { 84 int len; 85 86 for (len = sal_strlen(sub); *s; s++) { 87 if (sal_strncasecmp(s, sub, len) == 0) { 88 return s; 89 } 90 } 91 92 return 0; 93 } 94 95 /* 96 * strrepl: string replace 97 * Delete 'len' characters from position 'start' in string 's', 98 * and insert 'repstr' at the deletion point. 99 */ 100 101 char * 102 strrepl(char *s, int start, int len, const char *repstr) 103 { 104 memmove(s + start + sal_strlen(repstr), 105 s + start + len, 106 sal_strlen(s + start + len) + 1); 107 memmove(s + start, repstr, sal_strlen(repstr)); 108 109 return s; 110 } 111 112 /* 113 * Convert hex digit to hex character 114 */ 115 116 int 117 i2xdigit(int digit) 118 { 119 digit &= 0xf; 120 121 return (digit > 9) ? digit - 10 + 'a' : digit + '0'; 122 } 123 124 /* 125 * Convert hex character to digit 126 */ 127 128 int 129 xdigit2i(int digit) 130 { 131 if (digit >= '0' && digit <= '9') return (digit - '0' ); 132 if (digit >= 'a' && digit <= 'f') return (digit - 'a' + 10); 133 if (digit >= 'A' && digit <= 'F') return (digit - 'A' + 10); 134 return 0; 135 } 136 137 /* 138 * tabify_line 139 * 140 * Tabifies a string assuming a given tab_width. 141 * 142 * Output buffer should have at least as many characters as input 143 * string plus the NUL terminator. 144 */ 145 146 void 147 tabify_line(char *out, char *in, int tab_width) 148 { 149 int col = 0; 150 151 if (tab_width < 2) { 152 tab_width = 1; 153 } 154 155 while (*in) { 156 int ts; /* Spaces to next tab stop */ 157 int ns; /* Spaces that can be eaten from input */ 158 159 ts = col + tab_width - (col % tab_width) - col; 160 161 for (ns = 0; ns < ts && in[ns] == ' '; ns++) 162 ; 163 164 if (ts > 1 && ns >= ts) { 165 *out++ = '\t'; 166 col += ts; 167 in += ts; 168 } else { 169 *out++ = *in++; 170 col++; 171 } 172 } 173 174 *out = 0; 175 } 176 177 /* 178 * parse_rand 179 * 180 * Returns non-zero if the string is of the form 181 * rand(x) 182 * or 183 * rand(x,y) 184 * and zero otherwise. 185 * 186 * In the case of rand(x), val receives a random value between 0 187 * and x-1, inclusive. 188 * 189 * In the case of rand(x,y), val receives a random value between x 190 * and y, inclusive. 191 */ 192 193 int 194 parse_rand(char *str, uint32 *val) 195 { 196 uint32 min, max, rnd32; 197 198 if (sal_strncasecmp(str, "rand(", 5) != 0) { 199 return 0; 200 } 201 202 min = sal_ctoi(str + 5, &str); 203 204 if (*str == ',') { 205 max = sal_ctoi(str + 1, &str); 206 } else { 207 max = min - 1; 208 min = 0; 209 } 210 211 if (*str != ')') { 212 return 0; 213 } 214 215 rnd32 = (sal_rand() << 17 ^ 216 sal_rand() << 13 ^ 217 sal_rand() << 5 ^ 218 sal_rand() >> 3); 219 220 if (max - min + 1 == 0) { 221 *val = 0; 222 } else { 223 *val = min + rnd32 % (max - min + 1); 224 } 225 226 return 1; 227 } 228 229 /* 230 * Return true if a constant is a well-formed integer of the type 231 * supported by parse_integer. 232 */ 233 234 int 235 isint(char *s) 236 { 237 int base; 238 uint32 dummy; 239 240 if (s == NULL) { 241 return 0; 242 } 243 244 if (parse_rand(s, &dummy)) { 245 return 1; 246 } 247 248 if (*s == '-') { 249 s++; 250 } 251 252 if (*s == '0') { 253 if (s[1] == 'b' || s[1] == 'B') { 254 base = 2; 255 s += 2; 256 } else if (s[1] == 'x' || s[1] == 'X') { 257 base = 16; 258 s += 2; 259 } else 260 base = 8; 261 } else { 262 base = 10; 263 } 264 265 do { 266 if (!isxdigit((unsigned) *s) || xdigit2i(*s) >= base) { 267 return(0); 268 } 269 } while (*++s); 270 271 return(1); 272 } 273 274 /* 275 * Read an integer: return unsigned representation. 276 * Number format explained below. 277 * 278 * Expects: 279 * [-]0x[0-9|A-F|a-f]+ -hexadecimal if the string begins with "0x" 280 * [-][0-9]+ -decimal integer 281 * [-]0[0-7]+ -octal integer 282 * [-]0b[0-1]+ -binary if the string begins with "0b" 283 */ 284 285 uint32 286 parse_integer(char *str) 287 { 288 uint32 rnd; 289 290 if (parse_rand(str, &rnd)) { 291 return rnd; 292 } 293 294 if (!isint(str)) { 295 cli_out("WARNING: truncated malformed integer \"%s\"\n", str); 296 } 297 298 return _shr_ctoi(str); 299 } 300 301 /* 302 * Read string of integer 303 * argument s is a string with integers smaller than 32, sepereted by some char that is not digit 304 * the return pbmp is a pbmp of this numbers. 305 * if one of the numbers on the string is in hex form "0x" its taken as bit map. 306 * if "-1" set one to all bit map. 307 * example from: "0xf,7" - it will fill the bit pbmp : 1 1 1 1 0 0 0 1 308 */ 309 int 310 parse_small_integers(int unit, char *s, soc_pbmp_t *pbmp) 311 { 312 int integer, i; 313 314 BCM_PBMP_CLEAR(*pbmp); 315 316 while (*s != 0) { 317 318 if ((*s <= '9') && (*s >= '0')) { 319 integer = _shr_ctoi(s); 320 321 /* if the number is in hex form use it as bit map */ 322 if ((*s=='0' && ((*(s+1)=='x') || (*(s+1) == 'X'))) ) { 323 for(i=0; i<32; ++i) { 324 325 if (integer & (1 << i)) { 326 BCM_PBMP_PORT_ADD(*pbmp, i); 327 } 328 } 329 s = s+2; 330 331 } /* alse - block index */ 332 else if ((integer >= 0) && (integer < 32)) { 333 BCM_PBMP_PORT_ADD(*pbmp, integer); 334 } 335 336 while ((*s <= '9') && (*s >= '0')) { 337 ++s; 338 } 339 340 } 341 342 if (*s == '-' && *(s+1) == '1') { 343 for(i=0; i<32; ++i) { 344 BCM_PBMP_PORT_ADD(*pbmp, i); 345 } 346 347 break; 348 349 } 350 351 if (*s != 0) { 352 ++s; 353 } 354 } 355 356 return 0; 357 } 358 359 sal_vaddr_t 360 parse_address(char *str) 361 { 362 if (!isint(str)) { 363 cli_out("WARNING: truncated malformed address \"%s\"\n", str); 364 } 365 366 return _shr_ctoa(str); 367 } 368 369 /* 370 * --------------------------------------------------------------------------- 371 * Long Integer Support 372 * --------------------------------------------------------------------------- 373 * 374 * Long integers consist of a variable length array of uint32. 375 * 376 * Within the array, the least significant word comes first. This is 377 * true on all platforms. However, each word itself is stored in the 378 * platform native byte order. 379 */ 380 381 /* 382 * Read a long integer: can read a long hex integer, or a regular 383 * integer in any base supported by parse_integer. 384 * 385 * val[0] receives the least significant word (little-endian). 386 * nbuf is the number size (count of uint32's). 387 */ 388 389 void 390 parse_long_integer(uint32 *val, int nval, char *str) 391 { 392 char eight[11], *s, *t; 393 int i, neg; 394 395 if (*str == '-') { 396 neg = 1; 397 str++; 398 } else { 399 neg = 0; 400 } 401 402 sal_memset(val, 0, nval * sizeof (*val)); 403 404 if (parse_rand(str, &val[0])) { 405 goto done; 406 } 407 408 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { 409 val[0] = parse_integer(str); 410 goto done; 411 } 412 413 /* Skip to the last hex digit in the string */ 414 415 for (s = str + 1; isxdigit((unsigned) s[1]); s++) { 416 ; 417 } 418 419 /* Parse backward in groups of 8 digits */ 420 421 i = 0; 422 423 do { 424 /* Copy 8 digits backward to form a string "0xdddddddd\0" */ 425 t = eight + 11; 426 *--t = 0; 427 while (t > eight + 2 && (*s != 'x' && *s != 'X')) { 428 *--t = *s--; 429 } 430 *--t = 'x'; 431 *--t = '0'; 432 433 val[i++] = parse_integer(t); 434 } while ((*s != 'x' && *s != 'X') && i < nval); 435 436 done: 437 if (neg) { 438 uint32 cy = 1; 439 for (i = 0; i < nval; i++) { 440 if ((val[i] = (~val[i]) + cy) != 0) { 441 cy = 0; 442 } 443 } 444 } 445 } 446 447 /* 448 * Format a long integer. If the value is less than 10, generates 449 * decimal, otherwise generates hex. 450 * 451 * val[0] is the least significant word. 452 * nval is the number of uint32's in the value. 453 */ 454 455 void 456 format_long_integer(char *buf, uint32 *val, int nval) 457 { 458 int i; 459 460 for (i = nval - 1; i > 0; i--) { /* Skip leading zeroes */ 461 if (val[i]) { 462 break; 463 } 464 } 465 466 if (i == 0 && val[i] < 10) { /* Only a single word < 10? */ 467 sal_sprintf(buf, "%d", val[i]); 468 } else { 469 sal_sprintf(buf, "0x%x", val[i]); /* Print first word */ 470 } 471 472 while (--i >= 0) { /* Print rest of words, if any */ 473 sal_sprintf(buf + sal_strlen(buf), "%08x", val[i]); 474 } 475 } 476 477 void 478 format_spec_long_integer(char *buf, uint32 *val, int nval) 479 { 480 int i = nval - 1; 481 482 sal_sprintf(buf, "0x%08X", val[i]); 483 484 while (--i >= 0) { /* Print rest of words, if any */ 485 sal_sprintf(buf + sal_strlen(buf), " "); 486 sal_sprintf(buf + sal_strlen(buf), "0x%08X", val[i]); 487 } 488 } 489 490 /* 491 * Add long integers. 492 */ 493 494 void 495 add_long_integer(uint32 *dst, uint32 *src, int nval) 496 { 497 int i; 498 uint32 tmp, new_cy, cy = 0; 499 500 for (i = 0; i < nval; i++, cy = new_cy) { 501 tmp = dst[i]; /* Add digits, detect overflow */ 502 dst[i] += src[i]; 503 new_cy = (dst[i] < tmp); 504 tmp = dst[i]; /* Add carry, detect overflow */ 505 dst[i] += cy; 506 new_cy += (dst[i] < tmp); 507 } 508 } 509 510 /* 511 * Subtract long integers. 512 */ 513 514 void 515 sub_long_integer(uint32 *dst, uint32 *src, int nval) 516 { 517 int i; 518 uint32 tmp, new_br, br = 0; 519 520 for (i = 0; i < nval; i++, br = new_br) { 521 tmp = dst[i]; /* Sub digits, detect underflow */ 522 dst[i] -= src[i]; 523 new_br = (dst[i] > tmp); 524 tmp = dst[i]; /* Sub carry, detect underflow */ 525 dst[i] -= br; 526 new_br += (dst[i] > tmp); 527 } 528 } 529 530 /* 531 * Negate long integer. 532 */ 533 534 void 535 neg_long_integer(uint32 *dst, int nval) 536 { 537 int i; 538 uint32 tmp, new_br, br = 0; 539 540 for (i = 0; i < nval; i++, br = new_br) { 541 dst[i] = -dst[i]; 542 new_br = (dst[i] > 0); 543 tmp = dst[i]; /* Sub carry, detect overflow */ 544 dst[i] -= br; 545 new_br += (dst[i] > tmp); 546 } 547 } 548 549 /* 550 * Parse uint64 551 * Endian handling is taken into account. 552 */ 553 554 uint64 555 parse_uint64(char *str) 556 { 557 uint32 tmpval[2]; 558 uint64 rval; 559 560 parse_long_integer(tmpval, 2, str); 561 COMPILER_64_SET(rval, tmpval[1], tmpval[0]); 562 563 return rval; 564 } 565 566 /* 567 * Format uint64 568 * Endian handling is taken into account. 569 */ 570 571 void 572 format_uint64(char *buf, uint64 n) 573 { 574 uint32 val[2]; 575 576 val[0] = COMPILER_64_LO(n); 577 val[1] = COMPILER_64_HI(n); 578 579 format_long_integer(buf, val, 2); 580 } 581 582 /* 583 * Format uint64 as unsigned decimal. 584 * 585 * Comma should be one of: 586 * ',' to use commas every third digit 587 * '.' to use periods every third digit 588 * '\0' no commas or periods 589 * 590 * The buffer must have room for up to 21 bytes (if no commas or 591 * periods) or 27 bytes (commas or periods). 592 */ 593 594 void 595 format_uint64_decimal(char *buf, uint64 n, int comma) 596 { 597 int pw; 598 char *obuf; 599 600 static CONST struct pow10_s { 601 uint32 hi, lo; 602 } pow10[] = { 603 { 0U, 1U }, 604 { 0U, 10U }, 605 { 0U, 100U }, 606 { 0U, 1000U }, 607 { 0U, 10000U }, 608 { 0U, 100000U }, 609 { 0U, 1000000U }, 610 { 0U, 10000000U }, 611 { 0U, 100000000U }, 612 { 0U, 1000000000U }, 613 { 2U, 1410065408U }, 614 { 23U, 1215752192U }, 615 { 232U, 3567587328U }, 616 { 2328U, 1316134912U }, 617 { 23283U, 276447232U }, 618 { 232830U, 2764472320U }, 619 { 2328306U, 1874919424U }, 620 { 23283064U, 1569325056U }, 621 { 232830643U, 2808348672U }, 622 { 2328306436U, 2313682944U }, 623 }; 624 625 obuf = buf; 626 627 for (pw = 19; pw >= 0; pw--) { 628 uint64 p10; 629 int digit; 630 631 COMPILER_64_SET(p10, pow10[pw].hi, pow10[pw].lo); 632 633 for (digit = '0'; COMPILER_64_GE(n, p10); digit++) { 634 COMPILER_64_SUB_64(n, p10); 635 } 636 637 if (buf > obuf || digit != '0') { 638 *buf++ = digit; 639 if (comma != 0 && (pw % 3) == 0 && pw > 0) { 640 *buf++ = comma; 641 } 642 } 643 } 644 645 if (buf == obuf) { 646 *buf++ = '0'; 647 } 648 649 *buf = 0; 650 } 651 652 /* 653 * Parse a mac address that comes from a pure hex number. 654 * The leading 0x is assumed to have been stripped off. 655 * String can be up to 12 characters long. 656 * 657 * Process string from end. 658 */ 659 660 int 661 parse_macaddr_hex(char *str, sal_mac_addr_t macaddr) 662 { 663 char *s; 664 int i; 665 666 sal_memset(macaddr, 0, 6); 667 if ((sal_strlen(str) > 12) || (sal_strlen(str) == 0)) { 668 return -1; 669 } 670 s = str + sal_strlen(str) - 1; 671 for (i = 0; i < 6; i++) { 672 if (s < str) { /* done w/ string; fill w/ 0. */ 673 macaddr[5-i] = 0; 674 } else { 675 if (!isxdigit((unsigned) *s)) { /* bad character */ 676 return -1; 677 } 678 macaddr[5-i] = xdigit2i((unsigned) *(s--)); 679 if (isxdigit((unsigned) *s)) { 680 macaddr[5-i] += 16 * xdigit2i((unsigned) *(s--)); 681 } 682 } 683 } 684 685 return 0; 686 } 687 688 /* 689 * parse_macaddr will take a string of the form H:H:H:H:H:H where each 690 * H is one or two hex digits, or a string of the form 0xN where N may 691 * consist of up to 12 hex digits. The result is returned in a byte 692 * array to avoid endian confusion. 693 */ 694 695 int 696 parse_macaddr(char *str, sal_mac_addr_t macaddr) 697 { 698 char *s; 699 int i; 700 701 if (sal_strchr(str, ':')) { /* Colon format */ 702 s = str; 703 for (i = 0; i < 6; i++) { 704 if (!isxdigit((unsigned)*s)) { /* bad character */ 705 return -1; 706 } 707 macaddr[i] = xdigit2i((unsigned)*(s++)); 708 if (isxdigit((unsigned)*s)) { 709 macaddr[i] *= 16; 710 macaddr[i] += xdigit2i((unsigned)*(s++)); 711 } 712 if ((i < 5) && (*(s++) != ':')) { /* bad character */ 713 return -1; 714 } 715 } 716 if (*s) { 717 return -1; 718 } 719 } else if (str[0] == '0' && sal_tolower((int)str[1]) == 'x') { 720 return parse_macaddr_hex(&(str[2]), macaddr); 721 } else { /* Handle 0x... format */ 722 return -1; 723 } 724 725 return 0; 726 } 727 728 /* 729 * format_macaddr requires a buffer of 18 bytes minimum. 730 * It does not use sal_sprintf so it can be called from an interrupt context. 731 */ 732 733 void 734 format_macaddr(char buf[SAL_MACADDR_STR_LEN], sal_mac_addr_t macaddr) 735 { 736 int i; 737 738 for (i = 0; i <= 5; i++) { 739 *buf++ = i2xdigit(macaddr[i] >> 4); 740 *buf++ = i2xdigit(macaddr[i]); 741 *buf++ = ':'; 742 } 743 744 *--buf = 0; 745 } 746 747 /* 748 * increment_macaddr 749 */ 750 751 void 752 increment_macaddr(sal_mac_addr_t macaddr, int amount) 753 { 754 int i, v; 755 for (i = 5; i >= 0; i--) { 756 v = (int) macaddr[i] + amount; 757 macaddr[i] = v; 758 if (v >= 0 && v <= 255) 759 break; 760 amount = v >> 8; /* carry or borrow (signed shift) */ 761 } 762 } 763 764 int 765 parse_ipaddr(char *s, ip_addr_t *ipaddr) 766 { 767 char *ts; 768 int i, x; 769 ip_addr_t ip = 0; 770 771 if (sal_strchr(s, '.')) { /* dotted notation */ 772 for (i = 0; i < 4; i++) { 773 x = sal_ctoi(s, &ts); 774 if ((x > 0xff) || (x < 0)) { 775 return(-1); 776 } 777 ip = (ip << 8) | x; 778 if (*ts != '.') { /* End of string */ 779 break; 780 } 781 s = ts + 1; 782 } 783 if (((i != 3) || (*ts != '\0'))) { 784 return(-1); 785 } else { 786 *ipaddr = ip; 787 return(0); 788 } 789 } else if (isint(s)){ 790 *ipaddr = parse_integer(s); 791 return(0); 792 } else { 793 return(-1); 794 } 795 } 796 797 static INLINE int 798 colon_count(char *s) 799 { 800 int cc = 0; 801 char *ts = s; 802 803 while ((ts = sal_strchr(ts, ':')) != NULL) { 804 ts++; 805 cc++; 806 } 807 808 return cc; 809 } 810 811 int 812 parse_ip6addr(char *s, ip6_addr_t ipaddr) 813 { 814 char *ts; 815 int i, x; 816 int has_dcolon = 0; /* double colon */ 817 char *dstr = s; 818 char str_buf[50]; 819 char *tmps = &str_buf[0]; 820 uint8 *ip = (uint8 *)ipaddr; 821 822 while ((dstr = sal_strstr(dstr, "::")) != NULL) { 823 dstr += 2; 824 has_dcolon++; 825 } 826 if (has_dcolon > 1) { 827 return(-1); 828 } else if (has_dcolon == 1) { 829 dstr -= 2; 830 } 831 832 sal_memset(ipaddr, 0, sizeof (ip6_addr_t)); 833 if (sal_strchr(s, ':')) { /* colon notation */ 834 sal_strncpy(&tmps[2], s, 47); 835 tmps[49] = '\0'; 836 for (i = 0; i < 8; i++) { 837 tmps[0] = '0'; 838 tmps[1] = 'x'; 839 x = sal_ctoi(tmps, &ts); 840 if ((x > 0xffff) || (x < 0)) { 841 return(-1); 842 } 843 844 /* double colon, heading double colon not supported */ 845 if (has_dcolon && *ts == ':' && ts == &tmps[2]) { 846 int end; 847 int cc = colon_count(ts); 848 if (cc > 8) { 849 return (-1); 850 } 851 end = 8 - cc; 852 for (;i < end; i++) { 853 ip[2 * i] = 0; 854 ip[2 * i + 1] = 0; 855 } 856 i--; 857 tmps = ts - 1; 858 /* :: will be replaced by 0x */ 859 continue; 860 } 861 862 /* double colon, heading double colon not supported */ 863 if (has_dcolon && *ts == ':' && ts == &tmps[2]) { 864 int end; 865 int cc = colon_count(ts); 866 if (cc > 8) { 867 return (-1); 868 } 869 end = 8 - cc; 870 for (;i < end; i++) { 871 ip[2 * i] = 0; 872 ip[2 * i + 1] = 0; 873 } 874 i--; 875 tmps = ts - 1; 876 /* :: will be replaced by 0x */ 877 continue; 878 } 879 880 ip[2 * i] = (x >> 8) & 0xFF; 881 ip[2 * i + 1] = x & 0xFF; 882 if (*ts != ':') { /* End of string */ 883 break; 884 } 885 tmps = ts - 1; 886 } 887 if (((i != 7) || (*ts != '\0'))) { 888 return(-1); 889 } else { 890 return(0); 891 } 892 } else { 893 return(-1); 894 } 895 } 896 897 /* 898 * To be useful the incremnent position should also be specified 899 */ 900 void 901 increment_ip6addr(ip6_addr_t ipaddr, uint32 byte_pos, int amount) 902 { 903 int i, v; 904 if (byte_pos >= sizeof(ip6_addr_t)) { 905 return; 906 } 907 for (i = byte_pos; i >= 0; i--) { 908 v = (int) ipaddr[i] + amount; 909 ipaddr[i] = v; 910 if (v >= 0 && v <= 255) 911 break; 912 amount = v >> 8; /* carry or borrow (signed shift) */ 913 } 914 } 915 916 void 917 format_ipaddr(char buf[SAL_IPADDR_STR_LEN], ip_addr_t ipaddr) 918 { 919 sal_sprintf(buf, "%d.%d.%d.%d", 920 (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, 921 (ipaddr >> 8) & 0xff, ipaddr & 0xff); 922 } 923 924 void 925 format_ipaddr_mask(char *buf, ip_addr_t ipaddr, ip_addr_t mask) 926 { 927 int masklen, i; 928 929 /* Convert netmask to number of bits */ 930 931 masklen = 0; 932 for (i = 0; i < 32; i++) { 933 if (mask & 0x80000000) { 934 masklen++; 935 mask = mask << 1; 936 } else { 937 break; 938 } 939 } 940 sal_sprintf(buf, "%d.%d.%d.%d/%d", 941 (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, 942 (ipaddr >> 8) & 0xff, ipaddr & 0xff, masklen); 943 } 944 945 void 946 format_ip6addr(char buf[IP6ADDR_STR_LEN], ip6_addr_t ipaddr) 947 { 948 sal_sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", 949 (((uint16)ipaddr[0] << 8) | ipaddr[1]), 950 (((uint16)ipaddr[2] << 8) | ipaddr[3]), 951 (((uint16)ipaddr[4] << 8) | ipaddr[5]), 952 (((uint16)ipaddr[6] << 8) | ipaddr[7]), 953 (((uint16)ipaddr[8] << 8) | ipaddr[9]), 954 (((uint16)ipaddr[10] << 8) | ipaddr[11]), 955 (((uint16)ipaddr[12] << 8) | ipaddr[13]), 956 (((uint16)ipaddr[14] << 8) | ipaddr[15])); 957 } 958 959 /* 960 * Parse a string containing a list of ports into a bitmap string. 961 * The input format is: 962 * 963 * PBMP : '0x' {HEXDIGIT}+ { return BITS_SET($2); } 964 * | LIST { return $1; } 965 * ; 966 * LIST : [LIST ','] RANGE STEP { return UNION($1, $2, $3); } 967 * | [LIST ','] '~' RANGE STEP { return REMOVE($1, $2, $3); } 968 * ; 969 * RANGE : PORT '-' PORT { return $1 .. $2; } 970 * | PORT { return $1 .. $1; } 971 * | 'FE' { return FE ports; } 972 * | 'GE' { return GE ports; } 973 * | 'XE' { return XE ports; } 974 * | 'HG' { return HG ports; } 975 * | 'E' { return ether ports; } 976 * | '*' { return ether, HG ports; } 977 * | 'ALL' { return ether, HG, CPU ports; } 978 * ; 979 * STEP : ':' INTEGER { return $2 }; 980 * ; 981 * PORT : INTEGER{NUM_PORT} { return $1 } 982 * | 'E' INTEGER{NUM_E_PORT} { return E port $2 } 983 * | 'FE' INTEGER{NUM_FE_PORT} { return FE port $2 } 984 * | 'GE' INTEGER{NUM_GE_PORT} { return GE port $2 } 985 * | 'XE' INTEGER{NUM_GE_PORT} { return XE port $2 } 986 * | 'HG' INTEGER{NUM_HG_PORT} { return HG port $2 } 987 * | 'CPU' { return CMIC_PORT } 988 * | 'NONE' { return NIL } 989 * 990 * Returns 0 on success, -1 on syntax error. 991 */ 992 993 int 994 parse_pbmp(int unit, char *s, soc_pbmp_t *pbmp) 995 { 996 soc_pbmp_t bmall; 997 int complement, plast, pfirst, pstep, port, p, tp, i; 998 int matched, blk, blktype, is_ci = 0, is_phy = 0; 999 char *sn, *se; 1000 soc_block_name_t *blk_names; 1001 soc_pbmp_t pbmp_temp; 1002 1003 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 1004 return _shr_pbmp_decode(s, pbmp); 1005 } 1006 1007 SOC_PBMP_CLEAR(bmall); 1008 SOC_PBMP_CLEAR(pbmp_temp); 1009 SOC_PBMP_CLEAR(*pbmp); 1010 1011 blk_names = soc_block_names; 1012 pfirst = -1; 1013 pstep = 1; 1014 complement = 0; 1015 1016 while (*s) { 1017 if (s[0] == '~' || s[0] == '!') { 1018 complement = 1; 1019 s += 1; 1020 } 1021 1022 /* To cover for Apache XLPORTB0 and CLG2PORT blocks */ 1023 if ((sal_strncasecmp("XLB0PORT", s, (sizeof("XLB0PORT") - 1)) == 0) || 1024 (sal_strncasecmp("CLG2PORT", s, (sizeof("CLG2PORT") - 1)) == 0)) { 1025 sn = s + 8; 1026 } else { 1027 1028 1029 for (sn = s; *sn && *sn != '-' && *sn != ',' && *sn != ':' && 1030 !isdigit((unsigned)*sn); sn++) { 1031 ; 1032 } 1033 } 1034 1035 1036 se = sn; 1037 if (isdigit((unsigned)*sn)) { 1038 port = 0; 1039 do { 1040 port = port * 10 + (*se++ - '0'); 1041 } while (isdigit((unsigned) *se)); 1042 } else { 1043 port = -1; 1044 } 1045 plast = -1; 1046 BCM_PBMP_ASSIGN(pbmp_temp, PBMP_PORT_ALL(unit)); 1047 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_TRIDENT_SUPPORT) 1048 if (SOC_IS_ENDURO(unit) || SOC_IS_TD_TT(unit)) { 1049 /* Since the LB port in Enduro is port 1, not the last port. 1050 We need to add this to support <reg_name>.number 1051 register access method with correct port mapping in AV tests. */ 1052 BCM_PBMP_OR(pbmp_temp, PBMP_LB(unit)); 1053 } 1054 #endif /* BCM_ENDURO_SUPPORT || BCM_TRIDENT_SUPPORT */ 1055 1056 if (soc_feature(unit, soc_feature_ep_redirect_v2)) { 1057 BCM_PBMP_OR(pbmp_temp, PBMP_RDB_ALL(unit)); 1058 } 1059 if (SOC_IS_MONTEREY(unit)) { 1060 BCM_PBMP_OR(pbmp_temp, PBMP_MACSEC_ALL(unit)); 1061 } 1062 #if defined(BCM_TRIUMPH3_SUPPORT) 1063 if (SOC_IS_TRIUMPH3(unit)) { 1064 /* Add AXP ports. 1065 * We need to add this to support <reg_name>.number 1066 * register access method with correct port mapping in AV tests. 1067 */ 1068 BCM_PBMP_OR(pbmp_temp, PBMP_AXP_ALL(unit)); 1069 } 1070 #endif /* BCM_TRIUMPH3_SUPPORT */ 1071 if (sn == s) { /* unprefixed number */ 1072 if (soc_property_get(unit, spn_DPORT_MAP_DIRECT, FALSE)) { 1073 /* Treat port as internal port number */ 1074 plast = DPORT_FROM_PORT(unit, port); 1075 } else { 1076 plast = -1; 1077 1078 /* Iterate through the dport map and find the corresponding 1079 * logical port. If the logical port is valid and is the last 1080 * one passed in as the arg, mark it as the last port 1081 */ 1082 for (p = 0; p < SOC_DPORT_MAX; p++) { 1083 tp = soc_dport_to_port(unit, p); 1084 1085 /* If the logical port is valid and mapped, and if it's 1086 * the last port from the string passed above, mark it 1087 * as the last port and break out of the loop 1088 */ 1089 if (tp >= 0 && SOC_PBMP_MEMBER(pbmp_temp, tp)) { 1090 if (p == port) { 1091 plast = p; 1092 break; 1093 } 1094 } 1095 } 1096 } 1097 if (plast < 0) { 1098 return -1; /* error: port out of range */ 1099 } 1100 } else { /* prefix number */ 1101 tp = *sn; 1102 *sn = '\0'; 1103 if (sal_strcasecmp(s, "fe") == 0) { 1104 bmall = PBMP_FE_ALL(unit); 1105 } else if (sal_strcasecmp(s, "ge") == 0) { 1106 bmall = PBMP_GE_ALL(unit); 1107 } else if (sal_strcasecmp(s, "xe") == 0) { 1108 bmall = PBMP_XE_ALL(unit); 1109 } else if (sal_strcasecmp(s, "ce") == 0) { 1110 bmall = PBMP_CE_ALL(unit); 1111 } else if (sal_strcasecmp(s, "cd") == 0) { 1112 bmall = PBMP_CDE_ALL(unit); 1113 } else if (sal_strcasecmp(s, "hg") == 0) { 1114 bmall = PBMP_HG_ALL(unit); 1115 } else if (sal_strcasecmp(s, "hl") == 0) { 1116 bmall = PBMP_HL_ALL(unit); 1117 } else if (sal_strcasecmp(s, "hg_s") == 0) { 1118 bmall = PBMP_HG_SUBPORT_ALL(unit); 1119 } else if (sal_strcasecmp(s, "st") == 0) { 1120 bmall = PBMP_ST_ALL(unit); 1121 } else if (sal_strcasecmp(s, "il") == 0) { 1122 bmall = PBMP_IL_ALL(unit); 1123 } else if (SOC_IS_SAND(unit) && (sal_strcasecmp(s, "xl") == 0)) { 1124 bmall = PBMP_XL_ALL(unit); 1125 } else if (sal_strcasecmp(s, "axp") == 0) { 1126 bmall = PBMP_AXP_ALL(unit); 1127 } else if (sal_strcasecmp(s, "sch") == 0) { 1128 bmall = PBMP_SCH_ALL(unit); 1129 } else if (sal_strcasecmp(s, "sci") == 0) { 1130 bmall = PBMP_SCI_ALL(unit); 1131 } else if (sal_strcasecmp(s, "qsgmii") == 0) { 1132 bmall = PBMP_QSGMII_ALL(unit); 1133 } else if ((sal_strcasecmp(s, "sfi") == 0 || 1134 sal_strcasecmp(s, "if") == 0)) { 1135 bmall = PBMP_SFI_ALL(unit); 1136 } else if (sal_strcasecmp(s, "fabric") == 0) { 1137 bmall = PBMP_SFI_ALL(unit); 1138 port += SOC_INFO(unit).fabric_logical_port_base; /* fabric links starting from 1139 configurable logical_port_base */ 1140 } else if (sal_strcasecmp(s, "sci_sfi") == 0) { 1141 bmall = PBMP_SCI_ALL(unit); 1142 BCM_PBMP_AND(bmall, PBMP_SFI_ALL(unit)); 1143 } else if (sal_strcasecmp(s, "spi") == 0) { 1144 bmall = PBMP_SPI_ALL(unit); 1145 } else if (sal_strcasecmp(s, "spi_s") == 0) { 1146 bmall = PBMP_SPI_SUBPORT_ALL(unit); 1147 } else if (sal_strcasecmp(s, "e") == 0) { 1148 bmall = PBMP_E_ALL(unit); 1149 #ifdef BCM_DNX_SUPPORT 1150 } else if ((sal_strcasecmp(s, "eth") == 0) && SOC_IS_DNX(unit)) { 1151 bmall = PBMP_E_ALL(unit); 1152 #endif 1153 } else if (sal_strcasecmp(s, "cpu") == 0) { 1154 bmall = PBMP_CMIC(unit); 1155 } else if (sal_strcasecmp(s, "lb") == 0) { 1156 bmall = PBMP_LB(unit); 1157 } else if (sal_strcasecmp(s, "rdb") == 0) { 1158 bmall = PBMP_RDB_ALL(unit); 1159 } else if (sal_strcasecmp(s, "fae") == 0) { 1160 bmall = PBMP_FAE_ALL(unit); 1161 } else if (sal_strcasecmp(s, "msec") == 0) { 1162 bmall = PBMP_MACSEC_ALL(unit); 1163 } else if (sal_strcasecmp(s, "roe") == 0) { 1164 bmall = PBMP_CPRI_ALL(unit); 1165 } else if (sal_strcasecmp(s, "mmu") == 0) { 1166 bmall = PBMP_MMU(unit); 1167 } else if (sal_strcasecmp(s, "mgmt") == 0) { 1168 bmall = PBMP_MANAGEMENT(unit); 1169 } else if (sal_strcasecmp(s, "all") == 0) { 1170 bmall = PBMP_ALL(unit); 1171 SOC_PBMP_REMOVE(bmall, PBMP_MACSEC_ALL(unit)); 1172 SOC_PBMP_REMOVE(bmall, PBMP_LB(unit)); 1173 SOC_PBMP_REMOVE(bmall, PBMP_RDB_ALL(unit)); 1174 SOC_PBMP_REMOVE(bmall, PBMP_FAE_ALL(unit)); 1175 BCM_PBMP_OR(bmall, PBMP_SPI_ALL(unit)); 1176 } else if (sal_strcasecmp(s, "*") == 0) { 1177 bmall = PBMP_PORT_ALL(unit); 1178 BCM_PBMP_OR(bmall, PBMP_SPI_ALL(unit)); 1179 } else if (sal_strcasecmp(s, "none") == 0) { 1180 SOC_PBMP_CLEAR(bmall); 1181 } else if (sal_strcasecmp(s, "phy") == 0) { 1182 SOC_PBMP_ASSIGN(bmall,SOC_INFO(unit).physical_pbm); 1183 is_phy = 1; 1184 } else if (sal_strcasecmp(s, "ci") == 0) { 1185 SOC_PBMP_CLEAR(bmall); 1186 for (i = 0; blk_names[i].blk != SOC_BLK_NONE; i++) { 1187 if (sal_strcasecmp(blk_names[i].name, "ci") == 0) { 1188 blktype = blk_names[i].blk; 1189 SOC_BLOCK_ITER(unit, blk, blktype) { 1190 SOC_PBMP_OR(bmall, SOC_BLOCK_BITMAP(unit, blk)); 1191 plast = port; 1192 is_ci = 1; 1193 } 1194 } 1195 } 1196 } else { 1197 /* parse block names */ 1198 matched = 0; 1199 SOC_PBMP_CLEAR(bmall); 1200 for (i = 0; blk_names[i].blk != SOC_BLK_NONE; i++) { 1201 if (sal_strcasecmp(blk_names[i].name, s) == 0) { 1202 blktype = blk_names[i].blk; 1203 matched += 1; 1204 SOC_BLOCK_ITER(unit, blk, blktype) { 1205 if (port >= 0 && 1206 SOC_BLOCK_INFO(unit, blk).number != port) { 1207 continue; 1208 } 1209 SOC_PBMP_OR(bmall, SOC_BLOCK_BITMAP(unit, blk)); 1210 } 1211 } 1212 } 1213 if (matched == 0) { /* was not a block name */ 1214 *sn = tp; /* restore parsed string */ 1215 return -1; /* error: unexpected char */ 1216 } 1217 port = -1; /* don't use the number */ 1218 } 1219 *sn = tp; 1220 if (port >= 0) { 1221 i = -1; 1222 if(is_phy || is_ci) { 1223 SOC_PBMP_ITER(bmall,p){ 1224 if (p == port) { 1225 plast = p; 1226 break; 1227 } 1228 } 1229 } else { 1230 DPORT_SOC_PBMP_ITER(unit, bmall, p, tp) { 1231 if (SOC_IS_SAND(unit)) { 1232 if (p == port) { 1233 plast = p; 1234 break; 1235 } 1236 } else { 1237 i += 1; 1238 if (DPORT_FROM_DPORT_INDEX(unit, p, i) == port) { 1239 plast = p; 1240 break; 1241 } 1242 } 1243 } 1244 } 1245 if (plast < 0) { 1246 return -1; /* error: index out of range */ 1247 } 1248 } 1249 } 1250 s = se; 1251 1252 switch (*s) { 1253 case '-': 1254 pstep = 1; 1255 if (plast < 0) { 1256 return -1; /* error: range without port */ 1257 } else if (pfirst < 0) { 1258 pfirst = plast; 1259 } else { 1260 return -1; /* error: x-y-z */ 1261 } 1262 break; 1263 case ':': 1264 s++; 1265 if (!isdigit((unsigned)*s)) { 1266 return -1; 1267 } 1268 for (pstep = 0; isdigit((unsigned)*s); s++) { 1269 pstep = pstep * 10 + (*s - '0'); 1270 } 1271 if (pstep == 0 || (*s != ',' && *s != '\0')) { 1272 return -1; 1273 } 1274 /* fall through */ 1275 case ',': 1276 case '\0': 1277 if (plast < 0) { /* complete bitmap op */ 1278 pfirst = 999; 1279 plast = -1; 1280 DPORT_SOC_PBMP_ITER(unit, bmall, p, tp) { 1281 if (p < pfirst) { 1282 pfirst = p; 1283 } 1284 if (p > plast) { 1285 plast = p; 1286 } 1287 } 1288 } 1289 if (pfirst < 0) { /* just one port */ 1290 pfirst = plast; 1291 } 1292 for (port = pfirst; port <= plast; port += pstep) { /* a range */ 1293 p = is_ci ? port : DPORT_TO_PORT(unit, port); 1294 p = is_phy ? port : p; 1295 /* coverity[overrun-local] */ 1296 if ((p >= 0) && SOC_PBMP_NOT_NULL(bmall) && !SOC_PBMP_MEMBER(bmall, p)) { 1297 continue; /* skip gaps in range */ 1298 } 1299 if ((is_ci) || (SOC_PORT_VALID(unit, p)) || is_phy) { 1300 if (complement) { 1301 SOC_PBMP_PORT_REMOVE(*pbmp, p + is_phy*(SOC_INFO(unit).physical_port_offset-1)); 1302 } else { 1303 SOC_PBMP_PORT_ADD(*pbmp, p + is_phy*(SOC_INFO(unit).physical_port_offset-1)); 1304 } 1305 } 1306 } 1307 if (*s == '\0') { 1308 return 0; 1309 } 1310 pfirst = -1; 1311 pstep = 1; 1312 complement = 0; 1313 SOC_PBMP_CLEAR(bmall); 1314 is_ci = 0; 1315 break; 1316 default: 1317 return -1; /* error: unexpected char */ 1318 } 1319 s += 1; 1320 } 1321 return -1; /* error: unexpected end */ 1322 } 1323 1324 int 1325 parse_pp_pbmp(int unit, char *s, soc_pbmp_t *pbmp) 1326 { 1327 soc_pbmp_t bmall; 1328 int complement, plast, pfirst, pstep, port, p, i; 1329 char *sn, *se; 1330 soc_pbmp_t pbmp_temp; 1331 1332 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 1333 return _shr_pbmp_decode(s, pbmp); 1334 } 1335 1336 SOC_PBMP_CLEAR(bmall); 1337 SOC_PBMP_CLEAR(pbmp_temp); 1338 SOC_PBMP_CLEAR(*pbmp); 1339 1340 pfirst = -1; 1341 pstep = 1; 1342 complement = 0; 1343 1344 while (*s) { 1345 if (s[0] == '~' || s[0] == '!') { 1346 complement = 1; 1347 s += 1; 1348 } 1349 1350 for (sn = s; *sn && *sn != '-' && *sn != ',' && *sn != ':' && 1351 !isdigit((unsigned)*sn); sn++) { 1352 ; 1353 } 1354 se = sn; 1355 if (isdigit((unsigned)*sn)) { 1356 port = 0; 1357 do { 1358 port = port * 10 + (*se++ - '0'); 1359 } while (isdigit((unsigned) *se)); 1360 } else { 1361 port = -1; 1362 } 1363 1364 plast = -1; 1365 BCM_PBMP_ASSIGN(pbmp_temp, PBMP_PP_ALL(unit)); 1366 if (sn == s) { /* unprefixed number */ 1367 i = 0; 1368 plast = -1; 1369 PBMP_ITER(pbmp_temp, p) { 1370 if (i == port) { 1371 plast = p; 1372 break; 1373 } 1374 i += 1; 1375 } 1376 if (plast < 0) { 1377 return -1; /* error: port out of range */ 1378 } 1379 } else { /* prefix number */ 1380 p = *sn; 1381 *sn = '\0'; 1382 if (sal_strcasecmp(s, "pp") == 0) { 1383 bmall = PBMP_PP_ALL(unit); 1384 } else { 1385 /* Not Handled now */ 1386 } 1387 SOC_PBMP_ITER(bmall,p){ 1388 if (p == port) { 1389 plast = p; 1390 break; 1391 } 1392 } 1393 if (plast < 0) { 1394 return -1; /* error: index out of range */ 1395 } 1396 } 1397 s = se; 1398 1399 switch (*s) { 1400 case '-': 1401 pstep = 1; 1402 if (pfirst < 0) { 1403 pfirst = plast; 1404 } else { 1405 return -1; /* error: x-y-z */ 1406 } 1407 break; 1408 case ':': 1409 s++; 1410 if (!isdigit((unsigned)*s)) { 1411 return -1; 1412 } 1413 for (pstep = 0; isdigit((unsigned)*s); s++) { 1414 pstep = pstep * 10 + (*s - '0'); 1415 } 1416 if (pstep == 0 || (*s != ',' && *s != '\0')) { 1417 return -1; 1418 } 1419 /* fall through */ 1420 case ',': 1421 case '\0': 1422 if (pfirst < 0) { /* just one port */ 1423 pfirst = plast; 1424 } 1425 for (port = pfirst; port <= plast; port += pstep) { /* a range */ 1426 if (SOC_PBMP_NOT_NULL(bmall) && !SOC_PBMP_MEMBER(bmall, port)) { 1427 continue; /* skip gaps in range */ 1428 } 1429 if (1) { 1430 if (complement) { 1431 SOC_PBMP_PORT_REMOVE(*pbmp, port); 1432 } else { 1433 SOC_PBMP_PORT_ADD(*pbmp, port); 1434 } 1435 } 1436 } 1437 if (*s == '\0') { 1438 return 0; 1439 } 1440 pfirst = -1; 1441 pstep = 1; 1442 complement = 0; 1443 SOC_PBMP_CLEAR(bmall); 1444 break; 1445 default: 1446 return -1; /* error: unexpected char */ 1447 } 1448 s += 1; 1449 } 1450 return -1; /* error: unexpected end */ 1451 } 1452 1453 1454 int 1455 parse_bcm_pbmp(int unit, char *s, bcm_pbmp_t *pbmp) 1456 { 1457 int rv = parse_pbmp(unit, s, pbmp); 1458 1459 BCM_API_XLATE_PORT_PBMP_P2A(unit, pbmp); 1460 1461 return rv; 1462 } 1463 1464 int 1465 parse_pbmp_no_error(int unit, char *s, pbmp_t *pbmp) 1466 { 1467 pbmp_t bmall; 1468 int complement, plast, pfirst, pstep, port, p, tp, i; 1469 int matched, blk, blktype; 1470 char *sn, *se; 1471 uint16 dev_id; 1472 uint8 rev_id; 1473 soc_block_name_t *blk_names; 1474 pbmp_t pbmp_temp; 1475 1476 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 1477 return _shr_pbmp_decode(s, pbmp); 1478 } 1479 1480 SOC_PBMP_CLEAR(bmall); 1481 SOC_PBMP_CLEAR(pbmp_temp); 1482 SOC_PBMP_CLEAR(*pbmp); 1483 1484 blk_names = soc_block_names; 1485 soc_cm_get_id(unit, &dev_id, &rev_id); 1486 1487 pfirst = -1; 1488 pstep = 1; 1489 complement = 0; 1490 1491 while (*s) { 1492 if (s[0] == '~' || s[0] == '!') { 1493 complement = 1; 1494 s += 1; 1495 } 1496 1497 for (sn = s; *sn && *sn != '-' && *sn != ',' && *sn != ':' && 1498 !isdigit((unsigned)*sn); sn++) { 1499 ; 1500 } 1501 se = sn; 1502 if (isdigit((unsigned)*sn)) { 1503 port = 0; 1504 do { 1505 port = port * 10 + (*se++ - '0'); 1506 } while (isdigit((unsigned) *se)); 1507 } else { 1508 port = -1; 1509 } 1510 1511 plast = -1; 1512 BCM_PBMP_ASSIGN(pbmp_temp, PBMP_PORT_ALL(unit)); 1513 #if defined(BCM_ENDURO_SUPPORT) 1514 if(SOC_IS_ENDURO(unit)) { 1515 /* Since the LB port in Enduro is port 1, not the last port. 1516 We need to add this to support <reg_name>.number 1517 register access method with correct port mapping in AV tests. */ 1518 BCM_PBMP_OR(pbmp_temp, PBMP_LB(unit)); 1519 } 1520 #endif /* BCM_ENDURO_SUPPORT */ 1521 if (sn == s) { /* unprefixed number */ 1522 if (soc_property_get(unit, spn_DPORT_MAP_DIRECT, FALSE)) { 1523 /* Treat port as internal port number */ 1524 plast = DPORT_FROM_PORT(unit, port); 1525 } else { 1526 /* Port number is port index + 1 */ 1527 i = 0; 1528 plast = -1; 1529 /* coverity[overrun-local] */ 1530 DPORT_SOC_PBMP_ITER(unit, pbmp_temp, p, tp) { 1531 i += 1; 1532 if (i == port) { 1533 plast = p; 1534 break; 1535 } 1536 } 1537 } 1538 if (plast < 0) { 1539 return -1; /* error: port out of range */ 1540 } 1541 } else { /* prefix number */ 1542 tp = *sn; 1543 *sn = '\0'; 1544 if (sal_strcasecmp(s, "fe") == 0) { 1545 switch (dev_id) { 1546 case 0xb018: 1547 SOC_PBMP_WORD_SET(bmall, 0, 0xffffffc0); 1548 SOC_PBMP_WORD_SET(bmall, 1, 0x3fffff); 1549 break; 1550 case 0xb014: 1551 case 0xb024: 1552 case 0xb025: 1553 SOC_PBMP_WORD_SET(bmall, 0, 0x3fffffc0); 1554 break; 1555 default: 1556 break; 1557 } 1558 } else if (sal_strcasecmp(s, "ge") == 0) { 1559 switch (dev_id) { 1560 case 0xb218: 1561 SOC_PBMP_WORD_SET(bmall, 0, 0xfffffffe); 1562 SOC_PBMP_WORD_SET(bmall, 1, 0x3fffff); 1563 break; 1564 case 0xb214: 1565 case 0xb215: 1566 case 0xb224: 1567 case 0xb225: 1568 SOC_PBMP_WORD_SET(bmall, 0, 0x3ffffffe); 1569 break; 1570 case 0xb226: 1571 case 0xb227: 1572 SOC_PBMP_WORD_SET(bmall, 0, 0x3ffffe); 1573 break; 1574 case 0xb212: 1575 case 0xb213: 1576 case 0xb228: 1577 case 0xb229: 1578 SOC_PBMP_WORD_SET(bmall, 0, 0x3ffe); 1579 break; 1580 case 0xc71a: 1581 SOC_PBMP_WORD_SET(bmall, 0, 0xfffffff8); 1582 SOC_PBMP_WORD_SET(bmall, 1, 0x3fffff); 1583 break; 1584 case 0xc71b: 1585 case 0xc724: 1586 SOC_PBMP_WORD_SET(bmall, 0, 0x3ffffff8); 1587 break; 1588 case 0xc716: 1589 SOC_PBMP_WORD_SET(bmall, 0, 0x3fffc8); 1590 break; 1591 case 0xc726: 1592 SOC_PBMP_WORD_SET(bmall, 0, 0x3ffff8); 1593 break; 1594 case 0xb018: 1595 case 0xb014: 1596 case 0xb024: 1597 case 0xb025: 1598 SOC_PBMP_WORD_SET(bmall, 0, 0x3e); 1599 break; 1600 default: 1601 break; 1602 } 1603 } else if (sal_strcasecmp(s, "st") == 0) { 1604 switch (dev_id) { 1605 case 0xb218: 1606 case 0xb214: 1607 case 0xb215: 1608 case 0xb212: 1609 case 0xb213: 1610 case 0xb018: 1611 case 0xb014: 1612 SOC_PBMP_WORD_SET(bmall, 0, 0x6); 1613 break; 1614 case 0xb024: 1615 case 0xb025: 1616 case 0xb224: 1617 case 0xb225: 1618 case 0xb226: 1619 case 0xb227: 1620 case 0xb228: 1621 case 0xb229: 1622 SOC_PBMP_WORD_SET(bmall, 0, 0x36); 1623 default: 1624 break; 1625 } 1626 } else if (sal_strcasecmp(s, "e") == 0) { 1627 bmall = PBMP_E_ALL(unit); 1628 } else if (sal_strcasecmp(s, "cpu") == 0) { 1629 bmall = PBMP_CMIC(unit); 1630 } else if (sal_strcasecmp(s, "all") == 0) { 1631 bmall = PBMP_ALL(unit); 1632 BCM_PBMP_OR(bmall, PBMP_SPI_ALL(unit)); 1633 } else if (sal_strcasecmp(s, "*") == 0) { 1634 bmall = PBMP_PORT_ALL(unit); 1635 BCM_PBMP_OR(bmall, PBMP_SPI_ALL(unit)); 1636 } else if (sal_strcasecmp(s, "none") == 0) { 1637 SOC_PBMP_CLEAR(bmall); 1638 } else { 1639 /* parse block names */ 1640 matched = 0; 1641 SOC_PBMP_CLEAR(bmall); 1642 for (i = 0; blk_names[i].blk != SOC_BLK_NONE; i++) { 1643 if (sal_strcasecmp(blk_names[i].name, s) == 0) { 1644 blktype = blk_names[i].blk; 1645 matched += 1; 1646 SOC_BLOCK_ITER(unit, blk, blktype) { 1647 if (port >= 0 && 1648 SOC_BLOCK_INFO(unit, blk).number != port) { 1649 continue; 1650 } 1651 SOC_PBMP_OR(bmall, SOC_BLOCK_BITMAP(unit, blk)); 1652 } 1653 } 1654 } 1655 if (matched == 0) { /* was not a block name */ 1656 *sn = tp; /* restore parsed string */ 1657 return -1; /* error: unexpected char */ 1658 } 1659 port = -1; /* don't use the number */ 1660 } 1661 *sn = tp; 1662 if (port >= 0) { 1663 p = -1; 1664 SOC_PBMP_ITER(bmall, tp) { /* map port from bitmap */ 1665 p += 1; 1666 if (p == port) { 1667 plast = tp; 1668 } 1669 } 1670 if (plast < 0) { 1671 /* return -1; error: index out of range */ 1672 } 1673 1674 } 1675 } 1676 s = se; 1677 1678 switch (*s) { 1679 case '-': 1680 pstep = 1; 1681 if (plast < 0) { 1682 /* return -1; error: range without port */ 1683 } else if (pfirst < 0) { 1684 pfirst = plast; 1685 } else { 1686 return -1; /* error: x-y-z */ 1687 } 1688 break; 1689 case ':': 1690 s++; 1691 if (!isdigit((unsigned)*s)) { 1692 return -1; 1693 } 1694 for (pstep = 0; isdigit((unsigned)*s); s++) { 1695 pstep = pstep * 10 + (*s - '0'); 1696 } 1697 if (pstep == 0 || (*s != ',' && *s != '\0')) { 1698 return -1; 1699 } 1700 /* fall through */ 1701 case ',': 1702 case '\0': 1703 if (plast < 0) { /* complete bitmap op */ 1704 pfirst = 999; 1705 plast = -1; 1706 PBMP_ITER(bmall, p) { 1707 if (p < pfirst) { 1708 pfirst = p; 1709 } 1710 if (p > plast) { 1711 plast = p; 1712 } 1713 } 1714 } 1715 if (pfirst < 0) { /* just one port */ 1716 pfirst = plast; 1717 } 1718 for (p = pfirst; p <= plast; p += pstep) { /* a range */ 1719 /* coverity[overrun-local : FALSE] */ 1720 if (SOC_PBMP_NOT_NULL(bmall) && !SOC_PBMP_MEMBER(bmall, p)) { 1721 continue; /* skip gaps in range */ 1722 } 1723 if (SOC_PORT_VALID(unit, p)) { 1724 if (complement) { 1725 SOC_PBMP_PORT_REMOVE(*pbmp, p); 1726 } else { 1727 SOC_PBMP_PORT_ADD(*pbmp, p); 1728 } 1729 } 1730 } 1731 if (*s == '\0') { 1732 return 0; 1733 } 1734 pfirst = -1; 1735 pstep = 1; 1736 complement = 0; 1737 SOC_PBMP_CLEAR(bmall); 1738 break; 1739 default: 1740 return -1; /* error: unexpected char */ 1741 } 1742 s += 1; 1743 } 1744 return -1; /* error: unexpected end */ 1745 } 1746 1747 1748 STATIC int 1749 _parse_port(int unit, char *s, soc_port_t *portp) 1750 { 1751 int port, max_port; 1752 int i, p, tp; 1753 soc_pbmp_t pbmp_temp; 1754 1755 /* Check if only port number was passed. */ 1756 if (isint(s)) { 1757 port = parse_integer(s); 1758 *portp = port; 1759 if (soc_property_get(unit, spn_DPORT_MAP_DIRECT, FALSE) == FALSE) { 1760 /* Port number is port index + 1 */ 1761 i = 1; 1762 *portp = -1; 1763 SOC_PBMP_ASSIGN(pbmp_temp, PBMP_PORT_ALL(unit)); 1764 /* coverity[overrun-local] */ 1765 DPORT_SOC_PBMP_ITER(unit, pbmp_temp, p, tp) { 1766 if (i == port) { 1767 *portp = tp; 1768 break; 1769 } 1770 i += 1; 1771 } 1772 } 1773 if (*portp < 0) { 1774 return -1; /* error: invalid port */ 1775 } 1776 return 0; 1777 } 1778 1779 { 1780 max_port = SOC_MAX_NUM_PORTS; 1781 } 1782 1783 for (port = 0; port < max_port; port++) { 1784 if (!SOC_PORT_VALID(unit, port)) { 1785 continue; 1786 } 1787 if (sal_strcasecmp(s, "any") == 0) { 1788 *portp = port; 1789 return 0; 1790 } 1791 if (sal_strcasecmp(s, SOC_PORT_NAME(unit, port)) == 0) { 1792 *portp = port; 1793 return 0; 1794 } 1795 } 1796 1797 return -1; /* error: no matching name */ 1798 } 1799 1800 char * 1801 format_gport(char *buf, bcm_gport_t gport) 1802 { 1803 int gport_type; 1804 1805 assert(buf != NULL); 1806 1807 #define GPORT_TYPE_SPRINTF(_name) \ 1808 sal_sprintf(buf, "0x%x(%s)", gport, _name) 1809 1810 if (BCM_GPORT_IS_SET(gport)) { 1811 gport_type = (gport >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK; 1812 switch(gport_type) { 1813 case _SHR_GPORT_TYPE_LOCAL: 1814 GPORT_TYPE_SPRINTF("local"); 1815 break; 1816 case _SHR_GPORT_TYPE_LOCAL_CPU: 1817 GPORT_TYPE_SPRINTF("local_cpu"); 1818 break; 1819 case _SHR_GPORT_TYPE_MODPORT: 1820 GPORT_TYPE_SPRINTF("modport"); 1821 break; 1822 case _SHR_GPORT_TYPE_TRUNK: 1823 GPORT_TYPE_SPRINTF("trunk"); 1824 break; 1825 case _SHR_GPORT_TYPE_DEVPORT: 1826 GPORT_TYPE_SPRINTF("devport"); 1827 break; 1828 case _SHR_GPORT_TYPE_BLACK_HOLE: 1829 GPORT_TYPE_SPRINTF("black_hole"); 1830 break; 1831 case _SHR_GPORT_TYPE_MPLS_PORT: 1832 GPORT_TYPE_SPRINTF("mpls"); 1833 break; 1834 case _SHR_GPORT_TYPE_MIM_PORT: 1835 GPORT_TYPE_SPRINTF("mim"); 1836 break; 1837 case _SHR_GPORT_TYPE_WLAN_PORT: 1838 GPORT_TYPE_SPRINTF("wlan"); 1839 break; 1840 case _SHR_GPORT_TYPE_TRILL_PORT: 1841 GPORT_TYPE_SPRINTF("trill"); 1842 break; 1843 case _SHR_GPORT_TYPE_SUBPORT_GROUP: 1844 GPORT_TYPE_SPRINTF("subport_group"); 1845 break; 1846 case _SHR_GPORT_TYPE_SUBPORT_PORT: 1847 GPORT_TYPE_SPRINTF("subport_port"); 1848 break; 1849 case _SHR_GPORT_TYPE_VLAN_PORT: 1850 GPORT_TYPE_SPRINTF("vlan"); 1851 break; 1852 case _SHR_GPORT_TYPE_VXLAN_PORT: 1853 GPORT_TYPE_SPRINTF("vxlan"); 1854 break; 1855 case _SHR_GPORT_TYPE_FLOW_PORT: 1856 GPORT_TYPE_SPRINTF("flow"); 1857 break; 1858 case _SHR_GPORT_TYPE_NIV_PORT: 1859 GPORT_TYPE_SPRINTF("niv"); 1860 break; 1861 case _SHR_GPORT_TYPE_L2GRE_PORT: 1862 GPORT_TYPE_SPRINTF("l2gre"); 1863 break; 1864 case _SHR_GPORT_TYPE_EXTENDER_PORT: 1865 GPORT_TYPE_SPRINTF("extender"); 1866 break; 1867 default: 1868 GPORT_TYPE_SPRINTF("unknown"); 1869 break; 1870 } 1871 } else { 1872 sal_sprintf(buf, "0x%x", gport); 1873 } 1874 1875 #undef GPORT_TYPE_SPRINTF 1876 1877 return buf; 1878 } 1879 1880 #if defined(BCM_ESW_SUPPORT) 1881 STATIC int stack_len = 0; 1882 1883 STATIC int parse_gport_push(void) 1884 { 1885 stack_len++; 1886 return 0; 1887 } 1888 1889 STATIC int parse_gport_pop(void) 1890 { 1891 if (stack_len) { 1892 stack_len--; 1893 return 0; 1894 } 1895 1896 return 1; 1897 } 1898 1899 /* 1900 * Function : _bcm_util_gport_construct 1901 * Description : Internal function to construct a gport from 1902 * given parameters 1903 * Parameters : (IN) unit - BCM device number 1904 * (IN) gport_dest - Structure that contains destination 1905 * to encode into a gport 1906 * (OUT) gport - Global port identifier 1907 * Returns : BCM_E_XXX 1908 * Notes : The modid and port are translated from the 1909 * local modid/port space to application space 1910 */ 1911 static int 1912 _bcm_util_gport_construct(int unit, _bcm_util_gport_dest_t *gport_dest, bcm_gport_t *gport) 1913 { 1914 1915 bcm_gport_t l_gport = 0; 1916 bcm_module_t mod_out; 1917 bcm_port_t port_out; 1918 1919 if ((NULL == gport_dest) || (NULL == gport) ){ 1920 return BCM_E_PARAM; 1921 } 1922 1923 switch (gport_dest->gport_type) { 1924 case _SHR_GPORT_TYPE_TRUNK: 1925 SOC_GPORT_TRUNK_SET(l_gport, gport_dest->tgid); 1926 break; 1927 case _SHR_GPORT_TYPE_LOCAL_CPU: 1928 l_gport = BCM_GPORT_LOCAL_CPU; 1929 break; 1930 case _SHR_GPORT_TYPE_LOCAL: 1931 SOC_GPORT_LOCAL_SET(l_gport, gport_dest->port); 1932 break; 1933 case _SHR_GPORT_TYPE_SUBPORT_GROUP: 1934 SOC_GPORT_SUBPORT_GROUP_SET(l_gport, gport_dest->subport_id); 1935 break; 1936 case _SHR_GPORT_TYPE_MPLS_PORT: 1937 BCM_GPORT_MPLS_PORT_ID_SET(l_gport, gport_dest->mpls_id); 1938 break; 1939 case _SHR_GPORT_TYPE_MIM_PORT: 1940 BCM_GPORT_MIM_PORT_ID_SET(l_gport, gport_dest->mim_id); 1941 break; 1942 case _SHR_GPORT_TYPE_SUBPORT_PORT: 1943 BCM_GPORT_SUBPORT_PORT_SET(l_gport, gport_dest->subport_id); 1944 break; 1945 case _SHR_GPORT_TYPE_WLAN_PORT: 1946 BCM_GPORT_WLAN_PORT_ID_SET(l_gport, gport_dest->wlan_id); 1947 break; 1948 case _SHR_GPORT_TYPE_DEVPORT: 1949 BCM_GPORT_DEVPORT_SET(l_gport, unit, gport_dest->port); 1950 break; 1951 case _SHR_GPORT_TYPE_MODPORT: 1952 BCM_IF_ERROR_RETURN ( 1953 _bcm_gport_modport_hw2api_map(unit, gport_dest->modid, 1954 gport_dest->port, &mod_out, 1955 &port_out)); 1956 SOC_GPORT_MODPORT_SET(l_gport, mod_out, port_out); 1957 break; 1958 case _SHR_GPORT_TYPE_EGRESS_MODPORT: 1959 BCM_IF_ERROR_RETURN ( 1960 _bcm_gport_modport_hw2api_map(unit, gport_dest->modid, 1961 gport_dest->port, &mod_out, 1962 &port_out)); 1963 BCM_GPORT_EGRESS_MODPORT_SET(l_gport, mod_out, port_out); 1964 break; 1965 case _SHR_GPORT_TYPE_CHILD: 1966 BCM_GPORT_CHILD_SET(l_gport, 1967 gport_dest->modid, 1968 gport_dest->port); 1969 break; 1970 case _SHR_GPORT_TYPE_EGRESS_CHILD: 1971 BCM_GPORT_EGRESS_CHILD_SET(l_gport, 1972 gport_dest->modid, 1973 gport_dest->port); 1974 break; 1975 case _SHR_GPORT_TYPE_VLAN_PORT: 1976 SOC_GPORT_VLAN_PORT_ID_SET(l_gport, gport_dest->vlan_port_id); 1977 break; 1978 case _SHR_GPORT_TYPE_VXLAN_PORT: 1979 SOC_GPORT_VXLAN_PORT_ID_SET(l_gport, gport_dest->vxlan_id); 1980 break; 1981 case _SHR_GPORT_TYPE_TRILL_PORT: 1982 SOC_GPORT_TRILL_PORT_ID_SET(l_gport, gport_dest->trill_id); 1983 break; 1984 case _SHR_GPORT_TYPE_NIV_PORT: 1985 SOC_GPORT_NIV_PORT_ID_SET(l_gport, gport_dest->niv_id); 1986 break; 1987 case _SHR_GPORT_TYPE_L2GRE_PORT: 1988 SOC_GPORT_L2GRE_PORT_ID_SET(l_gport, gport_dest->l2gre_id); 1989 break; 1990 case _SHR_GPORT_TYPE_EXTENDER_PORT: 1991 SOC_GPORT_EXTENDER_PORT_ID_SET(l_gport, gport_dest->extender_id); 1992 break; 1993 default: 1994 return BCM_E_PARAM; 1995 } 1996 1997 *gport = l_gport; 1998 return BCM_E_NONE; 1999 } 2000 2001 2002 /* 2003 * Function: 2004 * parse_gport 2005 * Description: 2006 * Parses string that identifies a GPORT and constructs an appropriate GPORT 2007 * Parameters: 2008 * unit - Device unit number 2009 * s - input string to parse 2010 * portp - output port number 2011 */ 2012 int parse_gport(int unit, char *s, soc_port_t *portp) 2013 { 2014 int port_val = -1, mod_val = -1; 2015 int i = 0, start_pos = 0, str_len, modid_len = 0; 2016 char *gport_type_str = NULL; 2017 char *gport_val_str = NULL; 2018 char *mod_str = NULL; 2019 char *port_str = NULL; 2020 char *parse_port_str; 2021 char *start = s; 2022 int rv = CMD_OK; 2023 _bcm_util_gport_dest_t gport_dest; 2024 2025 if (NULL == s) { 2026 return CMD_FAIL; 2027 } 2028 2029 str_len = sal_strlen(s) + 1; 2030 2031 if (!str_len) { 2032 return CMD_FAIL; 2033 } 2034 while (s[i] != '\0') { 2035 if ((s[i] == '(') || (s[i] == '{') || (s[i] == '[')){ 2036 parse_gport_push(); 2037 /* Allocate only once - defensive check against wrong input */ 2038 if (!gport_type_str) { 2039 gport_type_str = sal_alloc(str_len, "GPORT type string"); 2040 } 2041 sal_strncpy(gport_type_str, start, i - start_pos); 2042 gport_type_str[i] = '\0'; 2043 start = (s + i + 1); 2044 start_pos = i + 1; 2045 } else if ((s[i] == ')') || (s[i] == '}') || (s[i] == ']')){ 2046 if (parse_gport_pop()) { 2047 rv = CMD_FAIL; 2048 goto done; 2049 } 2050 /* Allocate only once - defensive check against wrong input */ 2051 if (!gport_val_str) { 2052 gport_val_str = sal_alloc(str_len, "GPORT val string"); 2053 } 2054 sal_strncpy(gport_val_str, start, i - start_pos); 2055 gport_val_str[i - start_pos] = '\0'; 2056 } else if ((s[i] == ',') || (s[i] ==':') || (s[i] == '.') ) { 2057 /* Allocate only once - defensive check against wrong input */ 2058 if (!mod_str) { 2059 mod_str = sal_alloc(str_len, "Modid str"); 2060 } 2061 sal_strncpy(mod_str, start , i - start_pos); 2062 mod_str[i - start_pos] = '\0'; 2063 modid_len = i - start_pos; 2064 2065 /* Allocate only once - defensive check against wrong input */ 2066 if (!port_str) { 2067 port_str = sal_alloc(str_len, "Port str"); 2068 } 2069 start_pos = i + 1; 2070 if (start_pos >= (str_len - 2)) { 2071 rv = CMD_FAIL; 2072 goto done; 2073 } 2074 sal_strncpy(port_str, start + modid_len + 1, str_len - 2 - start_pos); 2075 port_str[str_len - 2 - start_pos] = '\0'; 2076 } 2077 i++; 2078 } 2079 2080 /* Check for redundant parentheses */ 2081 if (!parse_gport_pop()) { 2082 rv = CMD_FAIL; 2083 goto done; 2084 } 2085 2086 /* if not gport - don't parse */ 2087 if (NULL == gport_type_str) { 2088 if (isint(s)) { 2089 port_val = parse_integer(s); 2090 if (BCM_GPORT_IS_SET(port_val)) { 2091 *portp = port_val; 2092 rv = CMD_OK; 2093 goto done; 2094 } else { 2095 rv = CMD_FAIL; 2096 goto done; 2097 } 2098 } else { 2099 rv = CMD_FAIL; 2100 goto done; 2101 } 2102 } 2103 2104 /* Initialized gport_dest structure */ 2105 sal_memset(&gport_dest, 0, sizeof(_bcm_util_gport_dest_t)); 2106 2107 /* Take care of GPORTS that do not need input */ 2108 if (!sal_strcasecmp(gport_type_str, "localcpu") || 2109 !sal_strcasecmp(gport_type_str, "lc")) { 2110 gport_dest.gport_type = _SHR_GPORT_TYPE_LOCAL; 2111 goto gport_done; 2112 } 2113 if (!sal_strcasecmp(gport_type_str, "invalid")) { 2114 *portp = BCM_GPORT_INVALID; 2115 goto done; 2116 } 2117 if (!sal_strcasecmp(gport_type_str, "blackhole") || 2118 !sal_strcasecmp(gport_type_str, "bh")) { 2119 *portp = _SHR_GPORT_BLACK_HOLE; 2120 goto done; 2121 } 2122 2123 /* Parse the input */ 2124 if (NULL == port_str) { 2125 mod_val = -1; 2126 parse_port_str = gport_val_str; 2127 } else { 2128 parse_port_str = port_str; 2129 } 2130 2131 if (mod_str && isint(mod_str)) { 2132 mod_val = parse_integer(mod_str); 2133 } 2134 2135 if (isint(parse_port_str)) { 2136 port_val = parse_integer(parse_port_str); 2137 } else { 2138 if (_parse_port(unit, parse_port_str, &port_val) < 0) { 2139 rv = CMD_FAIL; 2140 goto done; 2141 } 2142 } 2143 2144 /* Take care of GPORTS that need input */ 2145 if (!sal_strcasecmp(gport_type_str, "modport") || 2146 !sal_strcasecmp(gport_type_str, "mp") || 2147 !sal_strcasecmp(gport_type_str, "egress_modport") || 2148 !sal_strcasecmp(gport_type_str, "emp")) { 2149 if (mod_val < 0) { 2150 /* If modid was not specified - use mymodid */ 2151 if (bcm_stk_my_modid_get(unit, &mod_val) < 0) { 2152 rv = CMD_FAIL; 2153 goto done; 2154 } 2155 } 2156 if (port_val < 0) { 2157 rv = CMD_FAIL; 2158 goto done; 2159 } 2160 if (('e' == gport_type_str[0]) || 2161 ('E' == gport_type_str[0])) { 2162 gport_dest.gport_type = _SHR_GPORT_TYPE_EGRESS_MODPORT; 2163 } else { 2164 gport_dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 2165 } 2166 gport_dest.modid = mod_val; 2167 gport_dest.port = port_val; 2168 } 2169 if (!sal_strcasecmp(gport_type_str, "child") || 2170 !sal_strcasecmp(gport_type_str, "egress_child")) { 2171 if (mod_val < 0) { 2172 /* If modid was not specified, use mymodid */ 2173 if (bcm_stk_my_modid_get(unit, &mod_val) < 0) { 2174 rv = CMD_FAIL; 2175 goto done; 2176 } 2177 } 2178 if (port_val < 0) { 2179 rv = CMD_FAIL; 2180 goto done; 2181 } 2182 if (('e' == gport_type_str[0]) || 2183 ('E' == gport_type_str[0])) { 2184 gport_dest.gport_type = _SHR_GPORT_TYPE_EGRESS_CHILD; 2185 } else { 2186 gport_dest.gport_type = _SHR_GPORT_TYPE_CHILD; 2187 } 2188 gport_dest.gport_type = _SHR_GPORT_TYPE_CHILD; 2189 gport_dest.modid = mod_val; 2190 gport_dest.port = port_val; 2191 } 2192 if (!sal_strcasecmp(gport_type_str, "trunk")) { 2193 gport_dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 2194 gport_dest.tgid = port_val; 2195 } 2196 if (!sal_strcasecmp(gport_type_str, "local")) { 2197 gport_dest.gport_type = _SHR_GPORT_TYPE_LOCAL; 2198 gport_dest.port = port_val; 2199 } 2200 if (!sal_strcasecmp(gport_type_str, "devport") || 2201 !sal_strcasecmp(gport_type_str, "dp")) { 2202 gport_dest.gport_type = _SHR_GPORT_TYPE_DEVPORT; 2203 gport_dest.port = port_val; 2204 } 2205 if (!sal_strcasecmp(gport_type_str, "mpls")) { 2206 gport_dest.gport_type = _SHR_GPORT_TYPE_MPLS_PORT; 2207 gport_dest.mpls_id = port_val; 2208 } 2209 if (!sal_strcasecmp(gport_type_str, "mim")) { 2210 gport_dest.gport_type = _SHR_GPORT_TYPE_MIM_PORT; 2211 gport_dest.mim_id = port_val; 2212 } 2213 if (!sal_strcasecmp(gport_type_str, "wlan")) { 2214 gport_dest.gport_type = _SHR_GPORT_TYPE_WLAN_PORT; 2215 gport_dest.wlan_id = port_val; 2216 } 2217 if (!sal_strcasecmp(gport_type_str, "sub")) { 2218 gport_dest.gport_type = _SHR_GPORT_TYPE_SUBPORT_PORT; 2219 gport_dest.subport_id = port_val; 2220 } 2221 if (!sal_strcasecmp(gport_type_str, "subg")) { 2222 gport_dest.gport_type = _SHR_GPORT_TYPE_SUBPORT_GROUP; 2223 gport_dest.subport_group_id = port_val; 2224 } 2225 if (!sal_strcasecmp(gport_type_str, "vlan")) { 2226 gport_dest.gport_type = _SHR_GPORT_TYPE_VLAN_PORT; 2227 gport_dest.vlan_port_id = port_val; 2228 } 2229 if (!sal_strcasecmp(gport_type_str, "vxlan")) { 2230 gport_dest.gport_type = _SHR_GPORT_TYPE_VXLAN_PORT; 2231 gport_dest.vxlan_id = port_val; 2232 } 2233 if (!sal_strcasecmp(gport_type_str, "trill")) { 2234 gport_dest.gport_type = _SHR_GPORT_TYPE_TRILL_PORT; 2235 gport_dest.trill_id = port_val; 2236 } 2237 if (!sal_strcasecmp(gport_type_str, "niv")) { 2238 gport_dest.gport_type = _SHR_GPORT_TYPE_NIV_PORT; 2239 gport_dest.niv_id = port_val; 2240 } 2241 if (!sal_strcasecmp(gport_type_str, "l2gre")) { 2242 gport_dest.gport_type = _SHR_GPORT_TYPE_L2GRE_PORT; 2243 gport_dest.l2gre_id = port_val; 2244 } 2245 if (!sal_strcasecmp(gport_type_str, "extender")) { 2246 gport_dest.gport_type = _SHR_GPORT_TYPE_EXTENDER_PORT; 2247 gport_dest.extender_id = port_val; 2248 } 2249 2250 gport_done: 2251 rv = _bcm_util_gport_construct(unit, &gport_dest, portp); 2252 done: 2253 if (mod_str) { 2254 sal_free(mod_str); 2255 } 2256 if (port_str) { 2257 sal_free(port_str); 2258 } 2259 if (gport_type_str) { 2260 sal_free(gport_type_str); 2261 } 2262 if (gport_val_str) { 2263 sal_free(gport_val_str); 2264 } 2265 2266 return rv; 2267 } 2268 #endif 2269 2270 int 2271 parse_port(int unit, char *s, soc_port_t *portp) 2272 { 2273 #if defined(BCM_ESW_SUPPORT) 2274 /* First try to parse a string as a GPORT identifier */ 2275 if (!parse_gport(unit, s, portp)) { 2276 /* If Success we done */ 2277 return 0; 2278 } 2279 #endif 2280 /* If parse_gport failed, try to parse the old way */ 2281 return _parse_port(unit, s, portp); 2282 } 2283 2284 int 2285 parse_bcm_port(int unit, char *s, bcm_port_t *portp) 2286 { 2287 int rv = parse_port(unit, s, (soc_port_t *)portp); 2288 2289 BCM_API_XLATE_PORT_P2A(unit, portp); 2290 2291 return rv; 2292 } 2293 2294 /* PQ_MOD_PORT parsing: PQ_MOD_PORT |= <mod>.<port> | PQ_PORT */ 2295 2296 int 2297 parse_mod_port(int unit, char *str, bcm_mod_port_t *mp) 2298 { 2299 int mod, port; 2300 char *cur_ptr = str; 2301 2302 if (isdigit((unsigned)*cur_ptr)) { 2303 mod = 0; 2304 do { 2305 mod = mod * 10 + (*cur_ptr++ - '0'); 2306 } while (isdigit((unsigned) *cur_ptr)); 2307 if (*cur_ptr == '.') { /* Parse port portion; else call parse_port */ 2308 cur_ptr++; 2309 if (isdigit((unsigned)*cur_ptr)) { 2310 port = 0; 2311 do { 2312 port = port * 10 + (*cur_ptr++ - '0'); 2313 } while (isdigit((unsigned) *cur_ptr)); 2314 if (*cur_ptr == '\0') { 2315 mp->mod = mod; 2316 mp->port = port; 2317 return 0; /* Looks good */ 2318 } 2319 } 2320 } 2321 } 2322 2323 /* If we get here, wasn't of form <mod>.<port> */ 2324 mp->mod = -1; 2325 return parse_port(unit, str, &mp->port); 2326 } 2327 2328 void 2329 dump_l2_addr(int unit, char *pfx, bcm_l2_addr_t *l2addr) 2330 { 2331 char pfmt[SOC_PBMP_FMT_LEN]; 2332 char bmstr[FORMAT_PBMP_MAX]; 2333 bcm_module_t local_modid; 2334 #ifdef BCM_ESW_SUPPORT 2335 _bcm_l2_gport_params_t gport_params; 2336 char gpfmt[FORMAT_GPORT_MAX]; 2337 #endif 2338 int islocal; 2339 2340 if (bcm_stk_my_modid_get(unit, &local_modid) != BCM_E_NONE) { 2341 local_modid = -1; 2342 } 2343 2344 cli_out("%smac=%02x:%02x:%02x:%02x:%02x:%02x vlan=%d GPORT=0x%x", 2345 pfx, 2346 l2addr->mac[0], l2addr->mac[1], l2addr->mac[2], 2347 l2addr->mac[3], l2addr->mac[4], l2addr->mac[5], 2348 l2addr->vid, l2addr->port); 2349 2350 #ifdef BCM_ESW_SUPPORT 2351 if (!SOC_IS_ARAD(unit) && BCM_GPORT_IS_SET(l2addr->port)) { 2352 if (BCM_FAILURE(_bcm_esw_l2_gport_parse(unit, l2addr, &gport_params))) { 2353 cli_out("Unknown GPORT 0x%x \n", l2addr->port); 2354 return; 2355 } 2356 #define L2_ADDR_GPORT_FORMAT_PRINT(_fmt, _gport) \ 2357 cli_out(" port=%s", format_gport(_fmt, _gport)) 2358 switch (gport_params.type) { 2359 case _SHR_GPORT_TYPE_MPLS_PORT: 2360 case _SHR_GPORT_TYPE_WLAN_PORT: 2361 case _SHR_GPORT_TYPE_MIM_PORT: 2362 case _SHR_GPORT_TYPE_TRILL_PORT: 2363 case _SHR_GPORT_TYPE_SUBPORT_GROUP: 2364 case _SHR_GPORT_TYPE_SUBPORT_PORT: 2365 case _SHR_GPORT_TYPE_VLAN_PORT: 2366 case _SHR_GPORT_TYPE_NIV_PORT: 2367 case _SHR_GPORT_TYPE_L2GRE_PORT: 2368 case _SHR_GPORT_TYPE_VXLAN_PORT: 2369 case _SHR_GPORT_TYPE_FLOW_PORT: 2370 case _SHR_GPORT_TYPE_EXTENDER_PORT: 2371 case _SHR_GPORT_TYPE_BLACK_HOLE: 2372 L2_ADDR_GPORT_FORMAT_PRINT(gpfmt, l2addr->port); 2373 break; 2374 case _SHR_GPORT_TYPE_TRUNK: 2375 l2addr->tgid = gport_params.param0; 2376 l2addr->flags |= BCM_L2_TRUNK_MEMBER; 2377 break; 2378 case _SHR_GPORT_TYPE_MODPORT: 2379 l2addr->port = gport_params.param0; 2380 l2addr->modid = gport_params.param1; 2381 break; 2382 case _SHR_GPORT_TYPE_LOCAL_CPU: 2383 l2addr->port = gport_params.param0; 2384 l2addr->modid = local_modid; 2385 break; 2386 default: 2387 cli_out("Unknown GPORT format \n"); 2388 return; 2389 } 2390 #undef L2_ADDR_GPORT_FORMAT_PRINT 2391 } 2392 if (SOC_IS_ESW(unit)) { 2393 (void)_bcm_esw_modid_is_local(unit, l2addr->modid, &islocal); 2394 } else 2395 #endif /* BCM_ESW_SUPPORT */ 2396 { 2397 islocal = (l2addr->modid == local_modid) ? TRUE : FALSE; 2398 } 2399 2400 if (l2addr->flags & BCM_L2_TRUNK_MEMBER) { 2401 cli_out(" Trunk=%d", l2addr->tgid); 2402 } else if (!BCM_GPORT_IS_SET(l2addr->port)) { 2403 cli_out(" modid=%d port=%d%s%s", l2addr->modid, l2addr->port, 2404 (islocal == TRUE) ? "/" : " ", 2405 (islocal == TRUE) ? 2406 mod_port_name(unit, l2addr->modid, l2addr->port) : " "); 2407 } 2408 2409 if (l2addr->flags & BCM_L2_STATIC) { 2410 cli_out(" Static"); 2411 } 2412 2413 if (l2addr->flags & BCM_L2_HIT) { 2414 cli_out(" Hit"); 2415 } 2416 2417 if (l2addr->cos_src != 0 || l2addr->cos_dst != 0) { 2418 cli_out(" COS(src=%d,dst=%d)", l2addr->cos_src, l2addr->cos_dst); 2419 } 2420 2421 if (l2addr->flags & BCM_L2_COS_SRC_PRI) { 2422 cli_out(" SCP"); 2423 } 2424 2425 if (l2addr->flags & BCM_L2_COPY_TO_CPU) { 2426 cli_out(" CPU"); 2427 } else if((l2addr->port == CMIC_PORT(unit)) && islocal) { 2428 if(!(l2addr->flags & (BCM_L2_L3LOOKUP | BCM_L2_TRUNK_MEMBER))) { 2429 cli_out(" CPU"); 2430 } 2431 } 2432 2433 if (l2addr->flags & BCM_L2_MIRROR) { 2434 cli_out(" Mirror"); 2435 } 2436 2437 if (l2addr->flags & BCM_L2_L3LOOKUP) { 2438 cli_out(" L3"); 2439 } 2440 2441 if (l2addr->flags & BCM_L2_DISCARD_SRC) { 2442 cli_out(" DiscardSrc"); 2443 } 2444 2445 if (l2addr->flags & BCM_L2_DISCARD_DST) { 2446 cli_out(" DiscardDest"); 2447 } 2448 2449 if (l2addr->flags & BCM_L2_PENDING) { 2450 cli_out(" Pending"); 2451 } 2452 2453 if (SOC_IS_XGS3_SWITCH(unit)) { 2454 if (l2addr->flags & BCM_L2_SETPRI) { 2455 cli_out(" ReplacePriority"); 2456 } 2457 } 2458 2459 if (l2addr->flags & BCM_L2_MCAST) { 2460 cli_out(" MCast=%d", l2addr->l2mc_group); 2461 } 2462 2463 if (SOC_PBMP_NOT_NULL(l2addr->block_bitmap)) { 2464 format_pbmp(unit, bmstr, sizeof (bmstr), l2addr->block_bitmap); 2465 cli_out(" MAC blocked port bitmap=%s: %s", 2466 SOC_PBMP_FMT(l2addr->block_bitmap, pfmt), bmstr); 2467 } 2468 2469 if (l2addr->group) { 2470 cli_out(" Group=%d", l2addr->group); 2471 } 2472 #ifdef BCM_PETRA_SUPPORT 2473 if(SOC_IS_ARAD(unit)) { 2474 cli_out(" encap_id=0x%x", l2addr->encap_id); 2475 } 2476 #endif 2477 cli_out("\n"); 2478 } 2479 2480 void 2481 dump_l2_cache_addr(int unit, char *pfx, bcm_l2_cache_addr_t *l2caddr) 2482 { 2483 cli_out("%smac=%02x:%02x:%02x:%02x:%02x:%02x", 2484 pfx, 2485 l2caddr->mac[0], l2caddr->mac[1], l2caddr->mac[2], 2486 l2caddr->mac[3], l2caddr->mac[4], l2caddr->mac[5]); 2487 2488 if (!ENET_MACADDR_BROADCAST(l2caddr->mac_mask)) { 2489 cli_out("/%02x:%02x:%02x:%02x:%02x:%02x", 2490 l2caddr->mac_mask[0], l2caddr->mac_mask[1], l2caddr->mac_mask[2], 2491 l2caddr->mac_mask[3], l2caddr->mac_mask[4], l2caddr->mac_mask[5]); 2492 } 2493 2494 cli_out(" vlan=%d", l2caddr->vlan); 2495 if (l2caddr->vlan_mask != BCM_L2_VID_MASK_ALL) { 2496 cli_out("/0x%03x", l2caddr->vlan_mask); 2497 } 2498 2499 if (l2caddr->src_port_mask != 0) { 2500 cli_out(" srcport=%d", l2caddr->src_port); 2501 if (l2caddr->src_port_mask != BCM_L2_SRCPORT_MASK_ALL) { 2502 cli_out("/0x%02x", l2caddr->src_port_mask); 2503 } 2504 } 2505 2506 if (l2caddr->flags & BCM_L2_CACHE_TRUNK) { 2507 cli_out(" trunk=%d", l2caddr->dest_trunk); 2508 } else { 2509 cli_out(" modid=%d port=%d/%s", 2510 l2caddr->dest_modid, 2511 l2caddr->dest_port, 2512 mod_port_name(unit, l2caddr->dest_modid, l2caddr->dest_port)); 2513 } 2514 2515 if (l2caddr->flags & BCM_L2_CACHE_SETPRI) { 2516 cli_out(" prio=%d", l2caddr->prio); 2517 } 2518 2519 if (l2caddr->flags & BCM_L2_CACHE_BPDU) { 2520 cli_out(" BPDU"); 2521 } 2522 2523 if ((l2caddr->flags & BCM_L2_CACHE_CPU) || 2524 (l2caddr->dest_port == CMIC_PORT(unit))) { 2525 cli_out(" CPU"); 2526 } 2527 2528 if (l2caddr->flags & BCM_L2_CACHE_L3) { 2529 cli_out(" L3"); 2530 } 2531 2532 if (l2caddr->flags & BCM_L2_CACHE_DISCARD) { 2533 cli_out(" Discard"); 2534 } 2535 2536 if (l2caddr->flags & BCM_L2_CACHE_MIRROR) { 2537 cli_out(" Mirror"); 2538 } 2539 2540 if (SOC_IS_XGS3_SWITCH(unit)) { 2541 if (l2caddr->flags & BCM_L2_CACHE_SETPRI) { 2542 cli_out(" ReplacePriority"); 2543 } 2544 } 2545 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) 2546 if (SOC_IS_FIREBOLT2(unit) || SOC_IS_TRX(unit)) { 2547 if (l2caddr->flags & BCM_L2_CACHE_LEARN_DISABLE) { 2548 cli_out(" LearnDisable"); 2549 } 2550 } 2551 #endif /* BCM_FIREBOLT2_SUPPORT */ 2552 2553 #if defined(BCM_TRX_SUPPORT) 2554 if (SOC_IS_TRX(unit)) { 2555 cli_out(" lookup_class =%d", l2caddr->lookup_class); 2556 } 2557 #endif /* BCM_TRX_SUPPORT */ 2558 if (l2caddr->flags & BCM_L2_CACHE_PROTO_PKT) { 2559 cli_out(" ProtocolPkt"); 2560 } 2561 2562 cli_out("\n"); 2563 } 2564 2565 /* 2566 * Format a pbmp into a string, the opposite of what parse_pbmp does. 2567 * For example, 0x00ffffff ==> "fe"; 0x0b000007 ==> "cpu,ge,fe0-fe2". 2568 * For clarity, returns "ge,fe" instead of "e" (or on GSL, just "ge"), 2569 * and returns "cpu,ge,fe" instead of "all" (or on GSL, just "cpu,ge"). 2570 */ 2571 2572 STATIC void 2573 _format_pbmp_type(int unit, 2574 char *dest, 2575 int bufsize, 2576 soc_pbmp_t pbmp, 2577 char *pname, 2578 soc_pbmp_t pall) 2579 { 2580 soc_pbmp_t bm; 2581 soc_port_t tport, port, dport, pfirst, plast; 2582 int size = 0; 2583 2584 if (SOC_PBMP_IS_NULL(pall)) { /* no such ports */ 2585 return; 2586 } 2587 2588 SOC_PBMP_ASSIGN(bm, pbmp); 2589 SOC_PBMP_AND(bm, pall); 2590 if (SOC_PBMP_EQ(bm, pall)) { /* all ports of this type */ 2591 size = sal_strlen(dest); 2592 assert((bufsize - size) >= 0); 2593 sal_snprintf(dest + size,(bufsize - size), ",%s", pname); 2594 return; 2595 } 2596 /* 2597 * The slightly tricky thing here is handling sparse sets of 2598 * bits in pall (on Tucana or Herc4 for example). 2599 */ 2600 pfirst = plast = -1; 2601 port = -1; 2602 /* coverity[overrun-local] */ 2603 DPORT_SOC_PBMP_ITER(unit, pall, dport, tport) { /* a subset of ports */ 2604 port += 1; 2605 /* coverity[overrun-local] */ 2606 if (SOC_PBMP_MEMBER(pbmp, tport)) { 2607 if (pfirst < 0) { 2608 pfirst = plast = (SOC_IS_DPP(unit) 2609 #ifdef BCM_DNX_SUPPORT 2610 || SOC_IS_DNX(unit) 2611 #endif 2612 #ifdef BCM_DNF_SUPPORT 2613 || SOC_IS_DNXF(unit) 2614 #endif 2615 )?dport:DPORT_FROM_DPORT_INDEX(unit, dport, port); 2616 } else { 2617 plast = (SOC_IS_DPP(unit) 2618 #ifdef BCM_DNX_SUPPORT 2619 || SOC_IS_DNX(unit) 2620 #endif 2621 #ifdef BCM_DNF_SUPPORT 2622 || SOC_IS_DNXF(unit) 2623 #endif 2624 )?dport:DPORT_FROM_DPORT_INDEX(unit, dport, port); 2625 } 2626 continue; 2627 } 2628 if (pfirst >= 0) { 2629 size = sal_strlen(dest); 2630 assert((bufsize - size) >= 0); 2631 sal_snprintf(dest + sal_strlen(dest), (bufsize - size), ",%s%d", pname, pfirst); 2632 if (pfirst != plast) { 2633 size = sal_strlen(dest); 2634 assert((bufsize - size) >= 0); 2635 sal_snprintf(dest + sal_strlen(dest), (bufsize - size), "-%s%d", pname, plast); 2636 } 2637 pfirst = plast = -1; 2638 } 2639 } 2640 2641 if (pfirst >= 0) { 2642 size = sal_strlen(dest); 2643 assert((bufsize - size) >= 0); 2644 sal_snprintf(dest + sal_strlen(dest), (bufsize - size), ",%s%d", pname, pfirst); 2645 if (pfirst != plast) { 2646 size = sal_strlen(dest); 2647 assert((bufsize - size) >= 0); 2648 sal_snprintf(dest + sal_strlen(dest), (bufsize - size), "-%s%d", pname, plast); 2649 } 2650 } 2651 } 2652 2653 char * 2654 format_pbmp(int unit, char *buf, int bufsize, soc_pbmp_t pbmp) 2655 { 2656 char tmp[FORMAT_PBMP_MAX]; 2657 soc_pbmp_t tpbm; 2658 2659 SOC_PBMP_ASSIGN(tpbm, pbmp); 2660 SOC_PBMP_REMOVE(tpbm, PBMP_ALL(unit)); 2661 if (SOC_PBMP_NOT_NULL(tpbm)) { 2662 sal_strncpy(buf, SOC_PBMP_FMT(pbmp, tmp), bufsize); 2663 } else if (SOC_PBMP_IS_NULL(pbmp)) { 2664 /* 2665 * COVERITY 2666 * 2667 * Handled below 2668 */ 2669 /* coverity[buffer_size] */ 2670 sal_strncpy(buf, "none", bufsize); 2671 if (bufsize < 5) { 2672 /* Guarantee null termination of buf */ 2673 buf[bufsize - 1] = 0; 2674 } 2675 } else { 2676 if (SOC_PBMP_MEMBER(pbmp, CMIC_PORT(unit)) != 0) { 2677 /* Coverity[secure_coding] */ 2678 sal_strcpy(tmp, ",cpu"); 2679 } else { 2680 tmp[0] = tmp[1] = 0; 2681 } 2682 2683 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "cd", PBMP_CDE_ALL(unit)); 2684 2685 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "ce", PBMP_CE_ALL(unit)); 2686 if(SOC_IS_SAND(unit)) { 2687 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "xl", PBMP_XL_ALL(unit)); 2688 } 2689 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "fe", PBMP_FE_ALL(unit)); 2690 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "ge", PBMP_GE_ALL(unit)); 2691 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "xe", PBMP_XE_ALL(unit)); 2692 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "hg", PBMP_HG_ALL(unit)); 2693 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "spi", PBMP_SPI_ALL(unit)); 2694 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "sci", PBMP_SCI_ALL(unit)); 2695 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "sfi", PBMP_SFI_ALL(unit)); 2696 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "spi_s", PBMP_SPI_SUBPORT_ALL(unit)); 2697 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "hg_s", PBMP_HG_SUBPORT_ALL(unit)); 2698 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "il", PBMP_IL_ALL(unit)); 2699 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "qsgmii", PBMP_QSGMII_ALL(unit)); 2700 _format_pbmp_type(unit, tmp, FORMAT_PBMP_MAX, pbmp, "roe", PBMP_CPRI_ALL(unit)); 2701 sal_strncpy(buf, tmp + 1, bufsize); 2702 } 2703 return buf; 2704 } 2705 2706 char * 2707 format_bcm_pbmp(int unit, char *buf, int bufsize, bcm_pbmp_t pbmp) 2708 { 2709 pbmp_t tpbm; 2710 2711 SOC_PBMP_ASSIGN(tpbm, pbmp); 2712 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tpbm); 2713 return format_pbmp(unit, buf, bufsize, tpbm); 2714 } 2715 2716 char * 2717 bcm_port_name(int unit, int port) 2718 { 2719 char *name = NULL; 2720 2721 BCM_API_XLATE_PORT_A2P(unit, &port); 2722 if (SOC_PORT_VALID_RANGE(unit, port)) { 2723 name = SOC_PORT_NAME(unit, port); 2724 } 2725 if (name == NULL) { 2726 name = "<unknown>"; 2727 } 2728 return name; 2729 } 2730 2731 char * 2732 mod_port_name(int unit, int modid, int port) 2733 { 2734 bcm_gport_t gport; 2735 bcm_port_t local_port; 2736 2737 if (BCM_GPORT_IS_SET(port)) { 2738 /* If port is already a gport, no conversion necessary */ 2739 gport = port; 2740 } else { 2741 /* else convert modid/port to gport */ 2742 BCM_GPORT_MODPORT_SET(gport, modid, port); 2743 } 2744 if (BCM_SUCCESS(bcm_port_local_get(unit, gport, &local_port))) { 2745 return bcm_port_name(unit, local_port); 2746 } 2747 return ""; 2748 } 2749 2750 /* 2751 * Parse a string containing a range of COS's. 2752 * The input format is: 2753 * 2754 * COS_RANGE : COS '-' COS { return $1 .. $2; } 2755 * | COS { return $1 .. $1; } 2756 * | {NULL} | '' | 'ALL' { return 0 .. NUM_COS - 1; } 2757 * ; 2758 * COS : INTEGER{NUM_COS} { return $1; } 2759 * ; 2760 */ 2761 2762 int 2763 parse_num_range(int unit, char *s, int *min, int *max, int legal_min, 2764 int legal_max) 2765 { 2766 if (s == 0 || *s == 0 || sal_strcasecmp(s, "all") == 0) { 2767 *min = legal_min; 2768 *max = legal_max; 2769 return 0; 2770 } 2771 2772 if ((*min = *s++ - '0') < legal_min || *min > legal_max) { 2773 return -1; 2774 } 2775 2776 if (*s == 0) { 2777 *max = *min; 2778 return 0; 2779 } 2780 2781 if (*s++ != '-') { 2782 return -1; 2783 } 2784 2785 if ((*max = *s++ - '0') > legal_max) { 2786 return -1; 2787 } 2788 2789 return (*s == 0 && *max >= *min) ? 0 : -1; 2790 } 2791 2792 int 2793 diag_parse_range(char *low, char *high, 2794 int *min, int *max, 2795 int legal_min, int legal_max) 2796 { 2797 if (low == 0 || *low == 0 || sal_strcasecmp(low, "all") == 0) { 2798 *min = legal_min; 2799 *max = legal_max; 2800 return 0; 2801 } 2802 2803 *min = sal_strtoul(low, NULL, 0); 2804 2805 if ((*min < legal_min) || *min > legal_max) { 2806 return -1; 2807 } 2808 2809 if (high == 0 || *high == 0) { 2810 *max = *min; 2811 return 0; 2812 } 2813 2814 *max = sal_strtoul(high, NULL, 0); 2815 2816 if (*max < *min || *max > legal_max) { 2817 return -1; 2818 } 2819 2820 return 0; 2821 } 2822 2823 /* 2824 * Utility routine for parse_block_range 2825 */ 2826 2827 STATIC int 2828 _parse_block(int unit, soc_block_types_t block_types, char **s, int *nump) 2829 { 2830 char *sblk, *snum; 2831 int blk, num; 2832 int i, phy_port; 2833 soc_block_t blktype; 2834 soc_block_name_t *blk_names; 2835 int port_num_blktype; 2836 2837 { 2838 #if defined(BCM_SAND_SUPPORT) 2839 if (SOC_IS_SAND(unit)) { 2840 blk_names = soc_dpp_block_names; 2841 } 2842 else 2843 #endif 2844 { 2845 blk_names = soc_block_names; 2846 } 2847 } 2848 2849 if (sal_strncasecmp("PORT_GROUP", *s, sizeof("PORT_GROUP") - 1) == 0) { 2850 switch ((*s)[sizeof("PORT_GROUP") - 1]) { 2851 case '4': 2852 blktype = SOC_BLK_PORT_GROUP4; 2853 break; 2854 case '5': 2855 blktype = SOC_BLK_PORT_GROUP5; 2856 break; 2857 default: 2858 return -1; 2859 } 2860 switch ((*s)[sizeof("PORT_GROUP*_") - 1]) { 2861 case 'X': 2862 case 'x': 2863 num = 0; 2864 break; 2865 case 'Y': 2866 case 'y': 2867 num = 1; 2868 break; 2869 default: 2870 return -1; 2871 } 2872 SOC_BLOCK_ITER(unit, blk, blktype) { 2873 if (SOC_BLOCK_INFO(unit, blk).number == num) { 2874 *s += sizeof("PORT_GROUP*_*") - 1; 2875 return blk; 2876 } 2877 } 2878 return -1; 2879 } 2880 2881 /* To cover for Apache XLPORTB0 and CLG2PORT blocks */ 2882 if ((sal_strncasecmp("XLB0PORT", *s, (sizeof("XLB0PORT") - 1)) == 0) || 2883 (sal_strncasecmp("CLG2PORT", *s, (sizeof("CLG2PORT") - 1)) == 0)) { 2884 sblk = *s + 8; 2885 } else { 2886 /* find the last "number" during string "s" 2887 ex. s = "pgw_ge8p2" ==> sblk = "2" 2888 */ 2889 int index = sal_strlen(*s); 2890 2891 sblk = &((*s)[index]); 2892 while ((index-1) >= 0 && 2893 ((*s)[index-1] >= '0' && (*s)[index-1] <= '9')) { 2894 sblk--; 2895 index--; 2896 } 2897 } 2898 2899 /* skip past prefix */ 2900 num = 0; 2901 snum = sblk; 2902 while (*snum && *snum >= '0' && *snum <= '9') { 2903 num = (num * 10) + (*snum - '0'); 2904 snum++; 2905 } 2906 2907 /* try to match a port name before we split the prefix */ 2908 PBMP_ALL_ITER(unit, i) { 2909 if (sal_strncasecmp(SOC_PORT_NAME(unit, i), *s, snum-*s) == 0) { 2910 *s = snum; 2911 if (soc_feature(unit, soc_feature_logical_port_num)) { 2912 phy_port = SOC_INFO(unit).port_l2p_mapping[i]; 2913 } else { 2914 phy_port = i; 2915 } 2916 2917 port_num_blktype = SOC_DRIVER(unit)->port_num_blktype > 1 ? 2918 SOC_DRIVER(unit)->port_num_blktype : 1; 2919 if (port_num_blktype > 1) { 2920 for (i = 0; i < port_num_blktype; i++) { 2921 blk = SOC_PORT_IDX_BLOCK(unit, phy_port, i); 2922 if (blk < 0) { 2923 break; 2924 } 2925 if (SOC_BLOCK_IN_LIST(block_types, 2926 SOC_BLOCK_TYPE(unit, blk))) { 2927 return blk; 2928 } 2929 } 2930 return -1; 2931 } else { 2932 return SOC_PORT_BLOCK(unit, phy_port); 2933 } 2934 } 2935 } 2936 2937 *sblk = '\0'; 2938 sblk = *s; 2939 *s = snum; 2940 2941 if (*sblk == '\0') { /* just digits */ 2942 if (nump == NULL) { 2943 return -1; 2944 } 2945 *nump = num; 2946 return 0; 2947 } 2948 2949 /* try to match a block name */ 2950 for (i = 0; blk_names[i].blk != SOC_BLK_NONE; i++) { 2951 if (sal_strcasecmp(blk_names[i].name, sblk) == 0) { 2952 blktype = blk_names[i].blk; 2953 SOC_BLOCK_ITER(unit, blk, blktype) { 2954 if (SOC_BLOCK_INFO(unit, blk).number == num) { 2955 return blk; 2956 } 2957 } 2958 return -1; 2959 } 2960 } 2961 2962 return -1; 2963 } 2964 2965 /* 2966 * Parse a string containing a range of StrataSwitch internal blocks. 2967 * The input format is: 2968 * 2969 * BLK_RANGE : BLOCK '-' BLOCK { return $1 .. $2; } 2970 * | BLOCK { return $1 .. $1; } 2971 * | 'E' { return MIN_EPIC .. MAX_EPIC; } 2972 * | 'G' { return MIN_GPIC .. MAX_GPIC; } 2973 * | 'H' { return MIN_HPIC .. MAX_HPIC; } 2974 * | 'ALL' { return MIN_EPIC .. MAX_GPIC; } 2975 * ; 2976 * BLOCK : INTEGER{NUM_PIC} { return $1; } 2977 * | 'E' INTEGER{NUM_EPIC} { return MIN_EPIC + $1; } 2978 * | 'G' INTEGER{NUM_GPIC} { return MIN_GPIC + $1; } 2979 * | 'H' INTEGER{NUM_GPIC} { return MIN_HPIC + $1; } 2980 * ; 2981 */ 2982 2983 int 2984 parse_block_range(int unit, 2985 soc_block_types_t regtype, 2986 char *s, 2987 int *min, 2988 int *max, 2989 soc_block_types_t mask) 2990 { 2991 int i, nummin, nummax; 2992 int matched, blk, idx = 0; 2993 soc_block_name_t *blk_port_names; 2994 soc_block_name_t *blk_names; 2995 2996 { 2997 #if defined(BCM_SAND_SUPPORT) 2998 if (SOC_IS_SAND(unit)) { 2999 blk_names = soc_dpp_block_names; 3000 blk_port_names = soc_dpp_block_port_names; 3001 } 3002 else 3003 #endif 3004 { 3005 blk_names = soc_block_names; 3006 blk_port_names = soc_block_port_names; 3007 } 3008 } 3009 3010 *min = 0; 3011 *max = SOC_INFO(unit).block_num; 3012 3013 /* empty string: all blocks */ 3014 if (s == NULL || *s == '\0') { 3015 return 0; 3016 } 3017 3018 /* all blocks */ 3019 if (sal_strcasecmp(s, "all") == 0 || sal_strcasecmp(s, "*") == 0) { 3020 return 0; 3021 } 3022 3023 /* all blocks of a certain type */ 3024 for (i = 0; blk_names[i].blk != SOC_BLK_NONE; i++) { 3025 if (sal_strcasecmp(blk_names[i].name, s) == 0) { 3026 mask[0] = blk_names[i].blk; 3027 return 0; 3028 } 3029 } 3030 3031 if (SOC_IS_ESW(unit)) { 3032 /* all blocks of a certain port type */ 3033 /* (remember, hg matches hpic and ipic) */ 3034 matched = 0; 3035 for (i = 0; blk_port_names[i].blk != SOC_BLK_NONE; i++) { 3036 if (sal_strcasecmp(blk_port_names[i].name, s) == 0) { 3037 mask[idx] = blk_port_names[i].blk; 3038 matched += 1; 3039 idx++; 3040 } 3041 } 3042 if (matched) { 3043 return 0; 3044 } 3045 } 3046 3047 nummin = -1; 3048 if ((*min = _parse_block(unit, regtype, &s, &nummin)) < 0) { 3049 return -1; 3050 } 3051 3052 if (*s == '\0') { 3053 if (nummin < 0) { 3054 *max = *min; 3055 return 0; 3056 } 3057 /* find the nummin'th port block */ 3058 matched = -1; 3059 SOC_BLOCK_ITER(unit, blk, SOC_BLK_PORT) { 3060 matched += 1; 3061 if (matched == nummin) { 3062 *max = *min = blk; 3063 return 0; 3064 } 3065 } 3066 return -1; 3067 } 3068 3069 if (*s++ != '-') { 3070 return -1; 3071 } 3072 3073 nummax = -1; 3074 if ((*max = _parse_block(unit, regtype, &s, &nummax)) < 0) { 3075 return -1; 3076 } 3077 if (*s != '\0') { 3078 return -1; 3079 } 3080 if ((nummin >= 0 && nummax < 0) || (nummin < 0 && nummax >= 0)) { 3081 return -1; 3082 } 3083 if (nummin < 0 && nummax < 0) { 3084 if (*min > *max) { 3085 return -1; 3086 } 3087 return 0; 3088 } 3089 if (nummin > nummax) { 3090 return -1; 3091 } 3092 /* find the nummin'th through nummax'th blocks */ 3093 matched = -1; 3094 SOC_BLOCK_ITER(unit, blk, SOC_BLK_PORT) { 3095 matched += 1; 3096 if (matched == nummin) { 3097 *min = blk; 3098 } 3099 if (matched == nummax) { 3100 *max = blk; 3101 return 0; 3102 } 3103 } 3104 return -1; 3105 } 3106 3107 /* 3108 * Parse a CMIC register name and return offset. Matching is 3109 * case-insensitive and works with or without the "CMIC_" prefix. Also 3110 * accepts address offset as an integer in hex or decimal. 3111 */ 3112 3113 int 3114 parse_cmic_regname(int unit, char *name, uint32 *offset_ptr) 3115 { 3116 3117 #if defined(BCM_ESW_SUPPORT) || defined(BCM_CMICM_SUPPORT) || defined(BCM_CMICX_SUPPORT) 3118 if (isint(name)) { 3119 *offset_ptr = parse_integer(name); 3120 return 0; /* Success */ 3121 } 3122 #ifdef BCM_CMICM_SUPPORT 3123 if(soc_feature(unit, soc_feature_cmicm)) { 3124 char *s; 3125 int i; 3126 soc_cmicm_reg_t *creg; 3127 for (i = 0; i < NUM_CMICM_REGS; i++) { 3128 creg = soc_cmicm_reg_get(i); 3129 s = creg->name; 3130 if (sal_strcasecmp(name, s) == 0 || sal_strcasecmp(name, s + 5) == 0) { 3131 *offset_ptr = creg->addr; 3132 return 0; 3133 } 3134 } 3135 return -1; 3136 } 3137 #endif 3138 3139 #ifdef BCM_CMICX_SUPPORT 3140 if(soc_feature(unit, soc_feature_cmicx)) { 3141 return(soc_parse_cmicx_regname(unit, name, offset_ptr)); 3142 } 3143 #endif 3144 3145 for (*offset_ptr = 0; *offset_ptr <= 0x10000; (*offset_ptr) += 4) { 3146 char *s = soc_pci_off2name(unit, *offset_ptr); 3147 if (sal_strcasecmp(name, s) == 0 || sal_strcasecmp(name, s + 5) == 0) 3148 return 0; /* Success */ 3149 } 3150 #endif 3151 return -1; 3152 } 3153 3154 /* 3155 * Look up a table memory by user-friendly name. 3156 * On success, stores result and returns 0. On failure, returns -1. 3157 * 3158 * A memory array index may be added after the memory name in square brackets like: mem[3]. 3159 * The function will fail for memory arrays for which an array index 3160 * is not specified when array_index is non-NULL. 3161 * The function will fail for non array memories for which an array index is specified. 3162 * For non array memories, array_index may be NULL; If not Null 0 will be returned in it. 3163 * 3164 * A table copy number may be appended to the table name following a 3165 * period, e.g. "mcast.2". If so, this value is returned in the copyno 3166 * parameter. If not, COPYNO_ALL is returned in the copyno parameter. 3167 * If copyno is NULL, an appended copy number causes a syntax error. 3168 * 3169 * Also accepts suffixes .E0-E2 and .G0-G1 for StrataSwitch 3170 * Also accepts suffixes .G0-.G11 and .H0 for Draco 3171 * Also accepts suffixes .H0-H7 for Hercules 3172 */ 3173 3174 int 3175 parse_memory_name(int unit, soc_mem_t *result, char *str, int *copyno, unsigned *array_index) 3176 { 3177 soc_mem_t mem; 3178 int blk, numblk, matched; 3179 char *cp, *aip, tmp[80]; 3180 uint64 blkbits; 3181 unsigned arr_ind; 3182 int block_types[2]; 3183 3184 if (str == NULL || *str == '\0') { 3185 return -1; 3186 } 3187 3188 /* Do not destroy input string */ 3189 sal_strncpy(tmp, str, sizeof (tmp)); 3190 tmp[sizeof (tmp) - 1] = '\0'; 3191 3192 blk = COPYNO_ALL; 3193 numblk = -1; 3194 if (( ((aip = sal_strchr(tmp, '[')) != NULL) && 3195 ((cp = sal_strchr(aip+1, ']')) != NULL) && (cp-aip > 1) ) || 3196 ( ((aip = sal_strchr(tmp, '(')) != NULL) && 3197 ((cp = sal_strchr(aip+1, ')')) != NULL) && (cp-aip > 1) ) ) { 3198 /* handle memory array */ 3199 3200 3201 3202 /* handle initial spaces after '[' */ 3203 for (cp = aip+1; *cp == ' '; ++cp) { 3204 } 3205 if (*cp < '0' || *cp >'9') { 3206 return -1; 3207 } 3208 /* read array index */ 3209 arr_ind = 0; 3210 for (; *cp >= '0' && *cp <='9'; ++cp) { 3211 arr_ind = arr_ind * 10 + (*cp - '0'); 3212 } 3213 /* handle trailing spaces before ']' */ 3214 for (; *cp == ' '; ++cp) { 3215 } 3216 if ((*cp != ']') && (*cp != ')')) { /* verify closing ']' */ 3217 return -1; 3218 } 3219 if (array_index == NULL) { 3220 return -1; 3221 } else { 3222 *array_index = arr_ind; 3223 } 3224 cp = sal_strchr(cp+1, '.'); 3225 *aip = '\0'; 3226 } else { 3227 arr_ind = 0xffffffff; 3228 cp = sal_strchr(tmp, '.'); 3229 if (array_index != NULL) { 3230 *array_index = 0; 3231 } 3232 } 3233 3234 if (cp != NULL) { 3235 if (copyno == NULL) { 3236 return -1; 3237 } 3238 *cp++ = '\0'; 3239 } 3240 3241 mem = -1; 3242 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 3243 #ifdef BCM_TOMAHAWK3_SUPPORT 3244 if (SOC_IS_TOMAHAWK3(unit)) { 3245 if (sal_strcasecmp(tmp, "EXACT_MATCH_ONLY_DOUBLE") == 0) { 3246 sal_strncpy(tmp, "EXACT_MATCH_2", sizeof (tmp)); 3247 } 3248 if (sal_strcasecmp(tmp, "EXACT_MATCH_ONLY_QUAD") == 0) { 3249 sal_strncpy(tmp, "EXACT_MATCH_4", sizeof (tmp)); 3250 } 3251 } 3252 #endif 3253 3254 for (mem = 0; mem < NUM_SOC_MEM; mem++) { 3255 if (!SOC_MEM_IS_VALID(unit, mem)) { 3256 continue; 3257 } 3258 3259 if (sal_strcasecmp(tmp, SOC_MEM_NAME(unit, mem)) == 0) { 3260 break; 3261 } 3262 3263 if (sal_strcasecmp(tmp, SOC_MEM_UFNAME(unit, mem)) == 0) { 3264 break; 3265 } 3266 3267 if (SOC_MEM_UFALIAS(unit, mem) != NULL && 3268 sal_strcasecmp(tmp, SOC_MEM_UFALIAS(unit, mem)) == 0) { 3269 break; 3270 } 3271 } 3272 if (mem == NUM_SOC_MEM) { 3273 return -1; 3274 } 3275 #endif 3276 3277 if (cp != NULL) { 3278 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 3279 blk = SOC_MEM_BLOCK_ANY(unit, mem); 3280 block_types[0] = SOC_BLOCK_TYPE(unit, blk); 3281 #else 3282 block_types[0] = SOC_BLOCK_TYPE_INVALID; 3283 #endif 3284 block_types[1] = SOC_BLOCK_TYPE_INVALID; 3285 blk = _parse_block(unit, block_types, &cp, &numblk); 3286 if (blk < 0 || *cp != '\0') { 3287 return -1; 3288 } 3289 } 3290 3291 /* memory array related validation */ 3292 if (arr_ind != 0xffffffff) { 3293 /* an array index was specified, verify that this is a memory array and that the index is in range */ 3294 if (!SOC_MEM_IS_ARRAY(unit, mem)) { 3295 cli_out("ERROR: an array index was specified for a memory which is not an array\n"); 3296 return -1; 3297 } else if (arr_ind >= (SOC_MEM_NUMELS(unit, mem) + SOC_MEM_FIRST_ARRAY_INDEX(unit, mem)) || arr_ind < SOC_MEM_FIRST_ARRAY_INDEX(unit, mem)) { 3298 cli_out("ERROR: array index %u is out of range, should be under %u and above %u \n ", 3299 arr_ind, (SOC_MEM_FIRST_ARRAY_INDEX(unit, mem) + SOC_MEM_NUMELS(unit, mem) - 1), SOC_MEM_FIRST_ARRAY_INDEX(unit, mem)); 3300 return -1; 3301 } 3302 } else if (array_index != NULL && SOC_MEM_IS_ARRAY(unit, mem)) { 3303 /* no array index specified, but this is a memory array */ 3304 cli_out("ERROR: an array index was not specified for a memory array\n"); 3305 return -1; 3306 } 3307 3308 if (numblk >= 0) { 3309 if (SOC_IS_XGS12_FABRIC(unit)) { 3310 /* 3311 * numblk is the index into a list of SOC_BLK_PORT blocks 3312 * well, thats intuitive, isn't it? 3313 * This makes numblk==0 be the cpic in all cases. 3314 * AAAAAAAARRRRRRRRRRRGGGGGGGGGGGHHHHHHHHHHHH!!!!!!! 3315 */ 3316 matched = -1; 3317 SOC_BLOCK_ITER(unit, blk, SOC_BLK_PORT) { 3318 matched += 1; 3319 if (matched == numblk) { 3320 break; 3321 } 3322 } 3323 } else { 3324 /* 3325 * numblk is the index into the list of blocks valid 3326 * for this memory (ie: it's a copy number) 3327 */ 3328 COMPILER_64_SET(blkbits, SOC_MEM_INFO(unit, mem).blocks_hi, 3329 SOC_MEM_INFO(unit, mem).blocks); 3330 matched = -1; 3331 for (blk = 0; !COMPILER_64_IS_ZERO(blkbits); 3332 blk++) { 3333 if (COMPILER_64_BITTEST(blkbits, 1)) { 3334 matched += 1; 3335 if (matched == numblk) { 3336 break; 3337 } 3338 } 3339 COMPILER_64_SHR(blkbits, 1); 3340 } 3341 } 3342 if (matched != numblk) { 3343 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 3344 cli_out("ERROR: memory %s.%d is not valid (not enough blocks)\n", 3345 SOC_MEM_UFNAME(unit, mem), numblk); 3346 #endif 3347 return -1; 3348 } 3349 } 3350 3351 *result = mem; 3352 if (copyno != NULL) { 3353 *copyno = blk; 3354 } 3355 3356 if (blk != COPYNO_ALL && !SOC_MEM_BLOCK_VALID(unit, mem, blk)) { 3357 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 3358 cli_out("ERROR: memory %s.%s (block %d) is not valid\n", 3359 SOC_MEM_UFNAME(unit, mem), 3360 SOC_BLOCK_NAME(unit, blk), 3361 blk); 3362 #endif 3363 return -1; 3364 } 3365 return 0; 3366 } 3367 3368 #if defined(BCM_ESW_SUPPORT) 3369 /* 3370 * parse_format_name 3371 * 3372 * Parses a string containing format name. 3373 * and return format ID. 3374 */ 3375 int 3376 parse_format_name(int unit, char *str, soc_format_t *format) 3377 { 3378 3379 int f_idx = 0; 3380 if (str == NULL || *str == '\0') { 3381 return -1; 3382 } 3383 for (f_idx = 0; f_idx < NUM_SOC_FORMAT; f_idx++) { 3384 if (!SOC_FORMAT_IS_VALID(unit, f_idx)) { 3385 continue; 3386 } 3387 if (sal_strcmp(str, 3388 SOC_FORMAT_NAME(unit, f_idx)) == 0) { 3389 *format = f_idx; 3390 return 0; 3391 } 3392 } 3393 return -1; 3394 } 3395 #endif /* BCM_ESW_SUPPORT */ 3396 /* 3397 * parse_memory_index 3398 * 3399 * Parses a string containing an integer memory index, allowing 3400 * the two special values "min" and "max" to indicate the minimum 3401 * and maximum indices. 3402 */ 3403 3404 int 3405 parse_memory_index(int unit, soc_mem_t mem, char *val_str) 3406 { 3407 int index; 3408 3409 index = 0; 3410 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 3411 if (!sal_strcasecmp(val_str, "min")) { 3412 return soc_mem_index_min(unit, mem); 3413 } 3414 3415 if (!sal_strcasecmp(val_str, "max")) { 3416 return soc_mem_index_max(unit, mem); 3417 } 3418 3419 index = parse_integer(val_str); 3420 3421 if (!soc_mem_index_valid(unit, mem, index)) { 3422 if (!(SOC_DEFIP_HOLE_RANGE_CHECK(unit, mem, index))) { 3423 cli_out("WARNING: index %d out of range for memory %s\n", 3424 index, SOC_MEM_UFNAME(unit, mem)); 3425 } 3426 } 3427 #endif 3428 3429 return index; 3430 } 3431 3432 /* 3433 * parse_memory_index 3434 * 3435 * Parses a string containing an integer memory array index, allowing 3436 * the two special values "min" and "max" to indicate the minimum 3437 * and maximum indices. 3438 */ 3439 3440 unsigned 3441 parse_memory_array_index(int unit, soc_mem_t mem, char *val_str) 3442 { 3443 unsigned array_index = 0; 3444 3445 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 3446 if (SOC_MEM_IS_ARRAY(unit, mem)) { 3447 soc_mem_array_info_t *maip = SOC_MEM_ARRAY_INFOP(unit, mem); 3448 if (maip) { 3449 if (!sal_strcasecmp(val_str, "min")) { 3450 return maip->first_array_index; 3451 } else if (!sal_strcasecmp(val_str, "max")) { 3452 return (maip->numels - 1 + maip->first_array_index); 3453 } 3454 array_index = parse_integer(val_str); 3455 if (array_index >= maip->numels + maip->first_array_index) { 3456 cli_out("WARNING: array index %u out of range for memory %s, changing it to %u\n", 3457 array_index, SOC_MEM_UFNAME(unit, mem), maip->numels - 1); 3458 array_index = (maip->numels - 1) + maip->first_array_index; 3459 } else if (array_index < maip->first_array_index) { 3460 cli_out("WARNING: array index %u out of range for memory %s, changing it to %u\n", 3461 array_index, SOC_MEM_UFNAME(unit, mem), maip->first_array_index); 3462 array_index = maip->first_array_index; 3463 } 3464 } 3465 } 3466 #endif 3467 3468 return array_index; 3469 } 3470 3471 /* 3472 * parse_port_mode 3473 * 3474 * Parses a port mode string consisting of a comma-separated 3475 * list of modes. Examples of valid input are: 3476 * 3477 * 1000full,100full,100half,10full,10half 3478 * 1000full,100,10 (equivalent to above) 3479 * 1000full,100,10,pause 3480 */ 3481 3482 static struct { 3483 char *str; 3484 soc_port_mode_t pm; 3485 } pm_map[] = { 3486 /* Multi-bit masks should come before their comprised 1-bit masks */ 3487 { "full", SOC_PM_FD }, 3488 { "half", SOC_PM_HD }, 3489 { "16G", SOC_PM_16GB }, 3490 { "16Gfull", SOC_PM_16GB_FD }, 3491 { "16Ghalf", SOC_PM_16GB_HD }, 3492 { "13G", SOC_PM_13GB }, 3493 { "13Gfull", SOC_PM_13GB_FD}, 3494 { "13Ghalf", SOC_PM_13GB_HD}, 3495 { "12G", SOC_PM_12GB }, 3496 { "12Gfull", SOC_PM_12GB_FD}, 3497 { "12Ghalf", SOC_PM_12GB_HD}, 3498 { "10G", SOC_PM_10GB }, 3499 { "10Gfull", SOC_PM_10GB_FD }, 3500 { "10Ghalf", SOC_PM_10GB_HD }, 3501 { "2500", SOC_PM_2500MB }, 3502 { "2500full", SOC_PM_2500MB_FD }, 3503 { "2500half", SOC_PM_2500MB_HD }, 3504 { "1000", SOC_PM_1000MB }, 3505 { "1000full", SOC_PM_1000MB_FD }, 3506 { "1000half", SOC_PM_1000MB_HD }, 3507 { "100", SOC_PM_100MB }, 3508 { "100full", SOC_PM_100MB_FD }, 3509 { "100half", SOC_PM_100MB_HD }, 3510 { "10", SOC_PM_10MB }, 3511 { "10full", SOC_PM_10MB_FD }, 3512 { "10half", SOC_PM_10MB_HD }, 3513 { "pause", SOC_PM_PAUSE }, 3514 { "pause_tx", SOC_PM_PAUSE_TX }, 3515 { "pause_rx", SOC_PM_PAUSE_RX }, 3516 { "TBI", SOC_PM_TBI }, 3517 { "MII", SOC_PM_MII }, 3518 { "GMII", SOC_PM_GMII }, 3519 { "SGMII", SOC_PM_SGMII }, 3520 { "XGMII", SOC_PM_XGMII }, 3521 { "combo", SOC_PM_COMBO }, 3522 { NULL, 0 }, 3523 }; 3524 3525 int 3526 parse_port_mode(char *str, soc_port_mode_t *mode) 3527 { 3528 int i; 3529 char *s = str; 3530 3531 *mode = 0; 3532 3533 while (*s != 0) { 3534 for (i = 0; pm_map[i].str != NULL; i++) { 3535 int len = sal_strlen(pm_map[i].str); 3536 3537 if (sal_strncasecmp(s, pm_map[i].str, len) == 0 && 3538 (s[len] == 0 || s[len] == ',')) { 3539 3540 *mode |= pm_map[i].pm; 3541 3542 if (*(s += len) == ',') { 3543 s++; 3544 } 3545 3546 break; 3547 } 3548 } 3549 3550 if (pm_map[i].str == NULL) { 3551 return -1; 3552 } 3553 } 3554 3555 return 0; 3556 } 3557 3558 #define TYPE_SP_FD 1 3559 #define TYPE_SP_HD 2 3560 #define TYPE_PAUSE 3 3561 #define TYPE_INTF 4 3562 #define TYPE_FLAGS 5 3563 #define TYPE_DPLX 6 3564 #define TYPE_CHANNEL 7 3565 #define TYPE_FEC 8 3566 #define TYPE_IGNORE 0 3567 #define FULL_DUPLEX 1 3568 #define HALF_DUPLEX 2 3569 static struct { 3570 char *str; 3571 int type; 3572 soc_port_mode_t pm; 3573 } pa_map[] = { 3574 /* Multi-bit masks should come before their comprised 1-bit masks */ 3575 { "full", TYPE_DPLX, FULL_DUPLEX }, 3576 { "half", TYPE_DPLX, HALF_DUPLEX }, 3577 { "127G", TYPE_SP_FD, SOC_PA_SPEED_127GB }, 3578 { "120G", TYPE_SP_FD, SOC_PA_SPEED_120GB }, 3579 { "106G", TYPE_SP_FD, SOC_PA_SPEED_106GB }, 3580 { "100G", TYPE_SP_FD, SOC_PA_SPEED_100GB }, 3581 { "53G", TYPE_SP_FD, SOC_PA_SPEED_53GB }, 3582 { "50G", TYPE_SP_FD, SOC_PA_SPEED_50GB }, 3583 { "42G", TYPE_SP_FD, SOC_PA_SPEED_42GB }, 3584 { "40G", TYPE_SP_FD, SOC_PA_SPEED_40GB }, 3585 { "32G", TYPE_SP_FD, SOC_PA_SPEED_32GB }, 3586 { "30G", TYPE_SP_FD, SOC_PA_SPEED_30GB }, 3587 { "27G", TYPE_SP_FD, SOC_PA_SPEED_27GB }, 3588 { "25G", TYPE_SP_FD, SOC_PA_SPEED_25GB }, 3589 { "24G", TYPE_SP_FD, SOC_PA_SPEED_24GB }, 3590 { "21G", TYPE_SP_FD, SOC_PA_SPEED_21GB }, 3591 { "20G", TYPE_SP_FD, SOC_PA_SPEED_20GB }, 3592 { "16G", TYPE_SP_FD, SOC_PA_SPEED_16GB }, 3593 { "16Gfull", TYPE_SP_FD, SOC_PA_SPEED_16GB}, 3594 { "16Ghalf", TYPE_SP_HD, SOC_PA_SPEED_16GB}, 3595 { "15G", TYPE_SP_FD, SOC_PA_SPEED_15GB}, 3596 { "13G", TYPE_SP_FD, SOC_PA_SPEED_13GB}, 3597 { "13Gfull", TYPE_SP_FD, SOC_PA_SPEED_13GB}, 3598 { "13Ghalf", TYPE_SP_HD, SOC_PA_SPEED_13GB}, 3599 { "12G", TYPE_SP_FD, SOC_PA_SPEED_12GB}, 3600 { "12Gfull", TYPE_SP_FD, SOC_PA_SPEED_12GB}, 3601 { "12Ghalf", TYPE_SP_HD, SOC_PA_SPEED_12GB}, 3602 { "10G", TYPE_SP_FD, SOC_PA_SPEED_10GB}, 3603 { "10Gfull", TYPE_SP_FD, SOC_PA_SPEED_10GB}, 3604 { "10Ghalf", TYPE_SP_HD, SOC_PA_SPEED_10GB}, 3605 { "5000", TYPE_SP_FD, SOC_PA_SPEED_5000MB}, 3606 { "5G", TYPE_SP_FD, SOC_PA_SPEED_5000MB}, 3607 { "2500", TYPE_SP_FD, SOC_PA_SPEED_2500MB}, 3608 { "2500full", TYPE_SP_FD, SOC_PA_SPEED_2500MB}, 3609 { "2500half", TYPE_SP_HD, SOC_PA_SPEED_2500MB}, 3610 { "1000", TYPE_SP_FD, SOC_PA_SPEED_1000MB}, 3611 { "1000full", TYPE_SP_FD, SOC_PA_SPEED_1000MB}, 3612 { "1000half", TYPE_SP_HD, SOC_PA_SPEED_1000MB}, 3613 { "100", TYPE_SP_FD, SOC_PA_SPEED_100MB}, 3614 { "100full", TYPE_SP_FD, SOC_PA_SPEED_100MB}, 3615 { "100half", TYPE_SP_HD, SOC_PA_SPEED_100MB}, 3616 { "10", TYPE_SP_FD, SOC_PA_SPEED_10MB}, 3617 { "10full", TYPE_SP_FD, SOC_PA_SPEED_10MB}, 3618 { "10half", TYPE_SP_HD, SOC_PA_SPEED_10MB}, 3619 { "pause", TYPE_PAUSE, SOC_PA_PAUSE}, 3620 { "pause_tx", TYPE_PAUSE, SOC_PA_PAUSE_TX}, 3621 { "pause_rx", TYPE_PAUSE, SOC_PA_PAUSE_RX}, 3622 { "TBI", TYPE_INTF, SOC_PA_INTF_TBI}, 3623 { "MII", TYPE_INTF, SOC_PA_INTF_MII}, 3624 { "GMII", TYPE_INTF, SOC_PA_INTF_GMII}, 3625 { "SGMII", TYPE_INTF, SOC_PA_INTF_SGMII}, 3626 { "XGMII", TYPE_INTF, SOC_PA_INTF_XGMII}, 3627 { "combo", TYPE_FLAGS, SOC_PA_COMBO}, 3628 { "short", TYPE_CHANNEL, SOC_PA_CHANNEL_SHORT}, 3629 { "long", TYPE_CHANNEL, SOC_PA_CHANNEL_LONG}, 3630 { "fec_none", TYPE_FEC, SOC_PA_FEC_NONE}, 3631 { "cl74", TYPE_FEC, SOC_PA_FEC_CL74}, 3632 { "cl91", TYPE_FEC, SOC_PA_FEC_CL91}, 3633 { NULL, 0,0 }, 3634 }; 3635 3636 int 3637 parse_port_ability(char *str, soc_port_ability_t *abil) 3638 { 3639 int i; 3640 int dplx = 0; 3641 char *s = str; 3642 3643 sal_memset((char *)abil, 0, sizeof(soc_port_ability_t)); 3644 while (*s != 0) { 3645 for (i = 0; pa_map[i].str != NULL; i++) { 3646 int len = sal_strlen(pa_map[i].str); 3647 if (sal_strncasecmp(s, pa_map[i].str, len) == 0 && 3648 (s[len] == 0 || s[len] == ',')) { 3649 switch (pa_map[i].type) { 3650 case TYPE_DPLX: 3651 dplx = pa_map[i].pm; 3652 break; 3653 case TYPE_SP_FD: 3654 if (dplx == HALF_DUPLEX) { 3655 abil->speed_half_duplex |= pa_map[i].pm; 3656 } else { 3657 abil->speed_full_duplex |= pa_map[i].pm; 3658 } 3659 break; 3660 case TYPE_SP_HD: 3661 if (dplx == FULL_DUPLEX) { 3662 abil->speed_full_duplex |= pa_map[i].pm; 3663 } else { 3664 abil->speed_half_duplex |= pa_map[i].pm; 3665 } 3666 break; 3667 case TYPE_PAUSE: 3668 abil->pause |= pa_map[i].pm; 3669 break; 3670 case TYPE_INTF: 3671 abil->interface |= pa_map[i].pm; 3672 break; 3673 case TYPE_FLAGS: 3674 abil->flags |= pa_map[i].pm; 3675 break; 3676 case TYPE_CHANNEL: 3677 abil->channel |= pa_map[i].pm; 3678 break; 3679 case TYPE_FEC: 3680 abil->fec |= pa_map[i].pm; 3681 break; 3682 default: 3683 break; 3684 } 3685 3686 if (*(s += len) == ',') { 3687 s++; 3688 } 3689 3690 break; 3691 } 3692 } 3693 3694 if (pa_map[i].str == NULL) { 3695 return -1; 3696 } 3697 } 3698 3699 return 0; 3700 } 3701 3702 3703 /* 3704 * format_port_mode 3705 * 3706 * Formats a port mode into a comma-separated list of port mode 3707 * strings. This is the reverse of parse_port_mode. 3708 * 3709 * If abbrev is TRUE, then "1000full,1000half" will be abbreviated 3710 * as "1000". 3711 * 3712 * Output buffer must be at least 80 characters. 3713 */ 3714 3715 void 3716 format_port_mode(char *buf, int bufsize, soc_port_mode_t mode, int abbrev) 3717 { 3718 int i, first = 1; 3719 3720 assert(bufsize >= 80); 3721 3722 buf[0] = 0; 3723 3724 for (i = 0; mode != 0 && pm_map[i].str != NULL; i++) { 3725 if (!abbrev && _shr_popcount(pm_map[i].pm) != 1) { 3726 continue; 3727 } 3728 3729 if ((mode & pm_map[i].pm) == pm_map[i].pm) { 3730 if (first) { 3731 first = 0; 3732 } else { 3733 *buf++ = ','; 3734 } 3735 3736 /* Coverity[secure_coding] */ 3737 sal_strcpy(buf, pm_map[i].str); 3738 3739 while (*buf != 0) { 3740 buf++; 3741 } 3742 3743 mode &= ~pm_map[i].pm; 3744 } 3745 } 3746 } 3747 3748 3749 /* Port Ability structure */ 3750 3751 typedef struct { 3752 char *str; 3753 soc_port_mode_t pa; 3754 } _port_ability_map_t; 3755 3756 3757 /* Port Ability speed mapping */ 3758 _port_ability_map_t pa_speed_map[] = { 3759 /* Multi-bit masks should come before their comprised 1-bit masks */ 3760 { "10MB", SOC_PA_SPEED_10MB }, 3761 { "100MB", SOC_PA_SPEED_100MB }, 3762 { "1000MB", SOC_PA_SPEED_1000MB }, 3763 { "2500MB", SOC_PA_SPEED_2500MB }, 3764 { "3000MB", SOC_PA_SPEED_3000MB }, 3765 { "5000MB", SOC_PA_SPEED_5000MB }, 3766 { "6000MB", SOC_PA_SPEED_6000MB }, 3767 { "10GB", SOC_PA_SPEED_10GB}, 3768 { "11GB", SOC_PA_SPEED_11GB}, 3769 { "12GB", SOC_PA_SPEED_12GB}, 3770 { "12GP5", SOC_PA_SPEED_12P5GB}, 3771 { "13GB", SOC_PA_SPEED_13GB}, 3772 { "15GB", SOC_PA_SPEED_15GB}, 3773 { "16GB", SOC_PA_SPEED_16GB}, 3774 { "20GB", SOC_PA_SPEED_20GB}, 3775 3776 { "21GB", SOC_PA_SPEED_21GB}, 3777 { "24GB", SOC_PA_SPEED_24GB}, 3778 3779 { "25GB", SOC_PA_SPEED_25GB}, 3780 { "27GB", SOC_PA_SPEED_27GB}, 3781 3782 { "30GB", SOC_PA_SPEED_30GB}, 3783 { "32GB", SOC_PA_SPEED_32GB}, 3784 { "40GB", SOC_PA_SPEED_40GB}, 3785 3786 { "42GB", SOC_PA_SPEED_42GB}, 3787 { "50GB", SOC_PA_SPEED_50GB}, 3788 { "53GB", SOC_PA_SPEED_53GB}, 3789 { "100GB", SOC_PA_SPEED_100GB}, 3790 { "106GB", SOC_PA_SPEED_106GB}, 3791 { NULL, 0 }, 3792 }; 3793 3794 /* Port Ability interface mapping */ 3795 _port_ability_map_t pa_intf_map[] = { 3796 /* Multi-bit masks should come before their comprised 1-bit masks */ 3797 { "tbi", SOC_PA_INTF_TBI}, 3798 { "mii", SOC_PA_INTF_MII}, 3799 { "gmii", SOC_PA_INTF_GMII}, 3800 { "rgmii", SOC_PA_INTF_RGMII}, 3801 { "sgmii", SOC_PA_INTF_SGMII}, 3802 { "xgmii", SOC_PA_INTF_XGMII}, 3803 { NULL, 0 }, 3804 }; 3805 3806 /* Port Ability pause mapping */ 3807 _port_ability_map_t pa_pause_map[] = { 3808 /* Multi-bit masks should come before their comprised 1-bit masks */ 3809 { "pause_tx", SOC_PA_PAUSE_TX}, 3810 { "pause_rx", SOC_PA_PAUSE_RX}, 3811 { "pause_asymm", SOC_PA_PAUSE_ASYMM}, 3812 { NULL, 0 }, 3813 }; 3814 3815 _port_ability_map_t pa_medium_map[] = { 3816 /* Multi-bit masks should come before their comprised 1-bit masks */ 3817 { "copper", SOC_PA_MEDIUM_COPPER}, 3818 { "fiber", SOC_PA_MEDIUM_FIBER}, 3819 { NULL, 0 }, 3820 }; 3821 3822 _port_ability_map_t pa_lb_map[] = { 3823 /* Multi-bit masks should come before their comprised 1-bit masks */ 3824 { "none", SOC_PA_LB_NONE}, 3825 { "MAC", SOC_PA_LB_MAC}, 3826 { "PHY", SOC_PA_LB_PHY}, 3827 { "LINE", SOC_PA_LB_LINE}, 3828 { NULL, 0 }, 3829 }; 3830 3831 _port_ability_map_t pa_flags_map[] = { 3832 /* Multi-bit masks should come before their comprised 1-bit masks */ 3833 { "autoneg", SOC_PA_AUTONEG}, 3834 { "combo", SOC_PA_COMBO}, 3835 { NULL, 0 }, 3836 }; 3837 3838 3839 STATIC void 3840 format_port_ability(char *buf, int bufsize, soc_port_mode_t ability, 3841 _port_ability_map_t *pa_map) 3842 { 3843 int i, first = 1; 3844 3845 assert(bufsize >= 80); 3846 memset(buf, 0, bufsize); 3847 3848 buf[0] = 0; 3849 3850 for (i = 0; ability != 0 && pa_map[i].str != NULL; i++) { 3851 if ((ability & pa_map[i].pa) == pa_map[i].pa) { 3852 /* Account for final termination null byte + plus one extra ',' */ 3853 assert(strlen(buf) + strlen(pa_map[i].str) + 2 <= bufsize); 3854 3855 if (first) { 3856 first = 0; 3857 } else { 3858 *buf++ = ','; 3859 } 3860 3861 /* Coverity[secure_coding] */ 3862 sal_strcpy(buf, pa_map[i].str); 3863 3864 while (*buf != 0) { 3865 buf++; 3866 } 3867 3868 ability &= ~pa_map[i].pa; 3869 } 3870 } 3871 } 3872 3873 /* 3874 * format_port_speed_ability 3875 * 3876 * Formats a port speed ability into a comma-separated list of port speed 3877 * strings. 3878 * Output buffer must be at least 80 characters. 3879 */ 3880 3881 void 3882 format_port_speed_ability(char *buf, int bufsize, soc_port_mode_t ability) 3883 { 3884 format_port_ability(buf, bufsize, ability, pa_speed_map); 3885 } 3886 3887 /* 3888 * format_port_intf_ability 3889 * 3890 * Formats a port interface ability into a comma-separated list of port 3891 * interface strings. 3892 * Output buffer must be at least 80 characters. 3893 */ 3894 void 3895 format_port_intf_ability(char *buf, int bufsize, soc_port_mode_t ability) 3896 { 3897 format_port_ability(buf, bufsize, ability, pa_intf_map); 3898 } 3899 3900 /* 3901 * format_port_medium_ability 3902 * 3903 * Formats a port medium ability into a comma-separated list of port 3904 * medium strings. 3905 * Output buffer must be at least 80 characters. 3906 */ 3907 void 3908 format_port_medium_ability(char *buf, int bufsize, soc_port_mode_t ability) 3909 { 3910 format_port_ability(buf, bufsize, ability, pa_medium_map); 3911 } 3912 3913 /* 3914 * format_port_pause_ability 3915 * 3916 * Formats a port pause ability into a comma-separated list of port 3917 * pause strings. 3918 * Output buffer must be at least 80 characters. 3919 */ 3920 void 3921 format_port_pause_ability(char *buf, int bufsize, soc_port_mode_t ability) 3922 { 3923 format_port_ability(buf, bufsize, ability, pa_pause_map); 3924 } 3925 /* 3926 * format_port_lb_ability 3927 * 3928 * Formats a port loopback ability into a comma-separated list of port 3929 * loopback strings. 3930 * Output buffer must be at least 80 characters. 3931 */ 3932 void 3933 format_port_lb_ability(char *buf, int bufsize, soc_port_mode_t ability) 3934 { 3935 format_port_ability(buf, bufsize, ability, pa_lb_map); 3936 } 3937 /* 3938 * format_port_flags_ability 3939 * 3940 * Formats a port flags ability into a comma-separated list of port 3941 * flags strings. 3942 * Output buffer must be at least 80 characters. 3943 */ 3944 void 3945 format_port_flags_ability(char *buf, int bufsize, soc_port_mode_t ability) 3946 { 3947 format_port_ability(buf, bufsize, ability, pa_flags_map); 3948 } 3949 3950 /* 3951 * Function: 3952 * parse_field_qualifier 3953 * Purpose: 3954 * Turn text into a bcm_field_qualifier_t for the Field Processor code. 3955 * 3956 * Returns: 3957 * bcm_field_qualifier_t value that matches the input string 3958 * or 3959 * BCM_FIELD_ENTRY_INVALID if badly formed string 3960 */ 3961 bcm_field_qualify_t 3962 parse_field_qualifier(char *qual_str) 3963 { 3964 char cannonical_str[64]; 3965 char tos1[] = "TOS"; 3966 char tos2[] = "bcmFieldQualifyTos"; 3967 bcm_field_qualify_t qual; 3968 3969 assert(qual_str != NULL); 3970 if (sal_strlen(qual_str) >= 64 - 1) { 3971 return BCM_FIELD_ENTRY_INVALID; 3972 } 3973 3974 if (!sal_strcasecmp(tos1, qual_str) || 3975 !sal_strcasecmp(tos2, qual_str)) { 3976 return bcmFieldQualifyDSCP; 3977 } 3978 3979 for (qual = 0; qual < bcmFieldQualifyCount; qual++) { 3980 /* Test for whole name of the qualifier */ 3981 format_field_qualifier(cannonical_str, qual, 0); 3982 if (!sal_strcasecmp(cannonical_str, qual_str)) { 3983 break; 3984 } 3985 /* Test for the suffix only */ 3986 if(!sal_strcasecmp(cannonical_str + sal_strlen("bcmFieldQualify"), 3987 qual_str)) { 3988 break; 3989 } 3990 } 3991 3992 /* If not found, result is BCM_FIELD_ENTRY_INVALID */ 3993 return qual; 3994 } 3995 3996 /* 3997 * Function: 3998 * format_field_qualifier 3999 * Purpose: 4000 * Format a bcm_field_qualify_t variable for output 4001 * Parameters: 4002 * buf - character buffer where string is written 4003 * qualifier - Field Qualifier value 4004 * brief - if 0, use cannonical form, otherwise use short format 4005 * Returns: 4006 * pointer to buffer for printf-style usage 4007 */ 4008 char * 4009 format_field_qualifier(char *buf, bcm_field_qualify_t qualifier, int brief) 4010 { 4011 char *qualifier_text[bcmFieldQualifyCount] = BCM_FIELD_QUALIFY_STRINGS; 4012 4013 assert(buf != NULL); 4014 4015 if (0 <= qualifier && qualifier < bcmFieldQualifyCount) { 4016 if (brief) { 4017 sal_sprintf(buf, "%s", qualifier_text[qualifier]); 4018 } else { 4019 sal_sprintf(buf, "bcmFieldQualify%s", qualifier_text[qualifier]); 4020 } 4021 } else { 4022 sal_sprintf(buf, "invalid qualifier value=%#x", qualifier); 4023 } 4024 4025 return buf; 4026 } 4027 4028 /* 4029 * Function: 4030 * parse_field_qset 4031 * Purpose: 4032 * Turn CLI input into a qset for the Field Processor code. 4033 */ 4034 int 4035 parse_field_qset(char *str, bcm_field_qset_t *qset) { 4036 char *buf; 4037 char *str_copy; 4038 int input_len; 4039 bcm_field_qualify_t qual; 4040 int retval = 0; 4041 char delimiters[] = " \t,\n\0{}"; 4042 int nval = _SHR_BITDCLSIZE(BCM_FIELD_QUALIFY_MAX); 4043 int idx; 4044 char eight[11], *src_str, *temp_str; 4045 char *tokstr; 4046 4047 assert(str != NULL); 4048 4049 BCM_FIELD_QSET_INIT(*qset); 4050 4051 str_copy = (char *) sal_alloc((BCM_FIELD_QSET_WIDTH_MAX * sizeof(char)), 4052 "qset string"); 4053 if (NULL == str_copy) { 4054 return (BCM_E_MEMORY); 4055 } 4056 4057 /* Parse bitmap input in the form of an Integer. */ 4058 if (isint(str)) { 4059 /* Skip to the last hex digit in the string */ 4060 for (src_str = str + 1; isxdigit((unsigned) src_str[1]); src_str++) { 4061 ; 4062 } 4063 4064 /* Parse backward in groups of 8 digits */ 4065 idx = 0; 4066 do { 4067 /* Copy 8 digits backward to form a string "0xdddddddd\0" */ 4068 temp_str = eight + 11; 4069 *--temp_str = 0; 4070 while (temp_str > eight + 2 && *src_str != 'x') { 4071 *--temp_str = *src_str--; 4072 } 4073 *--temp_str = 'x'; 4074 *--temp_str = '0'; 4075 4076 qset->w[idx++] = parse_integer(temp_str); 4077 } while (*src_str != 'x' && idx < nval); 4078 sal_free(str_copy); 4079 return 1; 4080 } 4081 4082 /* Parse list of qualifiers. */ 4083 input_len = sal_strlen(str); 4084 if (input_len >= BCM_FIELD_QSET_WIDTH_MAX) { 4085 sal_free(str_copy); 4086 return 0; 4087 } 4088 sal_strncpy(str_copy, str, input_len + 1); 4089 4090 buf = sal_strtok_r(str_copy, delimiters, &tokstr); 4091 4092 do { 4093 qual = parse_field_qualifier(buf); 4094 if (qual != BCM_FIELD_ENTRY_INVALID) { 4095 BCM_FIELD_QSET_ADD(*qset, qual); 4096 retval++; 4097 } 4098 buf = sal_strtok_r(NULL, delimiters, &tokstr); 4099 } while (buf); 4100 4101 sal_free(str_copy); 4102 return retval; 4103 } 4104 4105 /* 4106 * Function: 4107 * format_field_qset 4108 * Purpose: 4109 * Format a bcm_field_qset_t for output 4110 * Parameters: 4111 * buf - character buffer where string is written 4112 * qset - Field Qset value 4113 * Returns: 4114 * pointer to buffer (for printf-style usage) 4115 */ 4116 char * 4117 format_field_qset(char *buf, bcm_field_qset_t qset, char *separator) 4118 { 4119 bcm_field_qualify_t qual; 4120 char buf_local[30]; 4121 int first_print = 1; 4122 4123 assert(buf != NULL); 4124 4125 buf[0] = '{'; 4126 buf[1] = '\0'; 4127 4128 /* Iterate over Qset, looking for bits that are set. */ 4129 for (qual = 0; qual < bcmFieldQualifyCount; qual++) { 4130 if(BCM_FIELD_QSET_TEST(qset, qual)) { 4131 if (first_print == 1) { 4132 first_print = 0; 4133 } else { 4134 sal_strncat(buf, separator, sal_strlen(separator)); 4135 } 4136 format_field_qualifier(buf_local, qual, 1); 4137 sal_strncat(buf, buf_local, sal_strlen(buf_local)); 4138 } 4139 } 4140 sal_strncat(buf, "}", sal_strlen("}")); 4141 4142 return buf; 4143 } 4144 4145 /* 4146 * Function: 4147 * parse_field_group_mode 4148 * Purpose: 4149 * Turn text into a bcm_field_group_mode_t for the Field Processor code. 4150 * 4151 * Returns: 4152 * bcm_field_group_mode_t value that matches the input string 4153 * or 4154 * bcmFieldGroupModeCount if badly formed string 4155 */ 4156 bcm_field_group_mode_t 4157 parse_field_group_mode(char *act_str) 4158 { 4159 char cannonical_str[64]; 4160 bcm_field_group_mode_t mode; 4161 4162 assert(act_str != NULL); 4163 if (sal_strlen(act_str) >= 64 - 1) { 4164 return bcmFieldGroupModeCount; 4165 } 4166 4167 for (mode = 0; mode < bcmFieldGroupModeCount; mode++) { 4168 /* Test for whole name of the mode */ 4169 format_field_group_mode(cannonical_str, mode, 0); 4170 if (!sal_strcasecmp(cannonical_str, act_str)) { 4171 break; 4172 } 4173 /* Test for the suffix only */ 4174 if(!sal_strcasecmp(cannonical_str + sal_strlen("bcmFieldGroupMode"), 4175 act_str)) { 4176 break; 4177 } 4178 } 4179 4180 /* If not found, result is bcmFieldGroupModeCount */ 4181 return mode; 4182 } 4183 4184 /* 4185 * Function: 4186 * format_field_group_mode 4187 * Purpose: 4188 * Format a bcm_field_group_mode_t variable for output 4189 * Parameters: 4190 * buf - character buffer where string is written 4191 * mode - Field group_mode value 4192 * brief - if 0, use cannonical form, otherwise use short format 4193 * Returns: 4194 * pointer to buffer for printf-style usage 4195 */ 4196 char * 4197 format_field_group_mode(char *buf, bcm_field_group_mode_t mode, int brief) 4198 { 4199 char *mode_text[bcmFieldGroupModeCount] = BCM_FIELD_GROUP_MODE_STRINGS; 4200 4201 assert(buf != NULL); 4202 4203 if (0 <= mode && mode < bcmFieldGroupModeCount) { 4204 if (brief) { 4205 sal_sprintf(buf, "%s", mode_text[mode]); 4206 } else { 4207 sal_sprintf(buf, "bcmFieldGroupMode%s", mode_text[mode]); 4208 } 4209 } else { 4210 sal_sprintf(buf, "invalid group mode value=%#x", mode); 4211 } 4212 4213 return buf; 4214 } 4215 4216 /* 4217 * Function: 4218 * parse_field_action 4219 * Purpose: 4220 * Turn text into a bcm_field_action_t for the Field Processor code. 4221 * 4222 * Returns: 4223 * bcm_field_action_t value that matches the input string 4224 * or 4225 * BCM_FIELD_ENTRY_INVALID if badly formed string 4226 */ 4227 bcm_field_action_t 4228 parse_field_action(char *act_str) 4229 { 4230 char cannonical_str[64]; 4231 bcm_field_action_t action; 4232 4233 assert(act_str != NULL); 4234 if (sal_strlen(act_str) >= 64 - 1) { 4235 return BCM_FIELD_ENTRY_INVALID; 4236 } 4237 4238 for (action = 0; action < bcmFieldActionCount; action++) { 4239 /* Test for whole name of the action */ 4240 format_field_action(cannonical_str, action, 0); 4241 if (!sal_strcasecmp(cannonical_str, act_str)) { 4242 break; 4243 } 4244 /* Test for the suffix only */ 4245 if(!sal_strcasecmp(cannonical_str + sal_strlen("bcmFieldAction"), 4246 act_str)) { 4247 break; 4248 } 4249 } 4250 4251 /* If not found, result is BCM_FIELD_ENTRY_INVALID */ 4252 return action; 4253 } 4254 4255 /* 4256 * Function: 4257 * format_field_action 4258 * Purpose: 4259 * Format a bcm_field_action_t variable for output 4260 * Parameters: 4261 * buf - character buffer where string is written 4262 * action - Field action value 4263 * brief - if 0, use cannonical form, otherwise use short format 4264 * Returns: 4265 * pointer to buffer for printf-style usage 4266 */ 4267 static const char *action_text[bcmFieldActionCount] = BCM_FIELD_ACTION_STRINGS; 4268 char * 4269 format_field_action(char *buf, bcm_field_action_t action, int brief) 4270 { 4271 assert(buf != NULL); 4272 4273 if (0 <= action && action < bcmFieldActionCount) { 4274 if (brief) { 4275 sal_sprintf(buf, "%s", action_text[action]); 4276 } else { 4277 sal_sprintf(buf, "bcmFieldAction%s", action_text[action]); 4278 } 4279 } else { 4280 sal_sprintf(buf, "invalid action value=%#x", action); 4281 } 4282 4283 return buf; 4284 } 4285 4286 /* 4287 * Function: 4288 * parse_field_aset 4289 * Purpose: 4290 * Turn CLI input into a aset for the Field Processor code. 4291 */ 4292 int 4293 parse_field_aset(char *str, bcm_field_aset_t *aset, uint8 add) { 4294 char *buf; 4295 char *str_copy; 4296 int input_len; 4297 bcm_field_action_t action; 4298 int retval = 0; 4299 char delimiters[] = " \t,\n\0{}"; 4300 char *tokstr; 4301 4302 assert(str != NULL); 4303 4304 str_copy = (char *) sal_alloc((BCM_FIELD_ASET_WIDTH_MAX * sizeof(char)), 4305 "aset string"); 4306 if (NULL == str_copy) { 4307 return (BCM_E_MEMORY); 4308 } 4309 4310 /* Parse list of actions. */ 4311 input_len = sal_strlen(str); 4312 if (input_len >= BCM_FIELD_ASET_WIDTH_MAX) { 4313 sal_free(str_copy); 4314 return 0; 4315 } 4316 sal_strncpy(str_copy, str, input_len + 1); 4317 4318 buf = sal_strtok_r(str_copy, delimiters, &tokstr); 4319 4320 do { 4321 action = parse_field_action(buf); 4322 if (action != BCM_FIELD_ENTRY_INVALID) { 4323 if (add) { 4324 BCM_FIELD_ASET_ADD(*aset, action); 4325 } else { 4326 BCM_FIELD_ASET_REMOVE(*aset, action); 4327 } 4328 retval++; 4329 } 4330 buf = sal_strtok_r(NULL, delimiters, &tokstr); 4331 } while (buf); 4332 4333 sal_free(str_copy); 4334 return retval; 4335 } 4336 4337 /* 4338 * Function: 4339 * format_field_aset 4340 * Purpose: 4341 * Format a bcm_field_aset_t for output 4342 * Parameters: 4343 * buf - character buffer where string is written 4344 * aset - Field Aset value 4345 * Returns: 4346 * pointer to buffer (for printf-style usage) 4347 */ 4348 char * 4349 format_field_aset(char *buf, bcm_field_aset_t aset, char *separator) 4350 { 4351 bcm_field_action_t action; 4352 char buf_local[30]; 4353 int first_print = 1; 4354 4355 assert(buf != NULL); 4356 4357 buf[0] = '{'; 4358 buf[1] = '\0'; 4359 4360 /* Iterate over Aset, looking for bits that are set. */ 4361 for (action = 0; action < bcmFieldActionCount; action++) { 4362 if(BCM_FIELD_ASET_TEST(aset, action)) { 4363 if (first_print == 1) { 4364 first_print = 0; 4365 } else { 4366 sal_strncat(buf, separator, sal_strlen(separator)); 4367 } 4368 format_field_action(buf_local, action, 1); 4369 sal_strncat(buf, buf_local, sal_strlen(buf_local)); 4370 } 4371 } 4372 sal_strncat(buf, "}", sal_strlen("}")); 4373 4374 return buf; 4375 } 4376 4377 4378 #define FP_OLP_HDR_TYPE_STR_SZ 50 4379 /* 4380 * Function: 4381 * parse_field_olp_hdr_type 4382 * Purpose: 4383 * Turn CLI input into a bcm_field_oam_type_t for the Field Processor code. 4384 * 4385 * Returns: 4386 * bcm_field_olp_header_type_t value that matches the input string 4387 * or 4388 * bcmFieldOlpHeaderTypeCount if badly formed string 4389 */ 4390 bcm_field_olp_header_type_t parse_field_olp_hdr_type(char *str) 4391 { 4392 bcm_field_olp_header_type_t olp_hdr_type; 4393 char *olp_hdr_type_text[bcmFieldOlpHeaderTypeCount] = BCM_FIELD_OLP_HEADER_TYPE_STRINGS; 4394 char tbl_str[FP_OLP_HDR_TYPE_STR_SZ]; 4395 char lng_str[FP_OLP_HDR_TYPE_STR_SZ]; 4396 4397 if (str == NULL) { 4398 return bcmFieldOlpHeaderTypeCount; 4399 } 4400 4401 if (isint(str)) { 4402 return parse_integer(str); 4403 } 4404 4405 for (olp_hdr_type = 0; olp_hdr_type < bcmFieldOlpHeaderTypeCount; olp_hdr_type++) { 4406 sal_memset(tbl_str, 0, sizeof(char) * FP_OLP_HDR_TYPE_STR_SZ); 4407 sal_memset(lng_str, 0, sizeof(char) * FP_OLP_HDR_TYPE_STR_SZ); 4408 /* Test for the suffix only */ 4409 sal_strncpy(tbl_str, olp_hdr_type_text[olp_hdr_type], FP_OLP_HDR_TYPE_STR_SZ - 1); 4410 if (!sal_strcasecmp(tbl_str, str)) { 4411 break; 4412 } 4413 /* Test for whole name of the action */ 4414 sal_strncpy(lng_str, "bcmFieldOlpHeaderType", sizeof (lng_str)); 4415 sal_strncat(lng_str, tbl_str, 4416 FP_OLP_HDR_TYPE_STR_SZ - 1 - sal_strlen("bcmFieldOlpHeaderType")); 4417 if (!sal_strcasecmp(lng_str, str)) { 4418 break; 4419 } 4420 } 4421 return olp_hdr_type; 4422 } 4423 4424 #define FP_OAMTYPE_STR_SZ 50 4425 /* 4426 * Function: 4427 * parse_field_oam_type 4428 * Purpose: 4429 * Turn CLI input into a bcm_field_oam_type_t for the Field Processor code. 4430 * 4431 * Returns: 4432 * bcm_field_oam_type_t value that matches the input string 4433 * or 4434 * bcmFieldOamTypeCount if badly formed string 4435 */ 4436 bcm_field_oam_type_t 4437 parse_field_oam_type(char *str) 4438 { 4439 bcm_field_oam_type_t oamtype; 4440 char *oamtype_text[bcmFieldOamTypeCount] = BCM_FIELD_OAM_TYPE; 4441 char tbl_str[FP_OAMTYPE_STR_SZ]; 4442 char lng_str[FP_OAMTYPE_STR_SZ]; 4443 4444 if (str == NULL) { 4445 return bcmFieldOamTypeCount; 4446 } 4447 4448 if (isint(str)) { 4449 return parse_integer(str); 4450 } 4451 4452 for (oamtype = 0; oamtype < bcmFieldOamTypeCount; oamtype++) { 4453 sal_memset(tbl_str, 0, sizeof(char) * FP_OAMTYPE_STR_SZ); 4454 sal_memset(lng_str, 0, sizeof(char) * FP_OAMTYPE_STR_SZ); 4455 /* Test for the suffix only */ 4456 sal_strncpy(tbl_str, oamtype_text[oamtype], FP_OAMTYPE_STR_SZ - 1); 4457 if (!sal_strcasecmp(tbl_str, str)) { 4458 break; 4459 } 4460 /* Test for whole name of the action */ 4461 sal_strncpy(lng_str, "bcmFieldOamType", sizeof (lng_str)); 4462 sal_strncat(lng_str, tbl_str, 4463 FP_OAMTYPE_STR_SZ - 1 - sal_strlen("bcmFieldOamType")); 4464 if (!sal_strcasecmp(lng_str, str)) { 4465 break; 4466 } 4467 } 4468 return oamtype; 4469 } 4470 4471 4472 #define FP_DECAP_STR_SZ 50 4473 /* 4474 * Function: 4475 * parse_field_decap 4476 * Purpose: 4477 * Turn CLI input into a bcm_field_decap_t for the Field Processor code. 4478 * 4479 * Returns: 4480 * bcm_field_decap_t value that matches the input string 4481 * or 4482 * bcmFieldDecapCount if badly formed string 4483 */ 4484 bcm_field_decap_t 4485 parse_field_decap(char *str) 4486 { 4487 bcm_field_decap_t decap; 4488 char *decap_text[bcmFieldDecapCount] = BCM_FIELD_DECAP_STRINGS; 4489 char tbl_str[FP_DECAP_STR_SZ]; 4490 char lng_str[FP_DECAP_STR_SZ]; 4491 4492 if (str == NULL) { 4493 return bcmFieldDecapCount; 4494 } 4495 4496 if (isint(str)) { 4497 return parse_integer(str); 4498 } 4499 4500 for (decap = 0; decap < bcmFieldDecapCount; decap++) { 4501 sal_memset(tbl_str, 0, sizeof(char) * FP_DECAP_STR_SZ); 4502 sal_memset(lng_str, 0, sizeof(char) * FP_DECAP_STR_SZ); 4503 /* Test for the suffix only */ 4504 sal_strncpy(tbl_str, decap_text[decap], FP_DECAP_STR_SZ - 1); 4505 if (!sal_strcasecmp(tbl_str, str)) { 4506 break; 4507 } 4508 /* Test for whole name of the action */ 4509 /* Coverity[secure_coding] */ 4510 sal_strcpy(lng_str, "bcmFieldDecap"); 4511 sal_strncat(lng_str, tbl_str, 4512 FP_DECAP_STR_SZ - 1 - sal_strlen("bcmFieldDecap")); 4513 if (!sal_strcasecmp(lng_str, str)) { 4514 break; 4515 } 4516 } 4517 return decap; 4518 } 4519 4520 4521 #define FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ 50 4522 /* 4523 * Function: 4524 * parse_field_MplsOamCtrlPktType 4525 * Purpose: 4526 * Turn CLI input into a bcm_field_MplsOam_Control_pktType_t 4527 for the Field Processor code. 4528 * 4529 * Returns: 4530 * bcm_field_MplsOam_Control_pktType_t value that matches the input string 4531 * or 4532 * bcmFieldMplsOamControlPktTypeCount if badly formed string 4533 */ 4534 bcm_field_MplsOam_Control_pktType_t 4535 parse_field_MplsOamCtrlPktType (char *str) 4536 { 4537 bcm_field_MplsOam_Control_pktType_t pktType; 4538 char *MplsOamCtrlPktType[bcmFieldMplsOamControlPktTypeCount] 4539 = BCM_FIELD_MPLS_OAM_CONTROL_PKT_TYPE; 4540 char tbl_str[FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ]; 4541 char lng_str[FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ]; 4542 4543 if (str == NULL) { 4544 return bcmFieldMplsOamControlPktTypeCount; 4545 } 4546 4547 if (isint(str)) { 4548 return parse_integer(str); 4549 } 4550 4551 for (pktType = 0; pktType < bcmFieldMplsOamControlPktTypeCount; pktType++) { 4552 sal_memset(tbl_str, 0, sizeof(char) * FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ); 4553 sal_memset(lng_str, 0, sizeof(char) * FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ); 4554 /* Test for the suffix only */ 4555 sal_strncpy(tbl_str, MplsOamCtrlPktType[pktType], 4556 FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ - 1); 4557 if (!sal_strcasecmp(tbl_str, str)) { 4558 break; 4559 } 4560 /* Test for whole name of the action */ 4561 sal_strncpy(lng_str, "bcmFieldMplsOamControlPktType", sizeof (lng_str)); 4562 sal_strncat(lng_str, tbl_str, 4563 FP_MPLS_OAM_CTRL_PKT_TYPE_STR_SZ - 1 - 4564 sal_strlen("bcmFieldMplsOamControlPktType")); 4565 if (!sal_strcasecmp(lng_str, str)) { 4566 break; 4567 } 4568 } 4569 return pktType; 4570 } 4571 4572 #define FP_ROE_FRAME_TYPE_STR_SZ 40 4573 /* 4574 * Function: 4575 * parse_field_roe_frame_type 4576 * Purpose: 4577 * Turn CLI input into a bcm_field_roe_frame_type_t for the Field Processor code. 4578 * 4579 * Returns: 4580 * bcm_field_roe_frame_type_t value that matches the input string 4581 * or 4582 * bcmFieldRoeFrameTypeCount if badly formed string 4583 */ 4584 bcm_field_roe_frame_type_t parse_field_roe_frame_type(char *str) 4585 { 4586 bcm_field_roe_frame_type_t roe_frame_type; 4587 char *roe_frame_type_text[bcmFieldRoeFrameTypeCount] = BCM_FIELD_ROE_FRAME_TYPE_STRINGS; 4588 char tbl_str[FP_ROE_FRAME_TYPE_STR_SZ]; 4589 char lng_str[FP_ROE_FRAME_TYPE_STR_SZ]; 4590 4591 if (str == NULL) { 4592 return bcmFieldRoeFrameTypeCount; 4593 } 4594 4595 if (isint(str)) { 4596 return parse_integer(str); 4597 } 4598 4599 for (roe_frame_type = 0; roe_frame_type < bcmFieldRoeFrameTypeCount; roe_frame_type++) { 4600 sal_memset(tbl_str, 0, sizeof(char) * FP_ROE_FRAME_TYPE_STR_SZ); 4601 sal_memset(lng_str, 0, sizeof(char) * FP_ROE_FRAME_TYPE_STR_SZ); 4602 /* Test for the suffix only */ 4603 sal_strncpy(tbl_str, roe_frame_type_text[roe_frame_type], 4604 FP_ROE_FRAME_TYPE_STR_SZ - 1); 4605 if (!sal_strcasecmp(tbl_str, str)) { 4606 break; 4607 } 4608 /* Test for whole name of the action */ 4609 sal_strncpy(lng_str, "bcmFieldRoeFrameType", sizeof (lng_str)); 4610 sal_strncat(lng_str, tbl_str, 4611 FP_ROE_FRAME_TYPE_STR_SZ - 1 - \ 4612 sal_strlen("bcmFieldRoeFrameType")); 4613 if (!sal_strcasecmp(lng_str, str)) { 4614 break; 4615 } 4616 } 4617 return roe_frame_type; 4618 } 4619 4620 /* 4621 * Function: 4622 * format_field_decap 4623 * Purpose: 4624 * Format a bcm_field_decap_t variable for output. 4625 * Parameters: 4626 * buf - character buffer where string is written 4627 * decap - Field decap value 4628 * Returns: 4629 * pointer to buffer for printf-style usage 4630 */ 4631 char * 4632 format_field_decap(char *buf, bcm_field_decap_t decap) 4633 { 4634 char *decap_text[bcmFieldDecapCount] = BCM_FIELD_DECAP_STRINGS; 4635 4636 assert(buf != NULL); 4637 4638 if (0 <= decap && decap < bcmFieldDecapCount) { 4639 sal_sprintf(buf, "bcmFieldDecap%s", decap_text[decap]); 4640 } else { 4641 sal_sprintf(buf, "invalid decap value=%#x", decap); 4642 } 4643 4644 return buf; 4645 } 4646 4647 /* 4648 * Routine to load a big-endian value from a packet with no alignment 4649 * restrictions. Size is the length of the value in bytes (0-4). 4650 */ 4651 4652 uint32 4653 packet_load(uint8 *addr, int size) 4654 { 4655 uint32 val = 0; 4656 4657 switch (size) { 4658 default: 4659 val |= (uint32) *addr++ << 24; 4660 /* Fall through */ 4661 case 3: 4662 val |= (uint32) *addr++ << 16; 4663 case 2: 4664 val |= (uint32) *addr++ << 8; 4665 case 1: 4666 val |= (uint32) *addr++ << 0; 4667 case 0: 4668 ; 4669 } 4670 4671 return val; 4672 } 4673 /* 4674 * Random Pattern Packet Filler 4675 * 4676 * Fills a buffer of bytes with a random pattern. 4677 * There are no alignment restrictions on the buffer and length. 4678 */ 4679 4680 void 4681 packet_random_store(uint8 *buf, int size) 4682 { 4683 int align_off = ((sal_vaddr_t) buf & 3); 4684 int pat_off = 24; 4685 uint32 pat; 4686 4687 pat = sal_rand(); 4688 4689 if (align_off) { 4690 /* Store bytes from pat (MSB ==> LSB) until buf is aligned. */ 4691 4692 for (; ((sal_vaddr_t) buf & 3) != 0 && size > 0; pat_off -= 8, size--) { 4693 *buf++ = pat >> pat_off; 4694 } 4695 } 4696 4697 /* Store whole words. */ 4698 4699 for (; size > 3; buf += 4, size -= 4) { 4700 pat = sal_rand(); 4701 *(uint32 *) buf = bcm_htonl(pat); 4702 } 4703 /* Store up to 3 residual bytes. */ 4704 4705 pat = sal_rand(); 4706 for (; size > 0; size--, pat_off -= 8) { 4707 *buf++ = pat >> pat_off; 4708 if (pat_off == 0) { 4709 pat = sal_rand(); 4710 pat_off = 24; 4711 } 4712 } 4713 } 4714 4715 /* 4716 * Optimized Packet Filler 4717 * 4718 * Fills a buffer of bytes with a 32-bit incrementing pattern in 4719 * big-endian order. There are no alignment restrictions on the buffer 4720 * and length. 4721 * 4722 * The increment value is added to the pattern each time it is stored 4723 * (every 4 bytes). The final value of the pattern is returned (after 4724 * all the incrementing). 4725 */ 4726 4727 uint32 4728 packet_store(uint8 *buf, int size, uint32 pat, uint32 inc) 4729 { 4730 int align_off = ((sal_vaddr_t) buf & 3); 4731 int pat_off = 24; 4732 4733 if (align_off) { 4734 int align_shr = align_off * 8; 4735 int align_shl = 32 - align_shr; 4736 4737 /* Store bytes from pat (MSB ==> LSB) until buf is aligned. */ 4738 4739 for (; ((sal_vaddr_t)buf & 3) != 0 && size > 0; pat_off -= 8, size--) { 4740 *buf++ = pat >> pat_off; 4741 } 4742 4743 /* Store whole words, incrementing pat in the middle of words. */ 4744 4745 for (; size > 3; buf += 4, size -= 4) { 4746 uint32 x = pat << align_shl; 4747 pat += inc; 4748 x |= pat >> align_shr; 4749 *(uint32 *)buf = bcm_htonl(x); 4750 } 4751 } else { 4752 for (; size > 3; buf += 4, size -= 4, pat += inc) { 4753 *(uint32 *)buf = bcm_htonl(pat); 4754 } 4755 } 4756 4757 /* Store up to 3 residual bytes. */ 4758 4759 for (; size > 0; size--, pat_off -= 8) { 4760 *buf++ = pat >> pat_off; 4761 if (pat_off == 0) { 4762 pat += inc; /* Add increment and wrap around to MSB */ 4763 pat_off = 32; 4764 } 4765 } 4766 4767 return pat; 4768 } 4769 4770 /* 4771 * Optimized packet compare 4772 * 4773 * Returns byte offset of first mismatch, -1 for compare equal. 4774 */ 4775 4776 int 4777 packet_compare(uint8 *p1, uint8 *p2, int size) 4778 { 4779 int i = 0; 4780 4781 if ((((sal_vaddr_t) p1 ^ (sal_vaddr_t) p2) & 3) != 0) { 4782 goto residual; 4783 } 4784 4785 for (; ((sal_vaddr_t) p1 & 3) != 0 && i < size; i++) { 4786 if (p1[i] != p2[i]) { 4787 return i; 4788 } 4789 } 4790 4791 for (; i < size - 3; i += 4) { 4792 if (*(uint32 *) &p1[i] != *(uint32 *) &p2[i]) { 4793 break; 4794 } 4795 } 4796 4797 residual: 4798 4799 for (; i < size; i++) { 4800 if (p1[i] != p2[i]) { 4801 return i; 4802 } 4803 } 4804 4805 return -1; 4806 } 4807 4808 static struct { 4809 char *str; 4810 soc_phy_control_longreach_ability_t pa; 4811 } lr_pa_map[] = { 4812 /* Multi-bit masks should come before their comprised 1-bit masks */ 4813 { "10x1", SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_1PAIR }, 4814 { "10x2", SOC_PHY_CONTROL_LONGREACH_ABILITY_10M_2PAIR }, 4815 { "20x1", SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_1PAIR }, 4816 { "20x2", SOC_PHY_CONTROL_LONGREACH_ABILITY_20M_2PAIR }, 4817 { "25x1", SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_1PAIR }, 4818 { "25x2", SOC_PHY_CONTROL_LONGREACH_ABILITY_25M_2PAIR }, 4819 { "33x1", SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_1PAIR }, 4820 { "33x2", SOC_PHY_CONTROL_LONGREACH_ABILITY_33M_2PAIR }, 4821 { "50x1", SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_1PAIR }, 4822 { "50x2", SOC_PHY_CONTROL_LONGREACH_ABILITY_50M_2PAIR }, 4823 { "100x1", SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_1PAIR }, 4824 { "100x2", SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_2PAIR }, 4825 { "100x4", SOC_PHY_CONTROL_LONGREACH_ABILITY_100M_4PAIR }, 4826 { "pause_rx", SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_RX }, 4827 { "pause_tx", SOC_PHY_CONTROL_LONGREACH_ABILITY_PAUSE_TX }, 4828 { NULL, 0 }, 4829 }; 4830 4831 int 4832 parse_phy_control_longreach_ability(char *str, soc_phy_control_longreach_ability_t *ability) 4833 { 4834 int i; 4835 char *s = str; 4836 4837 *ability = 0; 4838 4839 while (*s != 0) { 4840 for (i = 0; lr_pa_map[i].str != NULL; i++) { 4841 int len = sal_strlen(lr_pa_map[i].str); 4842 4843 if (sal_strncasecmp(s, lr_pa_map[i].str, len) == 0 && 4844 (s[len] == 0 || s[len] == ',')) { 4845 4846 *ability |= lr_pa_map[i].pa; 4847 4848 if (*(s += len) == ',') { 4849 s++; 4850 } 4851 4852 break; 4853 } 4854 } 4855 4856 if (lr_pa_map[i].str == NULL) { 4857 return -1; 4858 } 4859 } 4860 4861 return 0; 4862 } 4863 4864 void 4865 format_phy_control_longreach_ability(char *buf, int bufsize, soc_phy_control_longreach_ability_t ability) 4866 { 4867 int i, first = 1; 4868 4869 assert(bufsize >= 80); 4870 4871 buf[0] = 0; 4872 4873 for (i = 0; ability != 0 && lr_pa_map[i].str != NULL; i++) { 4874 if ((ability & lr_pa_map[i].pa) == lr_pa_map[i].pa) { 4875 if (first) { 4876 first = 0; 4877 } else { 4878 *buf++ = ','; 4879 } 4880 4881 sal_strncpy(buf, lr_pa_map[i].str, bufsize); 4882 4883 while (*buf != 0) { 4884 buf++; 4885 } 4886 4887 ability &= ~lr_pa_map[i].pa; 4888 } 4889 } 4890 4891 } 4892 4893 pbmp_t 4894 soc_property_get_bcm_pbmp(int unit, const char *name, int defneg) 4895 { 4896 pbmp_t pbmp = soc_property_get_pbmp(unit, name, defneg); 4897 4898 BCM_API_XLATE_PORT_PBMP_P2A(unit, &pbmp); 4899 4900 return pbmp; 4901 } 4902 4903 uint32 4904 soc_property_bcm_port_get(int unit, bcm_port_t aport, 4905 const char *name, uint32 defl) 4906 { 4907 soc_port_t port = aport; 4908 4909 BCM_API_XLATE_PORT_A2P(unit, &port); 4910 4911 return soc_property_port_get(unit, port, name, defl); 4912 } 4913 4914 4915 int soc_phy_fw_acquire_default(const char *file_name, uint8 **fw, int *fw_len) 4916 { 4917 #ifndef NO_FILEIO 4918 FILE *fp; 4919 uint8 *buffer; 4920 int buffer_size, offset; 4921 4922 if ((fp = sal_fopen((char *)file_name, "rb")) == NULL) { 4923 return SOC_E_FAIL; 4924 } 4925 4926 buffer_size = sal_fsize(fp); 4927 4928 /* some implementations of sal_fsize cannot move the file pointer back to the begining */ 4929 sal_fclose(fp); 4930 if ((fp = sal_fopen((char *)file_name, "rb")) == NULL) { 4931 return SOC_E_FAIL; 4932 } 4933 4934 if (buffer_size == -1) { 4935 /* cannot determine the f/w file size */ 4936 buffer_size = MAX_FW_BUF_LEN; 4937 } 4938 4939 buffer = sal_alloc(buffer_size,"firmware_buffer"); 4940 if (buffer == NULL) { 4941 sal_fclose(fp); 4942 cli_out("ERROR: Can't allocate enough buffer : 0x%x\n", 4943 buffer_size); 4944 return SOC_E_FAIL; 4945 } 4946 4947 /* coverity[tainted_data_argument] */ 4948 offset = sal_fread(buffer, 1, buffer_size, fp); 4949 if (sal_ferror(fp)) { 4950 cli_out("ERROR: Can't read from file : %s\n", file_name); 4951 /* coverity[tainted_data] */ 4952 sal_free(buffer); 4953 sal_fclose(fp); 4954 return SOC_E_FAIL; 4955 } 4956 4957 sal_fclose(fp); 4958 4959 *fw = buffer; 4960 *fw_len = offset; 4961 4962 return SOC_E_NONE; 4963 #else 4964 return SOC_E_FAIL; 4965 #endif 4966 4967 } 4968 4969 int soc_phy_fw_release_default(const char *dev_name, uint8 *fw, int fw_len) 4970 { 4971 if (fw) { 4972 sal_free(fw); 4973 } 4974 return SOC_E_NONE; 4975 } 4976 4977 4978 #if defined(BROADCOM_DEBUG) 4979 4980 #define CHK_FLAG(pkt, flag, offset, line, desc) \ 4981 do { \ 4982 if ((pkt)->flags & (flag)) { \ 4983 sal_sprintf(&(line)[offset], desc); \ 4984 (offset) = sal_strlen(line); \ 4985 } \ 4986 } while (0) 4987 4988 STATIC char *_rx_pkt_dump_reason_names[bcmRxReasonCount] = 4989 BCM_RX_REASON_NAMES_INITIALIZER; 4990 4991 void 4992 bcm_pkt_dump(int unit, bcm_pkt_t *pkt, int dump_data) 4993 { 4994 char pbm_str[SOC_PBMP_FMT_LEN], 4995 upbm_str[SOC_PBMP_FMT_LEN], 4996 l3pbm_str[SOC_PBMP_FMT_LEN]; 4997 char line[80]; 4998 int i; 4999 int nl = 1; 5000 int offset = 0; 5001 5002 COMPILER_REFERENCE(unit); 5003 5004 cli_out("Packet dump: %p. Data in %d blocks.\n", (void *)pkt, 5005 pkt->blk_count); 5006 for (i = 0; i < pkt->blk_count; i++) { 5007 sal_sprintf(&line[offset], "%s(0x%p, %d)", nl ? "" : ", ", 5008 (void *)pkt->pkt_data[i].data, pkt->pkt_data[i].len); 5009 offset = sal_strlen(line); 5010 if (!((i+1) % 4)) { 5011 cli_out(" %s\n", line); 5012 nl = 1; 5013 offset = 0; 5014 } else { 5015 nl = 0; 5016 } 5017 } 5018 5019 if (!nl) { 5020 cli_out(" %s\n", line); 5021 } 5022 line[0] = '\0'; 5023 5024 cli_out(" unit %d. %s %d. sm %d. dp %d. dm %d. cos %d. " 5025 "prio_int %d.\n", 5026 pkt->unit, (pkt->flags & BCM_PKT_F_TRUNK) ? "st" : "sp", 5027 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port, 5028 pkt->src_mod, pkt->dest_port, pkt->dest_mod, pkt->cos, pkt->prio_int); 5029 cli_out(" opcode 0x%x. base_len %d. tot_len %d.\n", 5030 pkt->opcode, pkt->pkt_len, pkt->tot_len); 5031 cli_out(" tx pbm %s. upbm %s. l3pbm %s\n", 5032 SOC_PBMP_FMT(pkt->tx_pbmp, pbm_str), 5033 SOC_PBMP_FMT(pkt->tx_upbmp, upbm_str), 5034 SOC_PBMP_FMT(pkt->tx_l3pbmp, l3pbm_str)); 5035 cli_out(" rx_reason 0x%x. rx_unit %d." 5036 " rx_port %d. rx_cpu_cos %d. %s.\n", 5037 pkt->rx_reason, pkt->rx_unit, pkt->rx_port, pkt->rx_cpu_cos, 5038 (pkt->rx_untagged & BCM_PKT_OUTER_UNTAGGED) ? 5039 ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ? 5040 "Untagged" : "Inner tagged") : 5041 ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ? 5042 "Outer tagged" : "Double tagged")); 5043 5044 cli_out(" matched %d. classification-tag %d. timestamp %d.\n", 5045 pkt->rx_matched, 5046 pkt->rx_classification_tag, 5047 pkt->rx_timestamp); 5048 for (i = 0; i < bcmRxReasonCount; i++) { 5049 if (BCM_RX_REASON_GET(pkt->rx_reasons, i)) { 5050 cli_out(" reasons: %s\n", _rx_pkt_dump_reason_names[i]); 5051 } 5052 } 5053 5054 offset = 0; 5055 CHK_FLAG(pkt, BCM_PKT_F_HGHDR, offset, line, "hg_hdr "); 5056 CHK_FLAG(pkt, BCM_PKT_F_SLTAG, offset, line, "sl_tag "); 5057 CHK_FLAG(pkt, BCM_PKT_F_NO_VTAG, offset, line, "no_vtag "); 5058 cli_out(" flags-->%s\n", line); 5059 5060 offset = 0; 5061 CHK_FLAG(pkt, BCM_TX_CRC_ALLOC, offset, line, "crc_alloc "); 5062 CHK_FLAG(pkt, BCM_TX_CRC_REGEN, offset, line, "crc_regen "); 5063 CHK_FLAG(pkt, BCM_TX_CRC_FORCE_ERROR, offset, line, 5064 "crc_force_error "); 5065 cli_out(" tx flags-->%s\n", line); 5066 5067 offset = 0; 5068 CHK_FLAG(pkt, BCM_RX_CRC_STRIP, offset, line, "crc_strip "); 5069 CHK_FLAG(pkt, BCM_PKT_F_NO_VTAG, offset, line, "vtag_strip "); 5070 cli_out(" rx flags-->%s\n", line); 5071 5072 cli_out(" dma chan %d. adr pkt_data %p. idx %d. dv %p\n", 5073 pkt->dma_channel, (void *)&pkt->_pkt_data, pkt->_idx, pkt->_dv); 5074 cli_out(" hghdr: 0x%08x%08x%08x. sltag 0x%x. vtag 0x%x\n", 5075 ((uint32 *)(pkt->_higig))[0], ((uint32 *)(pkt->_higig))[1], 5076 ((uint32 *)(pkt->_higig))[2], ((uint32 *)(pkt->_sltag))[0], 5077 ((uint32 *)(pkt->_vtag))[0]); 5078 5079 if (dump_data) { 5080 int blk, byte = 0, tot_byte = 0; 5081 5082 offset = 0; 5083 for (blk = 0; blk < pkt->blk_count; blk++) { 5084 for (byte = 0; byte < pkt->pkt_data[blk].len; byte++) { 5085 ++tot_byte; 5086 sal_sprintf(&line[offset], "%02x%s", 5087 pkt->pkt_data[blk].data[byte], 5088 !(tot_byte % 4) ? " " : ""); 5089 offset = sal_strlen(line); 5090 if (!(tot_byte % 16)) { 5091 cli_out("data[%04d]: %s\n", tot_byte - 16, line); 5092 offset = 0; 5093 } 5094 if (tot_byte >= pkt->pkt_len) { /* Displayed all of packet */ 5095 goto loop_exit; 5096 } 5097 } 5098 } 5099 5100 loop_exit: 5101 if (tot_byte % 16) { 5102 cli_out("data[%04d]: %s\n", 16 * (tot_byte / 16), line); 5103 } 5104 } 5105 } 5106 5107 #endif /* BROADCOM_DEBUG */