openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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