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) */