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

metrics.c (38745B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:    metrics.c
      8  *
      9  * Purpose: 
     10  *
     11  * Functions:
     12  *      bcm_common_ptp_ctdev_alarm_callback_register
     13  *      bcm_common_ptp_ctdev_alarm_callback_unregister
     14  *      bcm_common_ptp_ctdev_alpha_get
     15  *      bcm_common_ptp_ctdev_alpha_set
     16  *      bcm_common_ptp_ctdev_enable_get
     17  *      bcm_common_ptp_ctdev_enable_set
     18  *      bcm_common_ptp_ctdev_verbose_get
     19  *      bcm_common_ptp_ctdev_verbose_set
     20  *
     21  *      _bcm_ptp_ctdev_init
     22  *      _bcm_ptp_ctdev_gateway
     23  *      _bcm_ptp_ctdev_phase_accumulator
     24  *      _bcm_ptp_ctdev_calculator
     25  *      _bcm_ptp_ctdev_get
     26  *      _bcm_ptp_llu_div
     27  *      _bcm_ptp_llu_isqrt
     28  *      _bcm_ptp_xorshift_rand
     29  *      _bcm_ptp_ctdev_g823_mask
     30  *      _bcm_ptp_circular_buffer_init
     31  *      _bcm_ptp_circular_buffer_free
     32  *      _bcm_ptp_circular_buffer_write
     33  *      _bcm_ptp_circular_buffer_read
     34  *      _bcm_ptp_circular_buffer_peekn
     35  */
     36 
     37 #if defined(INCLUDE_PTP)
     38 
     39 #include <bcm/ptp.h>
     40 #include <bcm_int/common/ptp.h>
     41 #include <bcm_int/ptp_common.h>
     42 #include <bcm/error.h>
     43 #include <shared/bsl.h>
     44 /* Definitions. */
     45 #define PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC                   (1000000000) /* 1 msec */
     46 #define PTP_CTDEV_FIXEDPOINT_BIT_MAX                                   (15)
     47 
     48 #define PTP_CTDEV_TAU0_SEC                                              (1)
     49 #define PTP_CTDEV_NUM_TIMESCALES                                       (11)
     50 
     51 #define PTP_CTDEV_ALPHA_NUMERATOR                                      (63)
     52 #define PTP_CTDEV_ALPHA_DENOMINATOR                                    (64)
     53 
     54 #define PTP_CTDEV_KEFF_NUMERATOR              (PTP_CTDEV_ALPHA_DENOMINATOR)
     55 #define PTP_CTDEV_KEFF_DENOMINATOR            (PTP_CTDEV_ALPHA_DENOMINATOR - \
     56                                                PTP_CTDEV_ALPHA_NUMERATOR)
     57 
     58 #define PTP_CTDEV_MUTEX_TIMEOUT_USEC                              (1000000)
     59 
     60 /* Macros. */
     61 #define PTP_CTDEV_MUTEX_TAKE() \
     62     PTP_MUTEX_TAKE(ctdev_mutex, PTP_CTDEV_MUTEX_TIMEOUT_USEC)
     63 
     64 #define PTP_CTDEV_MUTEX_RELEASE_RETURN(__rv__) \
     65     PTP_MUTEX_RELEASE_RETURN(ctdev_mutex, __rv__)
     66 
     67 /* Types. */
     68 typedef struct eltype_s {
     69     int32 value;
     70 } eltype_t;
     71 
     72 typedef struct _bcm_ptp_circular_buffer_s {
     73     int num_el;
     74     int num_read;
     75     int num_write;
     76 
     77     eltype_t* data;
     78     eltype_t* write_el;
     79     eltype_t* read_el;
     80 } _bcm_ptp_circular_buffer_t;
     81 
     82 typedef struct _bcm_ptp_ctdev_s {
     83     /* Timescale. */
     84     int tau;
     85     int m;
     86 
     87     int64 dS;
     88     uint64 dSsq;
     89     uint64 Sov;
     90 
     91     /* TVAR incl. fixed-point scaling. */
     92     uint64 tvar;
     93     /* TDEV incl. fixed-point scaling. */
     94     uint32 tdev;
     95     /* TDEV (picoseconds). */
     96     uint64 tdev_psec;
     97 
     98     /* Dynamic re-scaling fixed-point bit. */
     99     uint32 fpbit;
    100 } _bcm_ptp_ctdev_t;
    101 
    102 typedef struct _bcm_ptp_ctdev_array_s {
    103     _bcm_ptp_ctdev_t entry[PTP_CTDEV_NUM_TIMESCALES];
    104     _bcm_ptp_circular_buffer_t phase_buffer;
    105     _bcm_ptp_circular_buffer_t wrap_buffer;
    106 } _bcm_ptp_ctdev_array_t;
    107 
    108 typedef struct _bcm_ptp_ctdev_options_s {
    109     int enable;
    110     int dynamic_rescale;
    111     int verbose;
    112 } _bcm_ptp_ctdev_options_t;
    113 
    114 typedef struct _bcm_ptp_ctdev_parameters_s {
    115     uint16 alpha_numerator;
    116     uint16 alpha_denominator;
    117     uint16 keff_numerator;
    118     uint16 keff_denominator;
    119 } _bcm_ptp_ctdev_parameters_t;
    120 
    121 /* Macros. */
    122 
    123 /*
    124  * 64-BIT MATH: Inplace division.
    125  * Unsigned 64-bit dividend, unsigned 16-bit divisor.
    126  * NOTE: Macro is syntactically similar to SDK's COMPILER_64_*** operations.
    127  */
    128 #define COMPILER_64_UDIV_16(dst, src)                                              \
    129     do {                                                                           \
    130         int __el__;                                                                \
    131         uint16 __numh__[4];  /* Numerator as 16-bit half words. */                 \
    132         uint16 __qh__[4];    /* Quotient as 16-bit half-words. */                  \
    133         uint16 __rhat__ = 0; /* Remainder. */                                      \
    134                                                                                    \
    135         uint32 __Ql__;                                                             \
    136         uint32 __Qh__;                                                             \
    137                                                                                    \
    138         __numh__[0] = ((uint16)(COMPILER_64_LO(dst) & 0xffff));                    \
    139         __numh__[1] = ((uint16)(COMPILER_64_LO(dst) >> 16));                       \
    140         __numh__[2] = ((uint16)(COMPILER_64_HI(dst) & 0xffff));                    \
    141         __numh__[3] = ((uint16)(COMPILER_64_HI(dst) >> 16));                       \
    142                                                                                    \
    143         for (__el__ = 3; __el__ >= 0; --__el__) {                                  \
    144             __qh__[__el__] = (__rhat__*65536 + __numh__[__el__])/(src);            \
    145             __rhat__ = (__rhat__*65536 + __numh__[__el__]) - __qh__[__el__]*(src); \
    146         }                                                                          \
    147                                                                                    \
    148         __Ql__ = __qh__[0] + (__qh__[1] << 16);                                    \
    149         __Qh__ = __qh__[2] + (__qh__[3] << 16);                                    \
    150         COMPILER_64_SET(dst, __Qh__, __Ql__);                                      \
    151     } while (0)
    152 
    153 /*
    154  * 64-BIT MATH: Integer square root.
    155  * Unsigned 64-bit argument, unsigned 32-bit result.
    156  * NOTE: Macro is syntactically similar to SDK's COMPILER_64_*** operations.
    157  */
    158 #define COMPILER_64_ISQRT(dst, src)                                                \
    159     do {                                                                           \
    160         uint64 __root__;                                                           \
    161         uint64 __remainder__;                                                      \
    162         uint64 __place__;                                                          \
    163         uint64 __condval__;                                                        \
    164                                                                                    \
    165         __remainder__ = src;                                                       \
    166         COMPILER_64_ZERO(__root__);                                                \
    167         COMPILER_64_SET(__place__, 0x40000000, 0);                                 \
    168                                                                                    \
    169         while (COMPILER_64_GT(__place__, __remainder__)) {                         \
    170             COMPILER_64_UDIV_16(__place__, 4);                                     \
    171         }                                                                          \
    172                                                                                    \
    173         while (!COMPILER_64_IS_ZERO(__place__)) {                                  \
    174             __condval__ = __place__;                                               \
    175             COMPILER_64_ADD_64(__condval__, __root__);                             \
    176             if (COMPILER_64_GE(__remainder__, __condval__)) {                      \
    177                 COMPILER_64_SUB_64(__remainder__, __condval__);                    \
    178                 COMPILER_64_ADD_64(__root__, __place__);                           \
    179                 COMPILER_64_ADD_64(__root__, __place__);                           \
    180             }                                                                      \
    181             COMPILER_64_UDIV_16(__root__, 2);                                      \
    182             COMPILER_64_UDIV_16(__place__, 4);                                     \
    183         }                                                                          \
    184         dst = COMPILER_64_LO(__root__);                                            \
    185     } while (0)
    186 
    187 /* Constants and variables. */
    188 static _bcm_ptp_mutex_t ctdev_mutex = 0x0;
    189 
    190 static int32 phase_err_psec;
    191 static int32 wrap_counter;
    192 
    193 static const int64 zero64 = COMPILER_64_INIT(0,0);
    194 
    195 static const _bcm_ptp_ctdev_t ctdev_default;
    196 static _bcm_ptp_ctdev_array_t ctdev_array;
    197 
    198 static _bcm_ptp_ctdev_options_t ctdev_options = {
    199     0,
    200     1,
    201     0
    202 };
    203 
    204 static uint32 ctdev_flags;
    205 
    206 static _bcm_ptp_ctdev_parameters_t ctdev_parameters = {
    207     PTP_CTDEV_ALPHA_NUMERATOR,
    208     PTP_CTDEV_ALPHA_DENOMINATOR,
    209     PTP_CTDEV_KEFF_NUMERATOR,
    210     PTP_CTDEV_KEFF_DENOMINATOR
    211 };
    212 
    213 static int ctdev_memory_init;
    214 
    215 static bcm_ptp_ctdev_alarm_cb ctdev_alarm_fcn = NULL;
    216 static bcm_ptp_ctdev_alarm_data_t ctdev_alarm_data;
    217 
    218 /* Static functions. */
    219 static void _bcm_ptp_circular_buffer_init(_bcm_ptp_circular_buffer_t *buffer, int num_el);
    220 static void _bcm_ptp_circular_buffer_free(_bcm_ptp_circular_buffer_t *buffer);
    221 
    222 static void _bcm_ptp_circular_buffer_write(_bcm_ptp_circular_buffer_t *buffer, eltype_t *value);
    223 static void _bcm_ptp_circular_buffer_read(_bcm_ptp_circular_buffer_t *buffer, eltype_t *value);
    224 
    225 #if 0  /* Unused. Preserve for future use. */
    226 static void _bcm_ptp_circular_buffer_peek(_bcm_ptp_circular_buffer_t *buffer, eltype_t *value);
    227 #endif /* 0 */
    228 static void _bcm_ptp_circular_buffer_peekn(_bcm_ptp_circular_buffer_t *buffer, int n, eltype_t *value);
    229 
    230 
    231 /*
    232  * Function:
    233  *      _bcm_ptp_ctdev_init
    234  * Purpose:
    235  *      Initialize the continuous time deviation (C-TDEV) metric.
    236  * Parameters:
    237  *      unit      - (IN) Unit number.
    238  *      ptp_id    - (IN) PTP stack ID.
    239  *      clock_num - (IN) PTP clock number.
    240  *      p         - (IN) C-TDEV algorithm control parameters. (UNUSED)
    241  * Returns:
    242  *      BCM_E_XXX - Function status.
    243  * Notes:
    244  */
    245 int
    246 _bcm_ptp_ctdev_init(
    247     int unit,
    248     bcm_ptp_stack_id_t ptp_id,
    249     int clock_num,
    250     uint32 p)
    251 {
    252     int i;
    253 
    254     if (!ctdev_mutex) {
    255         ctdev_mutex = _bcm_ptp_mutex_create("ctdev_mutex");
    256     }
    257 
    258     PTP_CTDEV_MUTEX_TAKE();
    259 
    260     /* Memory management. */
    261     if (ctdev_memory_init) {
    262         _bcm_ptp_circular_buffer_free(&ctdev_array.phase_buffer);
    263         _bcm_ptp_circular_buffer_free(&ctdev_array.wrap_buffer);
    264     }
    265     ctdev_memory_init = 1;
    266 
    267     _bcm_ptp_circular_buffer_init(&ctdev_array.phase_buffer,
    268         1 + 3*(1 << (PTP_CTDEV_NUM_TIMESCALES -1)));
    269     phase_err_psec = 0;
    270 
    271     _bcm_ptp_circular_buffer_init(&ctdev_array.wrap_buffer,
    272         1 + 3*(1 << (PTP_CTDEV_NUM_TIMESCALES -1)));
    273     wrap_counter = 0;
    274 
    275     for (i = 0; i < PTP_CTDEV_NUM_TIMESCALES; ++i) {
    276         ctdev_array.entry[i] = ctdev_default;
    277 
    278         /* Set timescale. */
    279         ctdev_array.entry[i].m = 1 << i;
    280         ctdev_array.entry[i].tau = ctdev_array.entry[i].m * PTP_CTDEV_TAU0_SEC;
    281 
    282         /* Initialize dynamic re-scaling fixed-point bit. */
    283         ctdev_array.entry[i].fpbit = 0;
    284     }
    285 
    286     /* Restore default algorithm parameters. */
    287     ctdev_parameters.alpha_numerator = PTP_CTDEV_ALPHA_NUMERATOR;
    288     ctdev_parameters.alpha_denominator = PTP_CTDEV_ALPHA_DENOMINATOR;
    289     ctdev_parameters.keff_numerator = PTP_CTDEV_KEFF_NUMERATOR;
    290     ctdev_parameters.keff_denominator = PTP_CTDEV_KEFF_DENOMINATOR;
    291 
    292     /* Reset elapsed data time (duration of frequency correction data processed). */
    293     ctdev_alarm_data.elapsed_sec = 0;
    294 
    295     PTP_CTDEV_MUTEX_RELEASE_RETURN(BCM_E_NONE);
    296 }
    297 
    298 /*
    299  * Function:
    300  *      bcm_common_ptp_ctdev_alarm_callback_register
    301  * Purpose:
    302  *      Register a C-TDEV alarm callback function.
    303  * Parameters:
    304  *      unit      - (IN) Unit number.
    305  *      ptp_id    - (IN) PTP stack ID.
    306  *      clock_num - (IN) PTP clock number.
    307  *      alarm_cb  - (IN) C-TDEV alarm callback function pointer.
    308  * Returns:
    309  *      BCM_E_XXX - Function status.
    310  */
    311 int
    312 bcm_common_ptp_ctdev_alarm_callback_register(
    313     int unit,
    314     bcm_ptp_stack_id_t ptp_id,
    315     int clock_num,
    316     bcm_ptp_ctdev_alarm_cb alarm_cb)
    317 {
    318     int rv;
    319 
    320     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    321             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    322         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    323         return rv;
    324     }
    325 
    326     ctdev_alarm_fcn = alarm_cb;
    327     return BCM_E_NONE;
    328 }
    329 
    330 /*
    331  * Function:
    332  *      bcm_common_ptp_ctdev_alarm_callback_unregister
    333  * Purpose:
    334  *      Unregister a C-TDEV alarm callback function.
    335  * Parameters:
    336  *      unit      - (IN) Unit number.
    337  *      ptp_id    - (IN) PTP stack ID.
    338  *      clock_num - (IN) PTP clock number.
    339  * Returns:
    340  *      BCM_E_XXX - Function status.
    341  */
    342 int
    343 bcm_common_ptp_ctdev_alarm_callback_unregister(
    344     int unit,
    345     bcm_ptp_stack_id_t ptp_id,
    346     int clock_num)
    347 {
    348     int rv;
    349 
    350     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    351             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    352         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    353         return rv;
    354     }
    355 
    356     ctdev_alarm_fcn = NULL;
    357     return BCM_E_NONE;
    358 }
    359 
    360 /*
    361  * Function:
    362  *      bcm_common_ptp_ctdev_enable_get
    363  * Purpose:
    364  *      Get enable/disable state of C-TDEV processing.
    365  * Parameters:
    366  *      unit        - (IN)  Unit number.
    367  *      ptp_id      - (IN)  PTP stack ID.
    368  *      clock_num   - (IN)  PTP clock number.
    369  *      enable      - (OUT) Enable Boolean.
    370  *      flags       - (OUT) C-TDEV control flags. (UNUSED)
    371  * Returns:
    372  *      BCM_E_XXX - Function status.
    373  * Notes:
    374  */
    375 int
    376 bcm_common_ptp_ctdev_enable_get(
    377     int unit,
    378     bcm_ptp_stack_id_t ptp_id,
    379     int clock_num,
    380     int *enable,
    381     uint32 *flags)
    382 {
    383     int rv;
    384 
    385     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    386             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    387         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    388         return rv;
    389     }
    390 
    391     *enable = ctdev_options.enable;
    392     *flags = ctdev_flags;
    393 
    394     return BCM_E_NONE;
    395 }
    396 
    397 /*
    398  * Function:
    399  *      bcm_common_ptp_ctdev_enable_set
    400  * Purpose:
    401  *      Set enable/disable state of C-TDEV processing.
    402  * Parameters:
    403  *      unit        - (IN) Unit number.
    404  *      ptp_id      - (IN) PTP stack ID.
    405  *      clock_num   - (IN) PTP clock number.
    406  *      enable      - (IN) Enable Boolean.
    407  *      flags       - (IN) C-TDEV control flags. (UNUSED)
    408  * Returns:
    409  *      BCM_E_XXX - Function status.
    410  * Notes:
    411  */
    412 int
    413 bcm_common_ptp_ctdev_enable_set(
    414     int unit,
    415     bcm_ptp_stack_id_t ptp_id,
    416     int clock_num,
    417     int enable,
    418     uint32 flags)
    419 {
    420     int rv;
    421     uint32 p = 0;
    422 
    423     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    424             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    425         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    426         return rv;
    427     }
    428 
    429     /* Reset C-TDEV algorithm on disable.*/
    430     if (0 == enable) {
    431         if (BCM_FAILURE(rv = _bcm_ptp_ctdev_init(unit, ptp_id, clock_num, p))) {
    432             return rv;
    433         }
    434     }
    435 
    436     ctdev_options.enable = enable;
    437     ctdev_flags = flags;
    438 
    439     return BCM_E_NONE;
    440 }
    441 
    442 /*
    443  * Function:
    444  *      bcm_common_ptp_ctdev_verbose_get
    445  * Purpose:
    446  *      Get verbose program control option of C-TDEV processing.
    447  * Parameters:
    448  *      unit        - (IN)  Unit number.
    449  *      ptp_id      - (IN)  PTP stack ID.
    450  *      clock_num   - (IN)  PTP clock number.
    451  *      verbose     - (OUT) Verbose Boolean.
    452  * Returns:
    453  *      BCM_E_XXX - Function status.
    454  * Notes:
    455  */
    456 int
    457 bcm_common_ptp_ctdev_verbose_get(
    458     int unit,
    459     bcm_ptp_stack_id_t ptp_id,
    460     int clock_num,
    461     int *verbose)
    462 {
    463     int rv;
    464 
    465     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    466             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    467         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    468         return rv;
    469     }
    470 
    471     *verbose = ctdev_options.verbose;
    472     return BCM_E_NONE;
    473 }
    474 
    475 /*
    476  * Function:
    477  *      bcm_common_ptp_ctdev_verbose_set
    478  * Purpose:
    479  *      Set verbose program control option of C-TDEV processing.
    480  * Parameters:
    481  *      unit        - (IN) Unit number.
    482  *      ptp_id      - (IN) PTP stack ID.
    483  *      clock_num   - (IN) PTP clock number.
    484  *      verbose     - (IN) Verbose Boolean.
    485  * Returns:
    486  *      BCM_E_XXX - Function status.
    487  * Notes:
    488  */
    489 int
    490 bcm_common_ptp_ctdev_verbose_set(
    491     int unit,
    492     bcm_ptp_stack_id_t ptp_id,
    493     int clock_num,
    494     int verbose)
    495 {
    496     int rv;
    497 
    498     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    499             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    500         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    501         return rv;
    502     }
    503 
    504     ctdev_options.verbose = verbose;
    505     return BCM_E_NONE;
    506 }
    507 
    508 /*
    509  * Function:
    510  *      bcm_common_ptp_ctdev_alpha_get
    511  * Purpose:
    512  *      Get C-TDEV recursive algorithm forgetting factor (alpha).
    513  * Parameters:
    514  *      unit              - (IN)  Unit number.
    515  *      ptp_id            - (IN)  PTP stack ID.
    516  *      clock_num         - (IN)  PTP clock number.
    517  *      alpha_numerator   - (OUT) Forgetting factor numerator.
    518  *      alpha_denominator - (OUT) Forgetting factor denominator.
    519  * Returns:
    520  *      BCM_E_XXX - Function status.
    521  * Notes:
    522  */
    523 int
    524 bcm_common_ptp_ctdev_alpha_get(
    525     int unit,
    526     bcm_ptp_stack_id_t ptp_id,
    527     int clock_num,
    528     uint16 *alpha_numerator,
    529     uint16 *alpha_denominator)
    530 {
    531     int rv;
    532 
    533     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    534             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    535         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    536         return rv;
    537     }
    538 
    539     *alpha_numerator = ctdev_parameters.alpha_numerator;
    540     *alpha_denominator = ctdev_parameters.alpha_denominator;
    541 
    542     return BCM_E_NONE;
    543 }
    544 
    545 /*
    546  * Function:
    547  *      bcm_common_ptp_ctdev_alpha_set
    548  * Purpose:
    549  *      Set C-TDEV recursive algorithm forgetting factor (alpha).
    550  * Parameters:
    551  *      unit              - (IN) Unit number.
    552  *      ptp_id            - (IN) PTP stack ID.
    553  *      clock_num         - (IN) PTP clock number.
    554  *      alpha_numerator   - (IN) Forgetting factor numerator.
    555  *      alpha_denominator - (IN) Forgetting factor denominator.
    556  * Returns:
    557  *      BCM_E_XXX - Function status.
    558  * Notes:
    559  */
    560 int
    561 bcm_common_ptp_ctdev_alpha_set(
    562     int unit,
    563     bcm_ptp_stack_id_t ptp_id,
    564     int clock_num,
    565     uint16 alpha_numerator,
    566     uint16 alpha_denominator)
    567 {
    568     int rv;
    569 
    570     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, clock_num,
    571             PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    572         PTP_ERROR_FUNC("_bcm_ptp_function_precheck()");
    573         return rv;
    574     }
    575 
    576     if (alpha_numerator >= alpha_denominator) {
    577         /* alpha >= 1 numerically unstable by definition. */
    578         return BCM_E_PARAM;
    579     }
    580 
    581     ctdev_parameters.alpha_numerator = alpha_numerator;
    582     ctdev_parameters.alpha_denominator = alpha_denominator;
    583 
    584     ctdev_parameters.keff_numerator = ctdev_parameters.alpha_denominator;
    585     ctdev_parameters.keff_denominator =
    586         (ctdev_parameters.alpha_denominator - ctdev_parameters.alpha_numerator);
    587 
    588     LOG_CLI((BSL_META_U(unit,
    589                         "bcm_common_ptp_ctdev_alpha_set(): ALPHA = %u/%u\n"),
    590              (unsigned)ctdev_parameters.alpha_numerator,
    591              (unsigned)ctdev_parameters.alpha_denominator));
    592 
    593     return BCM_E_NONE;
    594 }
    595 
    596 /*
    597  * Function:
    598  *      _bcm_ptp_ctdev_gateway
    599  * Purpose:
    600  *      Gateway to update C-TDEV metric with event message data from PTP stack
    601  *      that includes 1s-average frequency correction measurement(s).
    602  * Parameters:
    603  *      unit        - (IN) Unit number.
    604  *      ptp_id      - (IN) PTP stack ID.
    605  *      clock_num   - (IN) PTP clock number.
    606  *      ev_data_len - (IN) TDEV event message data length (octets).
    607  *      ev_data     - (IN) TDEV event message data.
    608  * Returns:
    609  *      BCM_E_XXX - Function status.
    610  * Notes:
    611  */
    612 int
    613 _bcm_ptp_ctdev_gateway(
    614     int unit,
    615     bcm_ptp_stack_id_t ptp_id,
    616     int clock_num,
    617     int ev_data_len,
    618     uint8 *ev_data)
    619 {
    620     int rv;
    621     int i;
    622 
    623     int cursor = 0;
    624     int numel;
    625     int64 freq_corr_ppt;
    626 
    627     bcm_ptp_ctdev_alarm_data_t ctdev_alarm_data_copy;
    628 
    629     if (0 == ctdev_options.enable) {
    630         /* C-TDEV disabled. */
    631         if (ctdev_options.verbose) {
    632             LOG_CLI((BSL_META_U(unit,
    633                                 "_bcm_ptp_ctdev_gateway(): C-TDEV disabled.\n")));
    634         }
    635         return BCM_E_NONE;
    636     }
    637 
    638     /*
    639      * Advance cursor to data.
    640      * Higher-level callers vetted event type.
    641      * Only one TDEV event subtype at present.
    642      *
    643      * MESSAGE FORMAT:
    644      *     Octet 0:1 : Event type (TDEV event).
    645      *     Octet 2   : TDEV event subtype (frequency correction data).
    646      *     Octet 3   : Number of frequency correction data elements.
    647      *     Octet 4+8(N-1):4+8*N: Frequency correction entry N, parts per trillion.
    648      */
    649     cursor = 3;
    650     numel = ev_data[cursor++];
    651 
    652     while (numel--) {
    653         freq_corr_ppt = _bcm_ptp_int64_read(ev_data+cursor);
    654         cursor += sizeof(int64);
    655 
    656         if (BCM_FAILURE(rv = _bcm_ptp_ctdev_phase_accumulator(unit, ptp_id,
    657                 clock_num, freq_corr_ppt))) {
    658             PTP_ERROR_FUNC("_bcm_ptp_ctdev_phase_accumulator()");
    659             return rv;
    660         }
    661         if (BCM_FAILURE(rv = _bcm_ptp_ctdev_calculator(unit, ptp_id, clock_num))) {
    662             PTP_ERROR_FUNC("_bcm_ptp_ctdev_calculator()");
    663             return rv;
    664         }
    665 
    666         /* C-TDEV alarm. */
    667         ctdev_alarm_data.elapsed_sec += PTP_CTDEV_TAU0_SEC;
    668         if (ctdev_alarm_fcn) {
    669             COMPILER_64_SET(ctdev_alarm_data.freq_corr_ppt, COMPILER_64_HI(freq_corr_ppt), COMPILER_64_LO(freq_corr_ppt));
    670             /* ctdev_alarm_data.freq_corr_ppt = freq_corr_ppt; */
    671             ctdev_alarm_data.num_tau = PTP_CTDEV_NUM_TIMESCALES;
    672             for (i = 0; i < PTP_CTDEV_NUM_TIMESCALES; ++i) {
    673                 ctdev_alarm_data.tau_sec[i] = ctdev_array.entry[i].tau;
    674                 ctdev_alarm_data.tdev_psec[i] = ctdev_array.entry[i].tdev_psec;
    675             }
    676             /* Pass copy of alarm data to protect core data reused in recursive calculations. */
    677             ctdev_alarm_data_copy = ctdev_alarm_data;
    678             ctdev_alarm_fcn(unit, ptp_id, clock_num, &ctdev_alarm_data_copy);
    679         }
    680 
    681         if (ctdev_options.verbose) {
    682             /*
    683              * Display comma-delimited frequency correction and C-TDEV(tau).
    684              * NOTE: Printout assumes 12 timescales  are enabled/calculated.
    685              */
    686             /*
    687             LOG_CLI((BSL_META_U(unit,
    688                                 "%u,%lld,%llu,%llu,%llu,%llu,%llu,%llu,"
    689                                 "%llu,%llu,%llu,%llu,%llu,%llu\n"),
    690                      (unsigned)sal_time(), freq_corr_ppt,
    691                      (long long unsigned)ctdev_array.entry[0].tdev_psec,
    692                      (long long unsigned)ctdev_array.entry[1].tdev_psec,
    693                      (long long unsigned)ctdev_array.entry[2].tdev_psec,
    694                      (long long unsigned)ctdev_array.entry[3].tdev_psec,
    695                      (long long unsigned)ctdev_array.entry[4].tdev_psec,
    696                      (long long unsigned)ctdev_array.entry[5].tdev_psec,
    697                      (long long unsigned)ctdev_array.entry[6].tdev_psec,
    698                      (long long unsigned)ctdev_array.entry[7].tdev_psec,
    699                      (long long unsigned)ctdev_array.entry[8].tdev_psec,
    700                      (long long unsigned)ctdev_array.entry[9].tdev_psec,
    701                      (long long unsigned)ctdev_array.entry[10].tdev_psec,
    702                      (long long unsigned)ctdev_array.entry[11].tdev_psec));
    703              */
    704         }
    705     }
    706 
    707     return BCM_E_NONE;
    708 }
    709 
    710 /*
    711  * Function:
    712  *      _bcm_ptp_ctdev_phase_accumulator
    713  * Purpose:
    714  *      Update C-TDEV phase accumulator with frequency correction data.
    715  * Parameters:
    716  *      unit          - (IN) Unit number.
    717  *      ptp_id        - (IN) PTP stack ID.
    718  *      clock_num     - (IN) PTP clock number.
    719  *      freq_corr_ppt - (IN) Frequency correction (parts per trillion).
    720  * Returns:
    721  *      BCM_E_XXX - Function status.
    722  * Notes:
    723  */
    724 int
    725 _bcm_ptp_ctdev_phase_accumulator(
    726     int unit,
    727     bcm_ptp_stack_id_t ptp_id,
    728     int clock_num,
    729     const int64 freq_corr_ppt)
    730 {
    731     eltype_t qval;
    732 
    733     if (0 == ctdev_options.enable) {
    734         /* C-TDEV disabled. */
    735         if (ctdev_options.verbose) {
    736             LOG_CLI((BSL_META_U(unit,
    737                                 "_bcm_ptp_ctdev_phase_accumulator(): "
    738                                 "C-TDEV disabled.\n")));
    739         }
    740         return BCM_E_NONE;
    741     }
    742 
    743     PTP_CTDEV_MUTEX_TAKE();
    744 
    745     /* Phase accumulator incl. wrapping. */
    746     phase_err_psec += COMPILER_64_LO(freq_corr_ppt)*PTP_CTDEV_TAU0_SEC;
    747     if (phase_err_psec > PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC) {
    748         phase_err_psec -= (PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC << 1);
    749         ++wrap_counter;
    750     }
    751     if (phase_err_psec < -PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC) {
    752         phase_err_psec += (PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC << 1);
    753         --wrap_counter;
    754     }
    755 
    756     /* Enqueue. */
    757     qval.value = phase_err_psec;
    758     _bcm_ptp_circular_buffer_write(&ctdev_array.phase_buffer, &qval);
    759 
    760     qval.value = wrap_counter;
    761     _bcm_ptp_circular_buffer_write(&ctdev_array.wrap_buffer, &qval);
    762 
    763     PTP_CTDEV_MUTEX_RELEASE_RETURN(BCM_E_NONE);
    764 }
    765 
    766 /*
    767  * Function:
    768  *      _bcm_ptp_ctdev_calculator
    769  * Purpose:
    770  *      Calculate C-TDEV metric over relevant timescales.
    771  * Parameters:
    772  *      unit      - (IN) Unit number.
    773  *      ptp_id    - (IN) PTP stack ID.
    774  *      clock_num - (IN) PTP clock number.
    775  * Returns:
    776  *      BCM_E_XXX - Function status.
    777  * Notes:
    778  */
    779 int
    780 _bcm_ptp_ctdev_calculator(
    781     int unit,
    782     bcm_ptp_stack_id_t ptp_id,
    783     int clock_num)
    784 {
    785     int i;
    786 
    787     eltype_t pval;
    788     eltype_t qval;
    789     eltype_t wval;
    790     int32 dA;
    791     int32 dB;
    792     int32 dw;
    793 
    794     uint32 Sovh, dSl, dSh;
    795     uint32 fpbit_prior, fpbit_maxSov;
    796 
    797     _bcm_ptp_ctdev_t *ctdev;
    798 
    799     pval.value = 0;
    800 
    801     if (0 == ctdev_options.enable) {
    802         /* C-TDEV disabled. */
    803         if (ctdev_options.verbose) {
    804             LOG_CLI((BSL_META_U(unit,
    805                                 "_bcm_ptp_ctdev_calculator(): C-TDEV disabled.\n")));
    806         }
    807         return BCM_E_NONE;
    808     }
    809 
    810     PTP_CTDEV_MUTEX_TAKE();
    811 
    812     /* Dequeue. */
    813     _bcm_ptp_circular_buffer_read(&ctdev_array.phase_buffer, &qval);
    814     _bcm_ptp_circular_buffer_read(&ctdev_array.wrap_buffer, &wval);
    815 
    816     for (i = 0; i < PTP_CTDEV_NUM_TIMESCALES; ++i) {
    817         /* Set active C-TDEV(tau). */
    818         ctdev = &ctdev_array.entry[i];
    819 
    820         /*
    821          * Calculate S.
    822          * S = S + 3 dA + dB.
    823          *
    824          * NB: S is a second derivative of the phase deviations. C-TDEV calculates
    825          *     S via accumulation of O(1) backward finite difference approximations
    826          *     of the third derivative.
    827          */
    828 
    829         /* Assemble difference terms (dA,dB). */
    830         _bcm_ptp_circular_buffer_peekn(&ctdev_array.phase_buffer, 2*ctdev->m, &pval);
    831         dA = pval.value;
    832         _bcm_ptp_circular_buffer_peekn(&ctdev_array.phase_buffer, ctdev->m, &pval);
    833         dA -= pval.value;
    834 
    835         _bcm_ptp_circular_buffer_peekn(&ctdev_array.phase_buffer, 3*ctdev->m, &pval);
    836         dB = qval.value - pval.value;
    837 
    838         COMPILER_64_ADD_32(ctdev->dS, dA);
    839         COMPILER_64_ADD_32(ctdev->dS, dA);
    840         COMPILER_64_ADD_32(ctdev->dS, dA);
    841         COMPILER_64_ADD_32(ctdev->dS, dB);
    842 
    843         /* Account for phase wrapping effects in (dA,dB) terms. */
    844         dw = wval.value;
    845         _bcm_ptp_circular_buffer_peekn(&ctdev_array.wrap_buffer, ctdev->m, &pval);
    846         dw -= (3*pval.value);
    847         _bcm_ptp_circular_buffer_peekn(&ctdev_array.wrap_buffer, 2*ctdev->m, &pval);
    848         dw += (3*pval.value);
    849         _bcm_ptp_circular_buffer_peekn(&ctdev_array.wrap_buffer, 3*ctdev->m, &pval);
    850         dw -= pval.value;
    851 
    852         if (dw > 0) {
    853             while (dw--) {
    854                 COMPILER_64_ADD_32(ctdev->dS, (PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC << 1));
    855             }
    856         } else if (dw < 0) {
    857             while (dw++) {
    858                 COMPILER_64_SUB_32(ctdev->dS, (PTP_CTDEV_PHASE_ERROR_THRESHOLD_PSEC << 1));
    859             }
    860         }
    861 
    862         /* Calculate S^2. */
    863         COMPILER_64_ZERO(ctdev->dSsq);
    864         if (COMPILER_64_GE(ctdev->dS, zero64)) {
    865             COMPILER_64_ADD_64(ctdev->dSsq, ctdev->dS);
    866         } else {
    867             COMPILER_64_SUB_64(ctdev->dSsq, ctdev->dS);
    868         }
    869         /* NB: S^2 equals (S/tau)^2 in reference algorithm. */
    870         COMPILER_64_UDIV_16(ctdev->dSsq, ctdev->tau);
    871 
    872         /* Dynamic re-scaling. */
    873         if (1 == ctdev_options.dynamic_rescale) {
    874             fpbit_prior = ctdev->fpbit;
    875             ctdev->fpbit = 0;
    876             fpbit_maxSov = 31 - (fpbit_prior << 1);
    877             Sovh = COMPILER_64_HI(ctdev->Sov);
    878             dSl = COMPILER_64_LO(ctdev->dSsq);
    879             dSh = COMPILER_64_HI(ctdev->dSsq);
    880             while (Sovh > (1 << fpbit_maxSov) || (dSl > (1 << 31)) || (dSh > 0)) {
    881                 if (++ctdev->fpbit >= PTP_CTDEV_FIXEDPOINT_BIT_MAX) {
    882                     break;
    883                 }
    884                 if (dSh == 0) {
    885                     dSl >>= 1;
    886                 }
    887                 dSh >>= 1;
    888                 Sovh >>= 2;
    889             }
    890 
    891             if (ctdev->fpbit) {
    892                 COMPILER_64_UDIV_16(ctdev->dSsq, (1 << ctdev->fpbit));
    893             }
    894             if (ctdev->fpbit) {
    895                 COMPILER_64_UDIV_16(ctdev->Sov, (1 << ctdev->fpbit));
    896             }
    897             if (fpbit_prior) {
    898                 COMPILER_64_UMUL_32(ctdev->Sov, (1 << fpbit_prior));
    899             }
    900             if (ctdev->fpbit) {
    901                 COMPILER_64_UDIV_16(ctdev->Sov, (1 << ctdev->fpbit));
    902             }
    903             if (fpbit_prior) {
    904                 COMPILER_64_UMUL_32(ctdev->Sov, (1 << fpbit_prior));
    905             }
    906         }
    907 
    908         if (COMPILER_64_HI(ctdev->dSsq)) {
    909             /* Overflow. */
    910             PTP_CTDEV_MUTEX_RELEASE_RETURN(BCM_E_PARAM);
    911         }
    912         COMPILER_64_UMUL_32(ctdev->dSsq, COMPILER_64_LO(ctdev->dSsq));
    913 
    914         /*
    915          * Calculate Sov.
    916          * Sov = alpha Sov + S^2.
    917          */
    918         COMPILER_64_UDIV_16(ctdev->Sov, ctdev_parameters.alpha_denominator);
    919         COMPILER_64_UMUL_32(ctdev->Sov, ctdev_parameters.alpha_numerator);
    920         COMPILER_64_ADD_64(ctdev->Sov, ctdev->dSsq);
    921 
    922         /* Calculate time variance (TVAR). */
    923         ctdev->tvar = ctdev->Sov;
    924         COMPILER_64_UDIV_16(ctdev->tvar, 6);
    925         COMPILER_64_UDIV_16(ctdev->tvar, ctdev_parameters.keff_numerator);
    926         COMPILER_64_UMUL_32(ctdev->tvar, ctdev_parameters.keff_denominator);
    927 
    928         /* Calculate time deviation (TDEV). */
    929         COMPILER_64_ISQRT(ctdev->tdev, ctdev->tvar);
    930         COMPILER_64_SET(ctdev->tdev_psec, 0, ctdev->tdev);
    931         if ((1 == ctdev_options.dynamic_rescale) && ctdev->fpbit) {
    932             COMPILER_64_UMUL_32(ctdev->tdev_psec, (1 << ctdev->fpbit));
    933         }
    934     }
    935     PTP_CTDEV_MUTEX_RELEASE_RETURN(BCM_E_NONE);
    936 }
    937 
    938 /*
    939  * Function:
    940  *      _bcm_ptp_ctdev_get
    941  * Purpose:
    942  *      Get the C-TDEV metric for the specified timescale, if available.
    943  * Parameters:
    944  *      unit          - (IN)  Unit number.
    945  *      ptp_id        - (IN)  PTP stack ID.
    946  *      clock_num     - (IN)  PTP clock number.
    947  *      timescale_sec - (IN)  Timescale in seconds.
    948  *      tdev_psec     - (OUT) TDEV value.
    949  * Returns:
    950  *      BCM_E_XXX - Function status.
    951  * Notes:
    952  *      If the exact timescale is not available, the next larger one
    953  *      is returned.
    954  */
    955 int
    956 _bcm_ptp_ctdev_get(
    957     int unit,
    958     bcm_ptp_stack_id_t ptp_id,
    959     int clock_num,
    960     unsigned timescale_sec,
    961     uint64 *tdev_psec)
    962 {
    963     unsigned timescale_idx = 0;
    964 
    965     if (0 == ctdev_options.enable) {
    966         /* C-TDEV disabled. */
    967         if (ctdev_options.verbose) {
    968             LOG_CLI((BSL_META_U(unit,
    969                                 "_bcm_ptp_ctdev_get(): C-TDEV disabled.\n")));
    970         }
    971 
    972         return BCM_E_UNAVAIL;
    973     }
    974 
    975     PTP_CTDEV_MUTEX_TAKE();
    976 
    977     /* Find lg_2(timescale) */
    978     while (timescale_sec > PTP_CTDEV_TAU0_SEC) {
    979         ++timescale_idx;
    980         timescale_sec = timescale_sec / 2;
    981     }
    982 
    983     *tdev_psec = ctdev_array.entry[timescale_idx].tdev_psec;
    984 
    985     PTP_CTDEV_MUTEX_RELEASE_RETURN(BCM_E_NONE);
    986 }
    987 
    988 
    989 /*
    990  * Function:
    991  *      _bcm_ptp_llu_div
    992  * Purpose:
    993  *      Division of unsigned 64-bit quantity by unsigned 16-bit quantity.
    994  * Parameters:
    995  *      num - (IN) Numerator.
    996  *      den - (IN) Denominator.
    997  * Returns:
    998  *      Result, num / den.
    999  * Notes:
   1000  */
   1001 uint64
   1002 _bcm_ptp_llu_div(
   1003     uint64 num,
   1004     uint16 den)
   1005 {
   1006     int el;
   1007     uint16 numh[4];  /* Numerator as 16-bit half words. */
   1008     uint16 qh[4];    /* Quotient as 16-bit half-words. */
   1009     uint16 rhat = 0; /* Remainder. */
   1010 
   1011     uint32 Ql, Qh;
   1012     uint64 Q;
   1013 
   1014     numh[0] = (COMPILER_64_LO(num)) & 0xffff;
   1015     numh[1] = (COMPILER_64_LO(num) >> 16) & 0xffff;
   1016     numh[2] = (COMPILER_64_HI(num)) & 0xffff;
   1017     numh[3] = (COMPILER_64_HI(num) >> 16) & 0xffff;
   1018 
   1019     for (el = 3; el >= 0; --el) {
   1020         qh[el] = (rhat*65536 + numh[el])/(den);
   1021         rhat = (rhat*65536 + numh[el]) - qh[el]*(den);
   1022     }
   1023 
   1024     Ql = qh[0] + (qh[1] << 16);
   1025     Qh = qh[2] + (qh[3] << 16);
   1026     COMPILER_64_SET(Q, Qh, Ql);
   1027 
   1028     return Q;
   1029 }
   1030 
   1031 /*
   1032  * Function:
   1033  *      _bcm_ptp_llu_isqrt
   1034  * Purpose:
   1035  *      Integer square root of unsigned 64-bit quantity.
   1036  * Parameters:
   1037  *      x - (IN) Argument.
   1038  * Returns:
   1039  *      Result, isqrt(x).
   1040  * Notes:
   1041  */
   1042 uint32
   1043 _bcm_ptp_llu_isqrt(
   1044     uint64 x)
   1045 {
   1046     uint64 root, remainder, place, condval;
   1047 
   1048     remainder = x;
   1049     COMPILER_64_ZERO(root);
   1050     COMPILER_64_SET(place, 0x40000000, 0);
   1051 
   1052     while (COMPILER_64_GT(place, remainder)) {
   1053         COMPILER_64_UDIV_16(place, 4);
   1054     }
   1055 
   1056     while (!COMPILER_64_IS_ZERO(place)) {
   1057         condval = place;
   1058         COMPILER_64_ADD_64(condval, root);
   1059         if (COMPILER_64_GE(remainder, condval)) {
   1060             COMPILER_64_SUB_64(remainder, condval);
   1061             COMPILER_64_ADD_64(root, place);
   1062             COMPILER_64_ADD_64(root, place);
   1063         }
   1064         COMPILER_64_UDIV_16(root, 2);
   1065         COMPILER_64_UDIV_16(place, 4);
   1066     }
   1067     return COMPILER_64_LO(root);
   1068 }
   1069 
   1070 /*
   1071  * Function:
   1072  *      _bcm_ptp_xorshift_rand()
   1073  * Purpose:
   1074  *      Pseudorandom number generator based on xorshift algorithm with period 2^128 -1.
   1075  * Parameters:
   1076  *      None.
   1077  * Returns:
   1078  *      Result.
   1079  * Notes:
   1080  *      Ref. Marsaglia, G. (2003), Xorshift RNGs, Journal Statistical Software, 8, 1-9.
   1081  */
   1082 uint32
   1083 _bcm_ptp_xorshift_rand(
   1084     void)
   1085 {
   1086     static uint8 isseed;
   1087 
   1088     static uint32 x = 123456789;
   1089     static uint32 y = 362436069;
   1090     static uint32 z = 521288629;
   1091     static uint32 w = 88675123;
   1092 
   1093     uint32 t;
   1094 
   1095     /* Seed. */
   1096     if (0 == isseed) {
   1097         x = sal_time_usecs();
   1098         if (0 == x) {
   1099             x = 123456789;
   1100         }
   1101         isseed = 1;
   1102     }
   1103 
   1104     t = (x ^ (x << 11));
   1105     x = y; y = z; z = w;
   1106 
   1107     return ( w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)) );
   1108 }
   1109 
   1110 /*
   1111  * Function:
   1112  *      _bcm_ptp_ctdev_g823_mask
   1113  * Purpose:
   1114  *      Calculate ITU-T G.823 SEC TDEV mask.
   1115  * Parameters:
   1116  *      tau - (IN) Averaging time (sec).
   1117  * Returns:
   1118  *      ITU-T G.823 SEC TDEV mask value.
   1119  * Notes:
   1120  */
   1121 uint32
   1122 _bcm_ptp_ctdev_g823_mask(
   1123     int tau)
   1124 {
   1125     uint32 mask_psec = 0;
   1126     uint64 tau64;
   1127 
   1128     if (tau <= 17) {
   1129         /* NOTE: Actual cutoff is 17.14 sec. */
   1130         mask_psec = 12000;
   1131     } else if (tau <= 100) {
   1132         mask_psec = 700*tau;
   1133     } else {
   1134         /* NOTE: Equivalent scaling to increase precision of square-root result. */
   1135         COMPILER_64_SET(tau64, 0, 10000*tau);
   1136         COMPILER_64_ISQRT(mask_psec, tau64);
   1137         mask_psec *= 12;
   1138         mask_psec += 58000;
   1139         mask_psec += (3*tau)/10;
   1140     }
   1141 
   1142     return mask_psec;
   1143 }
   1144 
   1145 /*
   1146  * Function:
   1147  *      _bcm_ptp_circular_buffer_init
   1148  * Purpose:
   1149  *      Create and initialize a circular buffer.
   1150  * Parameters:
   1151  *      buffer - (IN) Circular buffer.
   1152  *      num_el - (IN) Number of buffer elements.
   1153  * Returns:
   1154  *      None.
   1155  * Notes:
   1156  */
   1157 static void
   1158 _bcm_ptp_circular_buffer_init(
   1159     _bcm_ptp_circular_buffer_t *buffer,
   1160     int num_el)
   1161 {
   1162     buffer->num_el = num_el;
   1163     buffer->num_write = 0;
   1164     buffer->num_read = 0;
   1165 
   1166     buffer->data = sal_alloc(buffer->num_el*sizeof(eltype_t),"ptp-circular-buffer");
   1167     sal_memset(buffer->data, 0, buffer->num_el*sizeof(eltype_t));
   1168 
   1169     buffer->read_el = buffer->data;
   1170     buffer->write_el = buffer->data;
   1171 }
   1172 
   1173 /*
   1174  * Function:
   1175  *      _bcm_ptp_circular_buffer_free
   1176  * Purpose:
   1177  *      Free circular buffer data memory.
   1178  * Parameters:
   1179  *      buffer - (IN) Circular buffer.
   1180  * Returns:
   1181  *      None.
   1182  * Notes:
   1183  */
   1184 static void
   1185 _bcm_ptp_circular_buffer_free(
   1186     _bcm_ptp_circular_buffer_t *buffer)
   1187 {
   1188     sal_free(buffer->data);
   1189 }
   1190 
   1191 /*
   1192  * Function:
   1193  *      _bcm_ptp_circular_buffer_write
   1194  * Purpose:
   1195  *      Enqueue; write data to circular buffer.
   1196  * Parameters:
   1197  *      buffer - (IN) Circular buffer.
   1198  *      value  - (IN) Data.
   1199  * Returns:
   1200  *      None.
   1201  * Notes:
   1202  */
   1203 static void
   1204 _bcm_ptp_circular_buffer_write(
   1205     _bcm_ptp_circular_buffer_t *buffer,
   1206     eltype_t *value)
   1207 {
   1208     *(buffer->write_el++) = *value;
   1209     if (buffer->write_el == buffer->data + buffer->num_el) {
   1210         buffer->write_el = buffer->data;
   1211     }
   1212     buffer->num_write++;
   1213 }
   1214 
   1215 /*
   1216  * Function:
   1217  *      _bcm_ptp_circular_buffer_read
   1218  * Purpose:
   1219  *      Dequeue; read data from circular buffer.
   1220  * Parameters:
   1221  *      buffer - (IN)  Circular buffer.
   1222  *      value  - (OUT) Data.
   1223  * Returns:
   1224  *      None.
   1225  * Notes:
   1226  */
   1227 static void
   1228 _bcm_ptp_circular_buffer_read(
   1229     _bcm_ptp_circular_buffer_t *buffer,
   1230     eltype_t *value)
   1231 {
   1232     *value = *(buffer->read_el++);
   1233     if (buffer->read_el == buffer->data + buffer->num_el) {
   1234         buffer->read_el = buffer->data;
   1235     }
   1236     buffer->num_read++;
   1237 }
   1238 
   1239 #if 0  /* Unused. Preserve for future use. */
   1240 /*
   1241  * Function:
   1242  *      _bcm_ptp_circular_buffer_peek
   1243  * Purpose:
   1244  *      Peek at most recent value written to buffer.
   1245  * Parameters:
   1246  *      buffer - (IN)  Circular buffer.
   1247  *      value  - (OUT) Data.
   1248  * Returns:
   1249  *      None.
   1250  * Notes:
   1251  */
   1252 static void
   1253 _bcm_ptp_circular_buffer_peek(
   1254     _bcm_ptp_circular_buffer_t *buffer,
   1255     eltype_t *value)
   1256 {
   1257     *value = (buffer->write_el == buffer->data) ?
   1258              *(buffer->write_el + buffer->num_el - 1) : *(buffer->write_el - 1);
   1259 }
   1260 #endif /* 0 */
   1261 
   1262 /*
   1263  * Function:
   1264  *      _bcm_ptp_circular_buffer_peekn
   1265  * Purpose:
   1266  *      Peek at prior value written to buffer.
   1267  * Parameters:
   1268  *      buffer - (IN)  Circular buffer.
   1269  *      n      - (IN)  Relative position of prior value (as positive index).
   1270  *      value  - (OUT) Data.
   1271  * Returns:
   1272  *      None.
   1273  * Notes:
   1274  */
   1275 static void
   1276 _bcm_ptp_circular_buffer_peekn(
   1277     _bcm_ptp_circular_buffer_t *buffer,
   1278     int n,
   1279     eltype_t *value)
   1280 {
   1281     if (n >= buffer->num_el) {
   1282         /* Peek index exceeds maximum allowed index based on buffer size. */
   1283         return;
   1284     } else if (n >= buffer->write_el - buffer->data) {
   1285         *value = *(buffer->write_el + buffer->num_el - n - 1);
   1286     } else {
   1287         *value = *(buffer->write_el - n - 1);
   1288     }
   1289 }
   1290 
   1291 #endif /* defined(INCLUDE_PTP) */