util.c (15869B)
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 * Driver utility routines 8 */ 9 10 #include <assert.h> 11 #include <soc/enet.h> 12 #include <soc/util.h> 13 #include <soc/error.h> 14 #include <sal/types.h> 15 #include <sal/core/libc.h> 16 #include <sal/core/thread.h> 17 #include <sal/appl/sal.h> 18 #include <shared/bsl.h> 19 20 static fw_desc_t fw_desc[MAX_FW_TYPES]; 21 static misc_desc_t misc_desc[_MAX_PHYS]; 22 23 int (*soc_phy_fw_acquire)(const char *dev_name, uint8 **fw, int *fw_len) = NULL; 24 int (*soc_phy_fw_release)(const char *dev_name, uint8 *fw, int fw_len) = NULL; 25 int (*soc_phy_misc_launch)(const char *dev_name, void *arg) = NULL; 26 27 28 /* 29 * soc_timeout 30 * 31 * These routines implement a polling timer that, in the normal case, 32 * has low overhead, but provides reasonably accurate timeouts for 33 * intervals longer than a millisecond. 34 * 35 * min_polls should be chosen so the operation is expected to complete 36 * within min_polls, if possible. If the operation completes within 37 * min_polls, there is very little overhead. Otherwise, the routine 38 * starts making O/S calls to check the real time clock and uses an 39 * exponential timeout to avoid hogging the CPU. 40 * 41 * Example usage: 42 * 43 * soc_timeout_t to; 44 * sal_usecs_t timeout_usec = 100000; 45 * int min_polls = 100; 46 * 47 * soc_timeout_init(&to, timeout_usec, min_polls); 48 * 49 * while (check_status(thing) != DONE) 50 * if (soc_timeout_check(&to)) { 51 * if (check_status(thing) == DONE) { 52 * break; 53 * } 54 * printf("Operation timed out\n"); 55 * return ERROR; 56 * } 57 * 58 * Note that even after timeout the status should be checked 59 * one more time. Otherwise there is a race condition where an 60 * ill-placed O/S task reschedule could cause a false timeout. 61 */ 62 63 void 64 soc_timeout_init(soc_timeout_t *to, sal_usecs_t usec, int min_polls) 65 { 66 to->min_polls = min_polls; 67 to->usec = usec; 68 to->polls = 1; 69 to->exp_delay = 1; /* In case caller sets min_polls < 0 */ 70 } 71 72 int 73 soc_timeout_check(soc_timeout_t *to) 74 { 75 if (++to->polls >= to->min_polls) { 76 if (to->min_polls >= 0) { 77 /* 78 * Just exceeded min_polls; calculate expiration time by 79 * consulting O/S real time clock. 80 */ 81 82 to->min_polls = -1; 83 to->expire = SAL_USECS_ADD(sal_time_usecs(), to->usec); 84 to->exp_delay = 1; 85 } else { 86 /* 87 * Exceeded min_polls in a previous call. 88 * Consult O/S real time clock to check for expiration. 89 */ 90 91 if (SAL_USECS_SUB(sal_time_usecs(), to->expire) >= 0) { 92 return 1; 93 } 94 95 sal_usleep(to->exp_delay); 96 97 /* Exponential backoff with 10% maximum latency */ 98 99 if ((to->exp_delay *= 2) > to->usec / 10) { 100 to->exp_delay = to->usec / 10; 101 } 102 } 103 } 104 105 return 0; 106 } 107 int 108 soc_tightdelay_timeout_check(soc_timeout_t *to) 109 { 110 if (++to->polls >= to->min_polls) { 111 if (to->min_polls >= 0) { 112 /* 113 * Just exceeded min_polls; calculate expiration time by 114 * consulting O/S real time clock. 115 */ 116 117 to->min_polls = -1; 118 to->expire = SAL_USECS_ADD(sal_time_usecs(), to->usec); 119 to->exp_delay = 1; 120 } 121 else if (to->expire < SOC_TIGHTLOOP_DELAY_LIMIT_USECS) { 122 /* 123 * Exceeded min_polls in a previous call. 124 * Consult O/S real time clock to check for expiration. 125 */ 126 127 if (SAL_USECS_SUB(sal_time_usecs(), to->expire) >= 0) { 128 return 1; 129 } 130 131 sal_udelay(to->exp_delay); 132 133 /* Exponential backoff with 10% maximum latency */ 134 135 if ((to->exp_delay *= 2) > to->usec / 10) { 136 to->exp_delay = to->usec / 10; 137 } 138 } 139 else { 140 /* 141 * Exceeded min_polls in a previous call. 142 * Consult O/S real time clock to check for expiration. 143 */ 144 145 if (SAL_USECS_SUB(sal_time_usecs(), to->expire) >= 0) { 146 return 1; 147 } 148 149 sal_usleep(to->exp_delay); 150 151 /* Exponential backoff with 10% maximum latency */ 152 153 if ((to->exp_delay *= 2) > to->usec / 10) { 154 to->exp_delay = to->usec / 10; 155 } 156 } 157 } 158 159 return 0; 160 } 161 162 sal_usecs_t 163 soc_timeout_elapsed(soc_timeout_t *to) 164 { 165 sal_usecs_t start_time; 166 167 start_time = SAL_USECS_SUB(to->expire, to->usec); 168 169 return SAL_USECS_SUB(sal_time_usecs(), start_time); 170 } 171 172 173 /* 174 * Function: 175 * soc_ntohl_load 176 * Purpose: 177 * Load a 32-bit value and convert from network to host byte order. 178 * Parameters: 179 * a - Address to load from 180 * Returns: 181 * 32-bit value. 182 * Notes: 183 * Unaligned addresses are handled (even if no swap is needed). 184 */ 185 uint32 186 soc_ntohl_load(const void *a) 187 { 188 uint32 v; 189 190 v = ((uint8 *)a)[0] << 24; 191 v |= ((uint8 *)a)[1] << 16; 192 v |= ((uint8 *)a)[2] << 8; 193 v |= ((uint8 *)a)[3] << 0; 194 195 return(v); 196 } 197 198 /* 199 * Function: 200 * soc_ntohs_load 201 * Purpose: 202 * Load a 16-bit value and convert from network to host byte order. 203 * Parameters: 204 * a - Address to load from 205 * Returns: 206 * 16-bit value. 207 * Notes: 208 * Unaligned addresses are handled (even if no swap is needed). 209 */ 210 uint16 211 soc_ntohs_load(const void *a) 212 { 213 uint16 v; 214 215 v = ((uint8 *)a)[0] << 8; 216 v |= ((uint8 *)a)[1] << 0; 217 218 return(v); 219 } 220 221 /* 222 * Function: 223 * soc_htonl_store 224 * Purpose: 225 * Convert a 32-bit value from host to network byte order and store. 226 * Parameters: 227 * a - Address to store to 228 * v - 32-bit value to store 229 * Returns: 230 * Original value of v 231 * Notes: 232 * Unaligned addresses are handled (even if no swap is needed). 233 */ 234 uint32 235 soc_htonl_store(void *a, uint32 v) 236 { 237 ((uint8 *)a)[0] = v >> 24; 238 ((uint8 *)a)[1] = v >> 16; 239 ((uint8 *)a)[2] = v >> 8; 240 ((uint8 *)a)[3] = v >> 0; 241 242 return(v); 243 } 244 245 /* 246 * Function: 247 * soc_htons_store 248 * Purpose: 249 * Convert a 16-bit value from host to network byte order and store. 250 * Parameters: 251 * a - Address to store to 252 * v - 16-bit value to store 253 * Returns: 254 * Original value of v 255 * Notes: 256 * Unaligned addresses are handled (even if no swap is needed). 257 */ 258 uint16 259 soc_htons_store(void *a, uint16 v) 260 { 261 ((uint8 *)a)[0] = v >> 8; 262 ((uint8 *)a)[1] = v >> 0; 263 264 return(v); 265 } 266 267 /* 268 * Function: 269 * soc_letohl_load 270 * Purpose: 271 * Load a 32-bit value and convert from little-endian to host byte order. 272 * Parameters: 273 * a - Address to load from 274 * Returns: 275 * 32-bit value. 276 * Notes: 277 * Unaligned addresses are handled (even if no swap is needed). 278 */ 279 uint32 280 soc_letohl_load(const void *a) 281 { 282 uint32 v; 283 284 v = ((uint8 *)a)[3] << 24; 285 v |= ((uint8 *)a)[2] << 16; 286 v |= ((uint8 *)a)[1] << 8; 287 v |= ((uint8 *)a)[0] << 0; 288 289 return(v); 290 } 291 292 /* 293 * Function: 294 * soc_letohs_load 295 * Purpose: 296 * Load a 16-bit value and convert from little-endian to host byte order. 297 * Parameters: 298 * a - Address to load from 299 * Returns: 300 * 16-bit value. 301 * Notes: 302 * Unaligned addresses are handled (even if no swap is needed). 303 */ 304 uint16 305 soc_letohs_load(const void *a) 306 { 307 uint16 v; 308 309 v = ((uint8 *)a)[1] << 8; 310 v |= ((uint8 *)a)[0] << 0; 311 312 return(v); 313 } 314 315 /* 316 * Function: 317 * soc_htolel_store 318 * Purpose: 319 * Convert a 32-bit value from host to little-endian byte order and store. 320 * Parameters: 321 * a - Address to store to 322 * v - 32-bit value to store 323 * Returns: 324 * Original value of v 325 * Notes: 326 * Unaligned addresses are handled (even if no swap is needed). 327 */ 328 uint32 329 soc_htolel_store(void *a, uint32 v) 330 { 331 ((uint8 *)a)[3] = v >> 24; 332 ((uint8 *)a)[2] = v >> 16; 333 ((uint8 *)a)[1] = v >> 8; 334 ((uint8 *)a)[0] = v >> 0; 335 336 return(v); 337 } 338 339 /* 340 * Function: 341 * soc_htoles_store 342 * Purpose: 343 * Convert a 16-bit value from host to little-endian byte order and store. 344 * Parameters: 345 * a - Address to store to 346 * v - 16-bit value to store 347 * Returns: 348 * Original value of v 349 * Notes: 350 * Unaligned addresses are handled (even if no swap is needed). 351 */ 352 uint16 353 soc_htoles_store(void *a, uint16 v) 354 { 355 ((uint8 *)a)[1] = v >> 8; 356 ((uint8 *)a)[0] = v >> 0; 357 358 return(v); 359 } 360 361 /* Helper routine to retreive particular bits from data */ 362 void 363 soc_bits_get(uint32 *str, uint32 minbit, uint32 maxbit, void *data_vp) 364 { 365 int len, str_index, data_index, right_shift_count, left_shift_count; 366 uint32 *data = data_vp; 367 368 len = maxbit - minbit + 1; 369 str_index = minbit >> 5; 370 data_index = 0; 371 right_shift_count = minbit & 0x1f; 372 left_shift_count = 32 - right_shift_count; 373 374 if (right_shift_count) { 375 for (; len > 0; len -= 32) { 376 data[data_index] = str[str_index++] >> right_shift_count; 377 data[data_index++] |= str[str_index] << left_shift_count; 378 } 379 } else { 380 for (; len > 0; len -= 32) { 381 data[data_index++] = str[str_index++]; 382 } 383 } 384 if (len & 0x1f) { 385 data[data_index - 1] &= (1 << (len & 0x1f)) - 1; 386 } 387 } 388 389 void soc_phy_fw_init(void) 390 { 391 int i = 0; 392 393 for (i = 0; i < MAX_FW_TYPES; i++) { 394 fw_desc[i].dev_name = NULL; 395 fw_desc[i].fw = NULL; 396 fw_desc[i].fw_len = 0; 397 } 398 399 } 400 401 void soc_phy_misc_init(void) 402 { 403 int i = 0; 404 405 for (i = 0; i < _MAX_PHYS; i++) { 406 misc_desc[i].dev_name = NULL; 407 misc_desc[i].arg = NULL; 408 } 409 410 } 411 412 int soc_phy_fw_get(char *dev_name, uint8 **fw, int *fw_len) 413 { 414 int i = 0; 415 416 while(i < MAX_FW_TYPES) { 417 if (fw_desc[i].fw == NULL) { 418 /* empty slot */ 419 break; 420 } 421 if ( !sal_strcmp(dev_name, fw_desc[i].dev_name) ) { 422 if (fw_desc[i].fw == NO_FW) { 423 /* f/w unavailable */ 424 return SOC_E_UNAVAIL; 425 } 426 /* matching f/w found */ 427 *fw = fw_desc[i].fw; 428 *fw_len = fw_desc[i].fw_len; 429 return SOC_E_NONE; 430 } 431 i++; 432 } 433 if (i == MAX_FW_TYPES) { 434 /* no more room */ 435 return SOC_E_UNAVAIL; 436 } 437 438 fw_desc[i].dev_name = dev_name; 439 440 if (soc_phy_fw_acquire && ((*soc_phy_fw_acquire)(dev_name, fw, fw_len) == SOC_E_NONE)) { 441 fw_desc[i].fw = *fw; 442 fw_desc[i].fw_len = *fw_len; 443 return SOC_E_NONE; 444 } else { 445 /* This type of f/w is not found. So add a blacklist entry. */ 446 fw_desc[i].fw = NO_FW; 447 } 448 449 return SOC_E_UNAVAIL; 450 } 451 452 void soc_phy_fw_put_all(void) 453 { 454 int i = 0; 455 456 while(i < MAX_FW_TYPES) { 457 if (fw_desc[i].dev_name == NULL) { 458 /* empty slot */ 459 break; 460 } 461 if ((fw_desc[i].fw == NO_FW) || (soc_phy_fw_release && 462 ((*soc_phy_fw_release)(fw_desc[i].dev_name, fw_desc[i].fw, fw_desc[i].fw_len) == SOC_E_NONE))) { 463 fw_desc[i].dev_name = NULL; 464 fw_desc[i].fw = NULL; 465 fw_desc[i].fw_len = 0; 466 } 467 i++; 468 } 469 470 } 471 472 /* 473 * Format a long integer. If the value is less than 10, generates 474 * decimal, otherwise generates hex. 475 * 476 * val[0] is the least significant word. 477 * nval is the number of uint32's in the value. 478 */ 479 480 void 481 soc_format_long_integer(char *buf, uint32 *val, int nval) 482 { 483 int i; 484 485 for (i = nval - 1; i > 0; i--) { /* Skip leading zeroes */ 486 if (val[i]) { 487 break; 488 } 489 } 490 491 if (i == 0 && val[i] < 10) { /* Only a single word < 10? */ 492 sal_sprintf(buf, "%d", val[i]); 493 } else { 494 sal_sprintf(buf, "0x%x", val[i]); /* Print first word */ 495 } 496 497 while (--i >= 0) { /* Print rest of words, if any */ 498 sal_sprintf(buf + sal_strlen(buf), "%08x", val[i]); 499 } 500 } 501 502 /* 503 * Format uint64 504 * Endian handling is taken into account. 505 */ 506 507 void 508 soc_format_uint64(char *buf, uint64 n) 509 { 510 uint32 val[2]; 511 512 val[0] = COMPILER_64_LO(n); 513 val[1] = COMPILER_64_HI(n); 514 515 soc_format_long_integer(buf, val, 2); 516 } 517 518 519 /* 520 * Convert hex character to digit 521 */ 522 523 int 524 soc_xdigit2i(int digit) 525 { 526 if (digit >= '0' && digit <= '9') return (digit - '0' ); 527 if (digit >= 'a' && digit <= 'f') return (digit - 'a' + 10); 528 if (digit >= 'A' && digit <= 'F') return (digit - 'A' + 10); 529 return 0; 530 } 531 532 /* 533 * Return true if a constant is a well-formed integer of the type 534 * supported by parse_integer. 535 */ 536 537 int 538 soc_isint(char *s) 539 { 540 int base; 541 542 if (s == NULL) { 543 return 0; 544 } 545 546 if (*s == '-') { 547 s++; 548 } 549 550 if (*s == '0') { 551 if (s[1] == 'b' || s[1] == 'B') { 552 base = 2; 553 s += 2; 554 } else if (s[1] == 'x' || s[1] == 'X') { 555 base = 16; 556 s += 2; 557 } else 558 base = 8; 559 } else { 560 base = 10; 561 } 562 563 do { 564 if (!isxdigit((unsigned) *s) || soc_xdigit2i(*s) >= base) { 565 return(0); 566 } 567 } while (*++s); 568 569 return(1); 570 } 571 /* 572 * Read an integer: return unsigned representation. 573 * Number format explained below. 574 * 575 * Expects: 576 * [-]0x[0-9|A-F|a-f]+ -hexadecimal if the string begins with "0x" 577 * [-][0-9]+ -decimal integer 578 * [-]0[0-7]+ -octal integer 579 * [-]0b[0-1]+ -binary if the string begins with "0b" 580 */ 581 582 uint32 583 soc_parse_integer(char *str) 584 { 585 586 if (!soc_isint(str)) { 587 cli_out("WARNING: truncated malformed integer \"%s\"\n", str); 588 } 589 590 return _shr_ctoi(str); 591 } 592 593 /* 594 * --------------------------------------------------------------------------- 595 * Long Integer Support 596 * --------------------------------------------------------------------------- 597 * 598 * Long integers consist of a variable length array of uint32. 599 * 600 * Within the array, the least significant word comes first. This is 601 * true on all platforms. However, each word itself is stored in the 602 * platform native byte order. 603 */ 604 605 /* 606 * Read a long integer: can read a long hex integer, or a regular 607 * integer in any base supported by parse_integer. 608 * 609 * val[0] receives the least significant word (little-endian). 610 * nbuf is the number size (count of uint32's). 611 */ 612 613 void 614 soc_parse_long_integer(uint32 *val, int nval, char *str) 615 { 616 char eight[11], *s, *t; 617 int i, neg; 618 619 if (*str == '-') { 620 neg = 1; 621 str++; 622 } else { 623 neg = 0; 624 } 625 626 sal_memset(val, 0, nval * sizeof (*val)); 627 628 629 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { 630 val[0] = soc_parse_integer(str); 631 goto done; 632 } 633 634 /* Skip to the last hex digit in the string */ 635 636 for (s = str + 1; isxdigit((unsigned) s[1]); s++) { 637 ; 638 } 639 640 /* Parse backward in groups of 8 digits */ 641 642 i = 0; 643 644 do { 645 /* Copy 8 digits backward to form a string "0xdddddddd\0" */ 646 t = eight + 11; 647 *--t = 0; 648 while (t > eight + 2 && *s != 'x') { 649 *--t = *s--; 650 } 651 *--t = 'x'; 652 *--t = '0'; 653 654 val[i++] = soc_parse_integer(t); 655 } while (*s != 'x' && i < nval); 656 657 done: 658 if (neg) { 659 uint32 cy = 1; 660 for (i = 0; i < nval; i++) { 661 if ((val[i] = (~val[i]) + cy) != 0) { 662 cy = 0; 663 } 664 } 665 } 666 } 667 668 /* 669 * Parse uint64 670 * Endian handling is taken into account. 671 */ 672 673 uint64 674 soc_parse_uint64(char *str) 675 { 676 uint32 tmpval[2]; 677 uint64 rval; 678 679 soc_parse_long_integer(tmpval, 2, str); 680 COMPILER_64_SET(rval, tmpval[1], tmpval[0]); 681 682 return rval; 683 } 684 685 int soc_phy_misc(const char *dev_name, void *arg) 686 { 687 int i = 0; 688 689 while(i < _MAX_PHYS) { 690 if (misc_desc[i].dev_name == NULL) { 691 /* empty slot */ 692 break; 693 } 694 if ( !sal_strcmp(dev_name, misc_desc[i].dev_name) && (misc_desc[i].arg == arg)) { 695 /* Matching entry found. Already invoked. */ 696 697 return SOC_E_NONE; 698 } 699 i++; 700 } 701 if (i == _MAX_PHYS) { 702 /* no more room */ 703 return SOC_E_UNAVAIL; 704 } 705 706 misc_desc[i].dev_name = dev_name; 707 misc_desc[i].arg = arg; 708 709 if ( !soc_phy_misc_launch ) { 710 return SOC_E_UNAVAIL; 711 } 712 713 if ((*soc_phy_misc_launch)(dev_name, arg) == SOC_E_NONE) { 714 return SOC_E_NONE; 715 } 716 717 misc_desc[i].dev_name = NULL; 718 misc_desc[i].arg = NULL; 719 720 return SOC_E_FAIL; 721 } 722