tdpll_inputs.c (95383B)
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: tdpll_inputs.c 8 * 9 * Purpose: Telecom DPLL input clock monitoring, reference selection, and switching. 10 * 11 * Functions: 12 * bcm_tdpll_input_clock_init 13 * bcm_tdpll_input_clock_shutdown 14 * bcm_tdpll_input_clock_control 15 * bcm_tdpll_input_clock_port_lookup 16 * bcm_tdpll_input_clock_mac_lookup 17 * bcm_tdpll_input_clock_mac_get 18 * bcm_tdpll_input_clock_mac_set 19 * bcm_tdpll_input_clock_reference_mac_get 20 * bcm_tdpll_input_clock_frequency_error_get 21 * bcm_tdpll_input_clock_threshold_state_get 22 * bcm_tdpll_input_clock_enable_get 23 * bcm_tdpll_input_clock_enable_set 24 * bcm_tdpll_input_clock_l1mux_get 25 * bcm_tdpll_input_clock_l1mux_set 26 * bcm_tdpll_input_clock_valid_get 27 * bcm_tdpll_input_clock_valid_set 28 * bcm_tdpll_input_clock_dpll_use_get 29 * bcm_tdpll_input_clock_dpll_use_set 30 * bcm_tdpll_input_clock_frequency_get 31 * bcm_tdpll_input_clock_frequency_set 32 * bcm_tdpll_input_clock_ql_get 33 * bcm_tdpll_input_clock_ql_set 34 * bcm_tdpll_input_clock_priority_get 35 * bcm_tdpll_input_clock_priority_set 36 * bcm_tdpll_input_clock_lockout_get 37 * bcm_tdpll_input_clock_lockout_set 38 * bcm_tdpll_input_clock_monitor_interval_get 39 * bcm_tdpll_input_clock_monitor_interval_set 40 * bcm_tdpll_input_clock_monitor_threshold_get 41 * bcm_tdpll_input_clock_monitor_threshold_set 42 * bcm_tdpll_input_clock_ql_enabled_get 43 * bcm_tdpll_input_clock_ql_enabled_set 44 * bcm_tdpll_input_clock_revertive_get 45 * bcm_tdpll_input_clock_revertive_set 46 * bcm_tdpll_input_clock_best_get 47 * bcm_tdpll_input_clock_dpll_reference_get 48 * bcm_tdpll_input_clock_monitor_callback_register 49 * bcm_tdpll_input_clock_monitor_callback_unregister 50 * bcm_tdpll_input_clock_selector_callback_register 51 * bcm_tdpll_input_clock_selector_callback_unregister 52 * bcm_common_tdpll_input_clock_callback_register 53 * bcm_common_tdpll_input_clock_callback_unregister 54 * 55 * bcm_tdpll_input_clock_state_machine 56 * bcm_tdpll_input_clock_reference_selector 57 * bcm_tdpll_input_clock_monitor_gateway 58 * bcm_tdpll_input_clock_monitor_data_get 59 * bcm_tdpll_input_clock_monitor_calc 60 * bcm_tdpll_input_clock_monitor_eval 61 */ 62 63 #if defined(INCLUDE_PTP) 64 65 #include <shared/bsl.h> 66 #include <shared/util.h> 67 68 #include <bcm/ptp.h> 69 #include <bcm_int/common/ptp.h> 70 #include <bcm_int/ptp_common.h> 71 #include <bcm/error.h> 72 73 /* Definitions. */ 74 #define TDPLL_USEC_PER_SEC (1000000) 75 #define TDPLL_NSEC_PER_SEC (1000000000) 76 77 #define TDPLL_ESMC_FAILURE_TIMEOUT_SEC (5) 78 79 #define TDPLL_MONITOR_INTERVAL_SEC_MIN (4) 80 #define TDPLL_MONITOR_INTERVAL_SEC_MAX (2048) 81 #define TDPLL_MONITOR_INTERVAL_SEC_DEFAULT (32) 82 83 #define TDPLL_ALARM_SOFT_WARN_THRESHOLD_PPB (8000) 84 #define TDPLL_ALARM_HARD_ACCEPT_THRESHOLD_PPB (9000) 85 #define TDPLL_ALARM_HARD_REJECT_THRESHOLD_PPB (12000) 86 87 #define TDPLL_FREQUENCY_ERROR_MAX_PPB (1000000000) 88 89 #define TDPLL_STATE_MACHINE_DPC_TIME_USEC_DEFAULT (1000000) 90 #define TDPLL_STATE_MACHINE_DPC_TIME_USEC_IDLE (10000000) 91 92 #define TDPLL_INPUT_L1MUX_NUM_MAX (2) 93 94 #define TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT (0u) 95 #define TDPLL_INPUT_CLOCK_STATE_TSAVAIL_BIT (1u) 96 #define TDPLL_INPUT_CLOCK_STATE_VALID_BIT (2u) 97 #define TDPLL_INPUT_CLOCK_STATE_QL_DNU_BIT (3u) 98 99 #define INPUT_CLOCK(clock_index) \ 100 (objdata.input_clock[clock_index]) 101 102 #define INPUT_CLOCK_BEST(dpll_index) \ 103 (objdata.input_clock[objdata.selector_state.selected_clock[dpll_index]]) 104 105 #define INPUT_CLOCK_ACTIVE(dpll_index) \ 106 (objdata.input_clock[objdata.selector_state.reference_clock[dpll_index]]) 107 108 #define INPUT_CLOCK_DPLL_REF(dpll_index) \ 109 (objdata.selector_state.reference_clock[dpll_index]) 110 111 #if defined(BCM_SABER2_SUPPORT) 112 #define SB2_EPHY_CLKSEL (30) 113 #define EPHY_PORT_MAP(i,L1MuxPort,phy_port,port) \ 114 /* ext.PHY 25MHz recovered clock,check SB2 top spec for lane info */\ 115 if(SB2_EPHY_CLKSEL==L1MuxPort) {\ 116 port = phy_port; /*PHY port used for L1 clk recovery*/\ 117 } else { /* SB2 without ext.PHY L1 recovery support */\ 118 port = L1MuxPort+1;\ 119 } 120 #endif /*BCM_SABER2_SUPPORT*/ 121 122 /* Macros. */ 123 124 /* Types. */ 125 126 /* Constants and variables. */ 127 static bcm_tdpll_input_clock_data_t objdata; 128 static shr_rdpc_t tdpll_input_clock_state_machine_rdpc; 129 130 /* Static functions. */ 131 static sal_usecs_t bcm_tdpll_input_clock_state_machine( 132 void **arg_unit, void **arg_stack_id, 133 void **unused0, void **unused1); 134 135 static int bcm_tdpll_input_clock_esmc_timeout( 136 int unit, int stack_id); 137 138 static int bcm_tdpll_input_clock_reference_selector( 139 int dpll_index); 140 141 static int bcm_tdpll_input_clock_monitor_gateway( 142 int unit, int stack_id); 143 144 static int bcm_tdpll_input_clock_monitor_data_get( 145 int unit, int stack_id); 146 147 static int bcm_tdpll_input_clock_monitor_calc( 148 int unit, int stack_id, 149 bcm_tdpll_input_clock_t *input_clock); 150 151 static int bcm_tdpll_input_clock_monitor_eval( 152 int unit, int stack_id, 153 bcm_tdpll_input_clock_t *input_clock); 154 155 156 /* 157 * Function: 158 * bcm_tdpll_input_clock_init() 159 * Purpose: 160 * Initialize T-DPLL input clock functionality. 161 * Parameters: 162 * unit - (IN) Unit number. 163 * stack_id - (IN) Stack identifier index. 164 * Returns: 165 * BCM_E_XXX - Function status. 166 * Notes: 167 */ 168 int 169 bcm_tdpll_input_clock_init( 170 int unit, 171 int stack_id) 172 { 173 int i; 174 int dpll_index; 175 176 if (shr_rdpc_callback_created(&tdpll_input_clock_state_machine_rdpc) == BCM_E_INIT) { 177 /* RDPC (and associated lock) is left in place on cleanup, so only create it once */ 178 shr_rdpc_callback_create(&tdpll_input_clock_state_machine_rdpc, &bcm_tdpll_input_clock_state_machine); 179 } 180 181 /* INPUT CLOCK MONITORING. */ 182 183 /* Set default monitoring parameters and thresholds. */ 184 objdata.monitor_options.interval = TDPLL_MONITOR_INTERVAL_SEC_DEFAULT; 185 objdata.monitor_options.soft_warn_threshold_ppb = TDPLL_ALARM_SOFT_WARN_THRESHOLD_PPB; 186 objdata.monitor_options.hard_accept_threshold_ppb = TDPLL_ALARM_HARD_ACCEPT_THRESHOLD_PPB; 187 objdata.monitor_options.hard_reject_threshold_ppb = TDPLL_ALARM_HARD_REJECT_THRESHOLD_PPB; 188 189 /* Monitor callback. */ 190 objdata.monitor_callback = NULL; 191 192 objdata.callback[bcmTdpllCallbackTypeMonitor] = NULL; 193 objdata.callback[bcmTdpllCallbackTypeSelector] = NULL; 194 objdata.callback[bcmTdpllCallbackTypeNotification] = NULL; 195 196 /*Initialize input clock attributes. */ 197 for (i = 0; i < TDPLL_INPUT_CLOCK_NUM_MAX; ++i) { 198 /* Identification attributes. */ 199 INPUT_CLOCK(i).index = i; 200 sal_memset(INPUT_CLOCK(i).mac, 0, sizeof(bcm_mac_t)); 201 202 /* 203 * L1 mux port assignment. 204 * First SyncE clock mapped to primary L1 clock recovery mux. 205 * Other SyncE clocks mapped to backup L1 clock recovery mux. 206 */ 207 INPUT_CLOCK(i).l1mux.index = (i <= TDPLL_INPUT_CLOCK_NUM_GPIO) ? 0:1; 208 INPUT_CLOCK(i).l1mux.port = 0; 209 210 /* DPLL instance assignments. */ 211 for (dpll_index = 0; dpll_index < TDPLL_DPLL_INSTANCE_NUM_MAX; ++dpll_index) { 212 INPUT_CLOCK(i).dpll_use[dpll_index] = 0; 213 } 214 215 /* Clock frequency and TS EVENT (timestamp) frequency. */ 216 INPUT_CLOCK(i).frequency.clock = 0; 217 INPUT_CLOCK(i).frequency.tsevent = 0; 218 INPUT_CLOCK(i).frequency.tsevent_quotient = -1; 219 220 /* State. */ 221 INPUT_CLOCK(i).state = 0; 222 223 /* Monitor. */ 224 INPUT_CLOCK(i).monitor.over_soft_warn_threshold = 0; 225 INPUT_CLOCK(i).monitor.under_hard_accept_threshold = 0; 226 INPUT_CLOCK(i).monitor.over_hard_reject_threshold = 0; 227 228 COMPILER_64_SET(INPUT_CLOCK(i).monitor.dt_ns, 0, TDPLL_MONITOR_INTERVAL_SEC_DEFAULT); 229 COMPILER_64_UMUL_32(INPUT_CLOCK(i).monitor.dt_ns, TDPLL_NSEC_PER_SEC); 230 INPUT_CLOCK(i).monitor.dtref_ns = INPUT_CLOCK(i).monitor.dt_ns; 231 232 COMPILER_64_ZERO(INPUT_CLOCK(i).monitor.dt_sum_ns); 233 INPUT_CLOCK(i).monitor.dtref_sum_ns = INPUT_CLOCK(i).monitor.dt_sum_ns; 234 COMPILER_64_ZERO(INPUT_CLOCK(i).monitor.prior_evnum); 235 INPUT_CLOCK(i).monitor.numev_sum = 0; 236 237 INPUT_CLOCK(i).monitor.num_missing_tsevent = 0; 238 239 /* Reference selection. */ 240 INPUT_CLOCK(i).select.ql = bcm_esmc_g781_II_ql_dus; 241 INPUT_CLOCK(i).select.priority = i; 242 INPUT_CLOCK(i).select.lockout = 0; 243 } 244 245 246 /* REFERENCE SELECTION. */ 247 for (dpll_index = 0; dpll_index < TDPLL_DPLL_INSTANCE_NUM_MAX; ++dpll_index) { 248 /* Set default reference selection algorithm options per DPLL instance. */ 249 objdata.selector_options.ql_enabled[dpll_index] = 0; 250 251 /* Set selected input clocks for each DPLL instance. */ 252 objdata.selector_state.prior_selected_clock[dpll_index] = -1; 253 objdata.selector_state.selected_clock[dpll_index] = -1; 254 objdata.selector_state.reference_clock[dpll_index] = -1; 255 } 256 257 /* Reference selection callback. */ 258 objdata.selector_callback = NULL; 259 260 /* REFERENCE SWITCHING. */ 261 for (dpll_index = 0; dpll_index < TDPLL_DPLL_INSTANCE_NUM_MAX; ++dpll_index) { 262 /* Set default reference switching cotrol parameters. */ 263 objdata.switching_options.revertive[dpll_index] = 0; 264 } 265 266 return BCM_E_NONE; 267 } 268 269 /* 270 * Function: 271 * bcm_tdpll_input_clock_cleanup() 272 * Purpose: 273 * Uninitialize T-DPLL input clock functionality. 274 * Parameters: 275 * unit - (IN) Unit number. 276 * Returns: 277 * BCM_E_XXX - Function status. 278 * Notes: 279 */ 280 int 281 bcm_tdpll_input_clock_cleanup( 282 int unit) 283 { 284 return shr_rdpc_callback_stop(&tdpll_input_clock_state_machine_rdpc); 285 } 286 287 /* 288 * Function: 289 * bcm_tdpll_input_clock_control() 290 * Purpose: 291 * Start/stop T-DPLL input clock monitoring, reference selection, and switching 292 * state machine. 293 * Parameters: 294 * unit - (IN) Unit number. 295 * stack_id - (IN) Stack identifier index. 296 * enable - (IN) Enable Boolean. 297 * Returns: 298 * BCM_E_XXX - Function status. 299 * Notes: 300 */ 301 int 302 bcm_common_tdpll_input_clock_control( 303 int unit, 304 int stack_id, 305 int enable) 306 { 307 int rv; 308 if (enable) { 309 rv = shr_rdpc_callback_start(&tdpll_input_clock_state_machine_rdpc, TDPLL_STATE_MACHINE_DPC_TIME_USEC_DEFAULT, 310 INT_TO_PTR(unit), INT_TO_PTR(stack_id), 0, 0); 311 } else { 312 rv = shr_rdpc_callback_stop(&tdpll_input_clock_state_machine_rdpc); 313 } 314 315 return rv; 316 } 317 318 /* 319 * Function: 320 * bcm_tdpll_input_clock_port_lookup() 321 * Purpose: 322 * Look up a SyncE input clock by port number. 323 * Parameters: 324 * unit - (IN) Unit number. 325 * stack_id - (IN) Stack identifier index. 326 * port_num - (IN) Physical port number. 327 * clock_index - (OUT) Input clock index. 328 * Returns: 329 * BCM_E_XXX - Function status. 330 * Notes: 331 */ 332 int 333 bcm_tdpll_input_clock_port_lookup( 334 int unit, 335 int stack_id, 336 int port_num, 337 int *clock_index) 338 { 339 int el; 340 int logical_port_num = port_num - 1; 341 342 if (SOC_IS_QUX(unit) || SOC_IS_QAX(unit) || SOC_IS_QMX(unit)|| SOC_IS_GREYHOUND2(unit)) { 343 logical_port_num = port_num; 344 } 345 346 for (el = 0; el < TDPLL_INPUT_CLOCK_NUM_SYNCE; ++el) { 347 #if defined(BCM_SABER2_SUPPORT) 348 if(SB2_EPHY_CLKSEL==INPUT_CLOCK(el+TDPLL_INPUT_CLOCK_NUM_GPIO).l1mux.port) {/* ext.PHY 25MHz recovered clock,check SB2 top spec for lane info */ 349 *clock_index = el+TDPLL_INPUT_CLOCK_NUM_GPIO; 350 objdata.phy_port[el+TDPLL_INPUT_CLOCK_NUM_GPIO] = port_num; /*ext.PHY port mapped to SB2 port num */ 351 return BCM_E_NONE; 352 } 353 #endif 354 if (logical_port_num == INPUT_CLOCK(el+TDPLL_INPUT_CLOCK_NUM_GPIO).l1mux.port) { 355 /* 356 * Select SyncE input clock. 357 * ESMC PDU ingressed on physical port corresponding to L1 mux 358 * port for a SyncE input clock. 359 */ 360 *clock_index = el + TDPLL_INPUT_CLOCK_NUM_GPIO; 361 return BCM_E_NONE; 362 } 363 } 364 365 return BCM_E_NOT_FOUND; 366 } 367 368 /* 369 * Function: 370 * bcm_tdpll_input_clock_mac_lookup() 371 * Purpose: 372 * Look up an input clock by MAC address. 373 * Parameters: 374 * unit - (IN) Unit number. 375 * stack_id - (IN) Stack identifier index. 376 * mac - (IN) MAC address. 377 * clock_index - (OUT) Input clock index. 378 * Returns: 379 * BCM_E_XXX - Function status. 380 * Notes: 381 */ 382 int 383 bcm_tdpll_input_clock_mac_lookup( 384 int unit, 385 int stack_id, 386 bcm_mac_t *mac, 387 int *clock_index) 388 { 389 int el; 390 391 for (el = 0; el < TDPLL_INPUT_CLOCK_NUM_MAX; ++el) { 392 /* Scan input clock array for entry with matching MAC address. */ 393 if (0 == sal_memcmp(mac, INPUT_CLOCK(el).mac, sizeof(bcm_mac_t))) { 394 /* Select corresponding input clock. */ 395 *clock_index = el; 396 return BCM_E_NONE; 397 } 398 } 399 400 return BCM_E_NOT_FOUND; 401 } 402 403 /* 404 * Function: 405 * _bcm_common_tdpll_input_clock_index_validate() 406 * Purpose: 407 * Validate the TDPLL input clock index. 408 * Parameters: 409 * unit - (IN) Unit number. 410 * clock_index - (IN) Input clock index. 411 * Returns: 412 * BCM_E_XXX - Function status. 413 * Notes: 414 */ 415 416 static int 417 _bcm_common_tdpll_input_clock_index_validate ( 418 int unit, 419 int clock_index) 420 { 421 int rv = BCM_E_NONE; 422 423 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 424 return BCM_E_PARAM; 425 } 426 427 #if defined (BCM_QAX_SUPPORT) 428 if ((SOC_IS_QUX(unit) || SOC_IS_QAX(unit)) && 429 ((clock_index == TDPLL_INPUT_CLOCK_IDX_GPIO4) || 430 (clock_index == TDPLL_INPUT_CLOCK_IDX_GPIO5)) ) { 431 return BCM_E_PARAM; 432 } 433 #endif 434 return rv; 435 } 436 437 /* 438 * Function: 439 * bcm_tdpll_input_clock_mac_get() 440 * Purpose: 441 * Get MAC address of input clock. 442 * Parameters: 443 * unit - (IN) Unit number. 444 * stack_id - (IN) Stack identifier index. 445 * clock_index - (IN) Input clock index. 446 * mac - (OUT) Input clock MAC address. 447 * Returns: 448 * BCM_E_XXX - Function status. 449 * Notes: 450 */ 451 int 452 bcm_common_tdpll_input_clock_mac_get( 453 int unit, 454 int stack_id, 455 int clock_index, 456 bcm_mac_t *mac) 457 { 458 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 459 return BCM_E_PARAM; 460 } 461 462 sal_memcpy(mac, INPUT_CLOCK(clock_index).mac, sizeof(bcm_mac_t)); 463 return BCM_E_NONE; 464 } 465 466 /* 467 * Function: 468 * bcm_tdpll_input_clock_mac_set() 469 * Purpose: 470 * Set MAC address of input clock. 471 * Parameters: 472 * unit - (IN) Unit number. 473 * stack_id - (IN) Stack identifier index. 474 * clock_index - (IN) Input clock index. 475 * mac - (IN) Input clock MAC address. 476 * Returns: 477 * BCM_E_XXX - Function status. 478 * Notes: 479 */ 480 int 481 bcm_common_tdpll_input_clock_mac_set( 482 int unit, 483 int stack_id, 484 int clock_index, 485 bcm_mac_t *mac) 486 { 487 int rv = BCM_E_NONE; 488 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 489 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 490 return rv; 491 } 492 493 sal_memcpy(INPUT_CLOCK(clock_index).mac, mac, sizeof(bcm_mac_t)); 494 return BCM_E_NONE; 495 } 496 497 /* 498 * Function: 499 * bcm_tdpll_input_clock_reference_mac_get() 500 * Purpose: 501 * Get MAC address of current selected reference clock of DPLL instance. 502 * Parameters: 503 * unit - (IN) Unit number. 504 * stack_id - (IN) Stack identifier index. 505 * dpll_index - (IN) DPLL instance number. 506 * mac - (OUT) Input clock MAC address. 507 * Returns: 508 * BCM_E_XXX - Function status. 509 * Notes: 510 */ 511 int 512 bcm_tdpll_input_clock_reference_mac_get( 513 int unit, 514 int stack_id, 515 int dpll_index, 516 bcm_mac_t *mac) 517 { 518 int reference_index; 519 520 /* Argument checking and error handling. */ 521 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 522 return BCM_E_PARAM; 523 } 524 525 reference_index = objdata.selector_state.reference_clock[dpll_index]; 526 527 if (reference_index < 0 || reference_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 528 sal_memset(mac, 0, sizeof(bcm_mac_t)); 529 return BCM_E_PARAM; 530 } 531 532 sal_memcpy(mac, INPUT_CLOCK(reference_index).mac, sizeof(bcm_mac_t)); 533 return BCM_E_NONE; 534 } 535 536 /* 537 * Function: 538 * bcm_tdpll_input_clock_frequency_error_get() 539 * Purpose: 540 * Get fractional frequency error of an input clock from input-clock 541 * monitoring process. 542 * Parameters: 543 * unit - (IN) Unit number. 544 * stack_id - (IN) Stack identifier index. 545 * clock_index - (IN) Input clock index. 546 * freq_error_ppb - (OUT) Input clock fractional frequency error (ppb). 547 * Returns: 548 * BCM_E_XXX - Function status. 549 * Notes: 550 */ 551 int 552 bcm_common_tdpll_input_clock_frequency_error_get( 553 int unit, 554 int stack_id, 555 int clock_index, 556 int *freq_error_ppb) 557 { 558 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 559 return BCM_E_PARAM; 560 } 561 *freq_error_ppb = INPUT_CLOCK(clock_index).monitor.freq_error_ppb; 562 563 return BCM_E_NONE; 564 } 565 566 /* 567 * Function: 568 * bcm_tdpll_input_clock_threshold_state_get() 569 * Purpose: 570 * Get monitor threshold state of an input clock from input-clock 571 * monitoring process. 572 * Parameters: 573 * unit - (IN) Unit number. 574 * stack_id - (IN) Stack identifier index. 575 * clock_index - (IN) Input clock index. 576 * threshold_type - (IN) Input-clock monitoring threshold type. 577 * threshold_state - (OUT) Input-clock monitoring threshold state Boolean. 578 * Returns: 579 * BCM_E_XXX - Function status. 580 * Notes: 581 */ 582 int 583 bcm_common_tdpll_input_clock_threshold_state_get( 584 int unit, 585 int stack_id, 586 int clock_index, 587 bcm_tdpll_input_clock_monitor_type_t threshold_type, 588 int *threshold_state) 589 { 590 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 591 return BCM_E_PARAM; 592 } 593 594 switch (threshold_type) { 595 case bcm_tdpll_input_clock_monitor_type_soft_warn: 596 *threshold_state = INPUT_CLOCK(clock_index).monitor.over_soft_warn_threshold ? 1:0; 597 break; 598 case bcm_tdpll_input_clock_monitor_type_hard_accept: 599 *threshold_state = INPUT_CLOCK(clock_index).monitor.under_hard_accept_threshold ? 1:0; 600 break; 601 case bcm_tdpll_input_clock_monitor_type_hard_reject: 602 *threshold_state = INPUT_CLOCK(clock_index).monitor.over_hard_reject_threshold ? 1:0; 603 break; 604 default: 605 return BCM_E_PARAM; 606 } 607 608 return BCM_E_NONE; 609 } 610 611 /* 612 * Function: 613 * bcm_tdpll_input_clock_enable_get() 614 * Purpose: 615 * Get input clock enable Boolean. 616 * Parameters: 617 * unit - (IN) Unit number. 618 * stack_id - (IN) Stack identifier index. 619 * clock_index - (IN) Input clock index. 620 * enable - (OUT) Input clock enable Boolean. 621 * Returns: 622 * BCM_E_XXX - Function status. 623 * Notes: 624 */ 625 int 626 bcm_common_tdpll_input_clock_enable_get( 627 int unit, 628 int stack_id, 629 int clock_index, 630 int *enable) 631 { 632 int i; 633 int rv; 634 635 uint8 payload[PTP_MGMTMSG_PAYLOAD_INDEXED_PROPRIETARY_MSG_SIZE_OCTETS] = {0}; 636 uint8 resp[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_ENABLED_SIZE_OCTETS] = {0}; 637 int resp_len = PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_ENABLED_SIZE_OCTETS; 638 639 bcm_ptp_port_identity_t portid; 640 641 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 642 return BCM_E_PARAM; 643 } 644 645 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 646 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 647 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 648 return rv; 649 } 650 651 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 652 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 653 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 654 return rv; 655 } 656 657 /* Make indexed payload to get enable Boolean for specified input clock. */ 658 sal_memcpy(payload, "BCM\0\0\0", 6); 659 payload[6] = (uint8)clock_index; 660 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 661 &portid, PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_INPUT_CLOCK_ENABLED, 662 payload, PTP_MGMTMSG_PAYLOAD_INDEXED_PROPRIETARY_MSG_SIZE_OCTETS, 663 resp, &resp_len))) { 664 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 665 return rv; 666 } 667 668 /* 669 * Parse response. 670 * Octet 0...5 : Custom management message key/identifier. 671 * BCM<null><null><null>. 672 * Octet 6 : Input clock index. 673 * Octet 7 : Input clock enable Boolean. 674 */ 675 i = 6; /* Advance cursor past custom management message identifier. */ 676 ++i; /* Advance past input clock index. */ 677 678 *enable = resp[i] ? 1:0; 679 680 /* Set host-maintained input clock enable Boolean. */ 681 if (*enable) { 682 INPUT_CLOCK(clock_index).state |= (1 << TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT); 683 } else { 684 INPUT_CLOCK(clock_index).state &= ~(1 << TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT); 685 } 686 687 return BCM_E_NONE; 688 } 689 690 /* 691 * Function: 692 * bcm_tdpll_input_clock_enable_set() 693 * Purpose: 694 * Set input-clock enable Boolean. 695 * Parameters: 696 * unit - (IN) Unit number. 697 * stack_id - (IN) Stack identifier index. 698 * clock_index - (IN) Input clock index. 699 * enable - (IN) Input clock enable Boolean. 700 * Returns: 701 * BCM_E_XXX - Function status. 702 * Notes: 703 */ 704 int 705 bcm_common_tdpll_input_clock_enable_set( 706 int unit, 707 int stack_id, 708 int clock_index, 709 int enable) 710 { 711 int i; 712 int rv; 713 714 uint8 payload[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_ENABLED_SIZE_OCTETS] = {0}; 715 uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS]; 716 int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 717 718 bcm_ptp_port_identity_t portid; 719 720 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 721 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 722 return rv; 723 } 724 725 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 726 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 727 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 728 return rv; 729 } 730 731 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 732 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 733 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 734 return rv; 735 } 736 737 /* 738 * Make payload. 739 * Octet 0...5 : Custom management message key/identifier. 740 * BCM<null><null><null>. 741 * Octet 6 : Input clock index. 742 * Octet 7 : Input clock enable Boolean. 743 */ 744 sal_memcpy(payload, "BCM\0\0\0", 6); 745 i = 6; 746 payload[i++] = (uint8)clock_index; 747 payload[i] = enable ? 1:0; 748 749 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 750 &portid, PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_INPUT_CLOCK_ENABLED, 751 payload, PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_ENABLED_SIZE_OCTETS, 752 resp, &resp_len))) { 753 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 754 return rv; 755 } 756 757 /* Set host-maintained input clock enable Boolean. */ 758 if (enable) { 759 INPUT_CLOCK(clock_index).state |= (1 << TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT); 760 } else { 761 INPUT_CLOCK(clock_index).state &= ~(1 << TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT); 762 } 763 764 return BCM_E_NONE; 765 } 766 767 /* 768 * Function: 769 * bcm_tdpll_input_clock_l1mux_get() 770 * Purpose: 771 * Get L1 mux mapping (mux index and port number) of input clock. 772 * Parameters: 773 * unit - (IN) Unit number. 774 * stack_id - (IN) Stack identifier index. 775 * clock_index - (IN) Input clock index. 776 * l1mux - (OUT) L1 mux mapping. 777 * Returns: 778 * BCM_E_XXX - Function status. 779 * Notes: 780 */ 781 int 782 bcm_common_tdpll_input_clock_l1mux_get( 783 int unit, 784 int stack_id, 785 int clock_index, 786 bcm_tdpll_input_clock_l1mux_t *l1mux) 787 { 788 int i; 789 int rv; 790 791 uint8 payload[PTP_MGMTMSG_PAYLOAD_INDEXED_PROPRIETARY_MSG_SIZE_OCTETS] = {0}; 792 uint8 resp[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_L1MUX_SIZE_OCTETS] = {0}; 793 int resp_len = PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_L1MUX_SIZE_OCTETS; 794 795 bcm_ptp_port_identity_t portid; 796 797 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 798 return BCM_E_PARAM; 799 } 800 801 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 802 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 803 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 804 return rv; 805 } 806 807 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 808 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 809 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 810 return rv; 811 } 812 813 /* Make indexed payload to get L1 mux port number for specified input clock. */ 814 sal_memcpy(payload, "BCM\0\0\0", 6); 815 payload[6] = (uint8)clock_index; 816 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 817 &portid, PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_INPUT_CLOCK_L1MUX, 818 payload, PTP_MGMTMSG_PAYLOAD_INDEXED_PROPRIETARY_MSG_SIZE_OCTETS, 819 resp, &resp_len))) { 820 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 821 return rv; 822 } 823 824 /* 825 * Parse response. 826 * Octet 0...5 : Custom management message key/identifier. 827 * BCM<null><null><null>. 828 * Octet 6 : Input clock index. 829 * Octet 7 : L1 mux index. 830 * Octet 8 : L1 mux port number. 831 * Octet 9 : Reserved. 832 */ 833 i = 6; /* Advance cursor past custom management message identifier. */ 834 ++i; /* Advance past input clock index. */ 835 836 l1mux->index = (int)((int8)resp[i++]); 837 l1mux->port = (int)((int8)resp[i]); 838 839 /* Set host-maintained L1 mux and mux port number. */ 840 INPUT_CLOCK(clock_index).l1mux.index = l1mux->index; 841 INPUT_CLOCK(clock_index).l1mux.port = l1mux->port; 842 843 return BCM_E_NONE; 844 } 845 846 /* 847 * Function: 848 * bcm_tdpll_input_clock_l1mux_set() 849 * Purpose: 850 * Set L1 mux mapping (mux index and port number) of input clock. 851 * Parameters: 852 * unit - (IN) Unit number. 853 * stack_id - (IN) Stack identifier index. 854 * clock_index - (IN) Input clock index. 855 * l1mux - (IN) L1 mux mapping. 856 * Returns: 857 * BCM_E_XXX - Function status. 858 * Notes: 859 */ 860 int 861 bcm_common_tdpll_input_clock_l1mux_set( 862 int unit, 863 int stack_id, 864 int clock_index, 865 bcm_tdpll_input_clock_l1mux_t *l1mux) 866 { 867 int i; 868 int rv; 869 870 uint8 payload[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_L1MUX_SIZE_OCTETS] = {0}; 871 uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS]; 872 int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 873 874 bcm_ptp_port_identity_t portid; 875 876 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX || 877 l1mux->index < 0 || l1mux->index >= TDPLL_INPUT_L1MUX_NUM_MAX) { 878 return BCM_E_PARAM; 879 } 880 881 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 882 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 883 return rv; 884 } 885 886 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 887 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 888 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 889 return rv; 890 } 891 892 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 893 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 894 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 895 return rv; 896 } 897 898 /* 899 * Make payload. 900 * Octet 0...5 : Custom management message key/identifier. 901 * BCM<null><null><null>. 902 * Octet 6 : Input clock index. 903 * Octet 7 : L1 mux index. 904 * Octet 8 : L1 mux port number. 905 */ 906 sal_memcpy(payload, "BCM\0\0\0", 6); 907 i = 6; 908 payload[i++] = (uint8)clock_index; 909 payload[i++] = (uint8)l1mux->index; 910 payload[i++] = (uint8)l1mux->port; 911 payload[i] = 0; 912 913 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 914 &portid, PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_INPUT_CLOCK_L1MUX, 915 payload, PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_L1MUX_SIZE_OCTETS, 916 resp, &resp_len))) { 917 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 918 return rv; 919 } 920 921 /* Set host-maintained L1 mux and muport number. */ 922 INPUT_CLOCK(clock_index).l1mux.index = l1mux->index; 923 INPUT_CLOCK(clock_index).l1mux.port = l1mux->port; 924 925 return BCM_E_NONE; 926 } 927 928 /* 929 * Function: 930 * bcm_tdpll_input_clock_valid_get() 931 * Purpose: 932 * Get valid Boolean of an input clock from input-clock monitoring process. 933 * Parameters: 934 * unit - (IN) Unit number. 935 * stack_id - (IN) Stack identifier index. 936 * clock_index - (IN) Input clock index. 937 * valid - (OUT) Input clock valid Boolean. 938 * Returns: 939 * BCM_E_XXX - Function status. 940 * Notes: 941 */ 942 int 943 bcm_common_tdpll_input_clock_valid_get( 944 int unit, 945 int stack_id, 946 int clock_index, 947 int *valid) 948 { 949 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 950 return BCM_E_PARAM; 951 } 952 *valid = (INPUT_CLOCK(clock_index).state & (1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT)); 953 954 return BCM_E_NONE; 955 } 956 957 /* 958 * Function: 959 * bcm_tdpll_input_clock_valid_set() 960 * Purpose: 961 * Set input-clock valid Boolean from monitoring process. 962 * Parameters: 963 * unit - (IN) Unit number. 964 * stack_id - (IN) Stack identifier index. 965 * clock_index - (IN) Input clock index. 966 * valid - (IN) Input clock valid Boolean. 967 * Returns: 968 * BCM_E_XXX - Function status. 969 * Notes: 970 * Assignment is transient. Valid Boolean shall be reset by subsequent 971 * input-clock monitoring decision. 972 */ 973 int 974 bcm_common_tdpll_input_clock_valid_set( 975 int unit, 976 int stack_id, 977 int clock_index, 978 int valid) 979 { 980 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 981 return BCM_E_PARAM; 982 } 983 984 if (valid) { 985 INPUT_CLOCK(clock_index).state |= (1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT); 986 } else { 987 INPUT_CLOCK(clock_index).state &= ~(1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT); 988 } 989 990 return BCM_E_NONE; 991 } 992 993 /* 994 * Function: 995 * bcm_tdpll_input_clock_dpll_use_get() 996 * Purpose: 997 * Get input-clock DPLL-use/assignment Boolean for reference selection. 998 * Parameters: 999 * unit - (IN) Unit number. 1000 * stack_id - (IN) Stack identifier index. 1001 * clock_index - (IN) Input clock index. 1002 * dpll_index - (IN) DPLL instance number. 1003 * dpll_use - (OUT) DPLL-use Boolean. 1004 * Returns: 1005 * BCM_E_XXX - Function status. 1006 * Notes: 1007 * DPLL-use Boolean controls whether an input clock is used in reference 1008 * selection logic for logical DPLL instance. 1009 */ 1010 int 1011 bcm_tdpll_input_clock_dpll_use_get( 1012 int unit, 1013 int stack_id, 1014 int clock_index, 1015 int dpll_index, 1016 int *dpll_use) 1017 { 1018 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX || 1019 clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 1020 return BCM_E_PARAM; 1021 } 1022 *dpll_use = INPUT_CLOCK(clock_index).dpll_use[dpll_index] ? 1:0; 1023 1024 return BCM_E_NONE; 1025 } 1026 1027 /* 1028 * Function: 1029 * bcm_tdpll_input_clock_dpll_use_set() 1030 * Purpose: 1031 * Set input-clock DPLL-use/assignment Boolean for reference selection. 1032 * Parameters: 1033 * unit - (IN) Unit number. 1034 * stack_id - (IN) Stack identifier index. 1035 * clock_index - (IN) Input clock index. 1036 * dpll_index - (IN) DPLL instance number. 1037 * dpll_use - (IN) DPLL-use Boolean. 1038 * Returns: 1039 * BCM_E_XXX - Function status. 1040 * Notes: 1041 * DPLL-use Boolean controls whether an input clock is used in reference 1042 * selection logic for logical DPLL instance. 1043 */ 1044 int 1045 bcm_tdpll_input_clock_dpll_use_set( 1046 int unit, 1047 int stack_id, 1048 int clock_index, 1049 int dpll_index, 1050 int dpll_use) 1051 { 1052 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX || 1053 clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 1054 return BCM_E_PARAM; 1055 } 1056 INPUT_CLOCK(clock_index).dpll_use[dpll_index] = dpll_use ? 1:0; 1057 1058 return BCM_E_NONE; 1059 } 1060 1061 /* 1062 * Function: 1063 * bcm_tdpll_input_clock_frequency_get() 1064 * Purpose: 1065 * Get input clock frequency. 1066 * Parameters: 1067 * unit - (IN) Unit number. 1068 * stack_id - (IN) Stack identifier index. 1069 * clock_index - (IN) Input clock index. 1070 * clock_frequency - (OUT) Frequency (Hz). 1071 * tsevent_frequency - (OUT) TS event frequency (Hz). 1072 * Returns: 1073 * BCM_E_XXX - Function status. 1074 * Notes: 1075 */ 1076 int 1077 bcm_common_tdpll_input_clock_frequency_get( 1078 int unit, 1079 int stack_id, 1080 int clock_index, 1081 uint32 *clock_frequency, 1082 uint32 *tsevent_frequency) 1083 { 1084 int i; 1085 int rv; 1086 1087 uint8 payload[PTP_MGMTMSG_PAYLOAD_INDEXED_PROPRIETARY_MSG_SIZE_OCTETS] = {0}; 1088 uint8 resp[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_FREQUENCY_SIZE_OCTETS] = {0}; 1089 int resp_len = PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_FREQUENCY_SIZE_OCTETS; 1090 1091 bcm_ptp_port_identity_t portid; 1092 1093 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 1094 return BCM_E_PARAM; 1095 } 1096 1097 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 1098 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 1099 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 1100 return rv; 1101 } 1102 1103 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 1104 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 1105 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 1106 return rv; 1107 } 1108 1109 /* Make indexed payload to get frequency for specified input clock. */ 1110 sal_memcpy(payload, "BCM\0\0\0", 6); 1111 payload[6] = (uint8)clock_index; 1112 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 1113 &portid, PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_INPUT_CLOCK_FREQUENCY, 1114 payload, PTP_MGMTMSG_PAYLOAD_INDEXED_PROPRIETARY_MSG_SIZE_OCTETS, 1115 resp, &resp_len))) { 1116 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 1117 return rv; 1118 } 1119 1120 /* 1121 * Parse response. 1122 * Octet 0...5 : Custom management message key/identifier. 1123 * BCM<null><null><null>. 1124 * Octet 6 : Input clock index. 1125 * Octet 7 : Reserved. 1126 * Octet 8...11 : Frequency (Hz). 1127 * Octet 12...15 : TS event frequency (Hz). 1128 */ 1129 i = 6; /* Advance cursor past custom management message identifier. */ 1130 ++i; /* Advance past input clock index. */ 1131 ++i; /* Advance past reserved octet. */ 1132 1133 *clock_frequency = _bcm_ptp_uint32_read(resp + i); 1134 i += 4; 1135 *tsevent_frequency = _bcm_ptp_uint32_read(resp + i); 1136 1137 /* Set host-maintained input clock frequencies and ratio. */ 1138 INPUT_CLOCK(clock_index).frequency.clock = *clock_frequency; 1139 INPUT_CLOCK(clock_index).frequency.tsevent = *tsevent_frequency; 1140 INPUT_CLOCK(clock_index).frequency.tsevent_quotient = *tsevent_frequency ? 1141 (*clock_frequency + (*tsevent_frequency >> 1))/(*tsevent_frequency) : -1; 1142 1143 return BCM_E_NONE; 1144 } 1145 1146 /* 1147 * Function: 1148 * bcm_tdpll_input_clock_frequency_set() 1149 * Purpose: 1150 * Set input clock frequency. 1151 * Parameters: 1152 * unit - (IN) Unit number. 1153 * stack_id - (IN) Stack identifier index. 1154 * clock_index - (IN) Input clock index. 1155 * clock_frequency - (IN) Frequency (Hz). 1156 * tsevent_frequency - (IN) TS event frequency (Hz). 1157 * Returns: 1158 * BCM_E_XXX - Function status. 1159 * Notes: 1160 */ 1161 int 1162 bcm_common_tdpll_input_clock_frequency_set( 1163 int unit, 1164 int stack_id, 1165 int clock_index, 1166 uint32 clock_frequency, 1167 uint32 tsevent_frequency) 1168 { 1169 int i; 1170 int rv; 1171 1172 uint8 payload[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_FREQUENCY_SIZE_OCTETS] = {0}; 1173 uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS]; 1174 int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 1175 1176 bcm_ptp_port_identity_t portid; 1177 1178 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 1179 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 1180 return rv; 1181 } 1182 1183 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 1184 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 1185 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 1186 return rv; 1187 } 1188 1189 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 1190 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 1191 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 1192 return rv; 1193 } 1194 1195 /* 1196 * CONSTRAINT: TS event frequency is a multiple of 1 kHz / 100 Hz. 1197 * DPLL instances (and physical synthesizers bound to them) 1198 * operate at 1 kHz / 100 Hz. 1199 */ 1200 if ((0 == tsevent_frequency) || (tsevent_frequency % BCM_TDPLL_FREQUENCY)) { 1201 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1202 (BSL_META_U(unit, 1203 "TS EVENT frequency is not a multiple of %u Hz. fTS: %u\n"), 1204 (unsigned)BCM_TDPLL_FREQUENCY, (unsigned)tsevent_frequency)); 1205 return BCM_E_PARAM; 1206 } 1207 1208 /* 1209 * CONSTRAINT: TS event frequency and input clock frequency are integrally 1210 * related, N = f_clock / f_tsevent, such that TS events occur 1211 * at every Nth input clock edge. 1212 */ 1213 if ((0 == tsevent_frequency) || (clock_frequency % tsevent_frequency)) { 1214 LOG_VERBOSE(BSL_LS_BCM_COMMON, 1215 (BSL_META_U(unit, 1216 "CLOCK and TS EVENT frequencies are not integrally related. fCLK: %u fTS: %u"), 1217 (unsigned)clock_frequency, (unsigned)tsevent_frequency)); 1218 return BCM_E_PARAM; 1219 } 1220 1221 /* 1222 * Make payload. 1223 * Octet 0...5 : Custom management message key/identifier. 1224 * BCM<null><null><null>. 1225 * Octet 6 : Input clock index. 1226 * Octet 7 : Reserved. 1227 * Octet 8...11 : Frequency (Hz). 1228 * Octet 12...15 : TS event frequency (Hz). 1229 */ 1230 sal_memcpy(payload, "BCM\0\0\0", 6); 1231 i = 6; 1232 payload[i++] = (uint8)clock_index; 1233 payload[i++] = 0; 1234 1235 _bcm_ptp_uint32_write(payload+i, clock_frequency); 1236 i += 4; 1237 _bcm_ptp_uint32_write(payload+i, tsevent_frequency); 1238 1239 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 1240 &portid, PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_INPUT_CLOCK_FREQUENCY, 1241 payload, PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_FREQUENCY_SIZE_OCTETS, 1242 resp, &resp_len))) { 1243 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 1244 return rv; 1245 } 1246 1247 /* Set host-maintained input clock frequencies and ratio. */ 1248 INPUT_CLOCK(clock_index).frequency.clock = clock_frequency; 1249 INPUT_CLOCK(clock_index).frequency.tsevent = tsevent_frequency; 1250 INPUT_CLOCK(clock_index).frequency.tsevent_quotient = clock_frequency/tsevent_frequency; 1251 1252 return BCM_E_NONE; 1253 } 1254 1255 /* 1256 * Function: 1257 * bcm_tdpll_input_clock_ql_get() 1258 * Purpose: 1259 * Get input clock quality level (QL). 1260 * Parameters: 1261 * unit - (IN) Unit number. 1262 * stack_id - (IN) Stack identifier index. 1263 * clock_index - (IN) Input clock index. 1264 * ql - (OUT) QL. 1265 * Returns: 1266 * BCM_E_XXX - Function status. 1267 * Notes: 1268 */ 1269 int 1270 bcm_common_tdpll_input_clock_ql_get( 1271 int unit, 1272 int stack_id, 1273 int clock_index, 1274 bcm_esmc_quality_level_t *ql) 1275 { 1276 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 1277 return BCM_E_PARAM; 1278 } 1279 *ql = INPUT_CLOCK(clock_index).select.ql; 1280 1281 return BCM_E_NONE; 1282 } 1283 1284 /* 1285 * Function: 1286 * bcm_tdpll_input_clock_ql_set() 1287 * Purpose: 1288 * Set input clock quality level (QL). 1289 * Parameters: 1290 * unit - (IN) Unit number. 1291 * stack_id - (IN) Stack identifier index. 1292 * clock_index - (IN) Input clock index. 1293 * ql - (IN) QL. 1294 * Returns: 1295 * BCM_E_XXX - Function status. 1296 * Notes: 1297 */ 1298 int 1299 bcm_common_tdpll_input_clock_ql_set( 1300 int unit, 1301 int stack_id, 1302 int clock_index, 1303 bcm_esmc_quality_level_t ql) 1304 { 1305 int dpll_index; 1306 int rv = BCM_E_NONE; 1307 1308 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 1309 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 1310 return rv; 1311 } 1312 1313 INPUT_CLOCK(clock_index).select.ql = ql; 1314 1315 /* Transmit ESMC event PDU for DPLLs that use input clock as reference. */ 1316 for (dpll_index = 0; dpll_index < TDPLL_DPLL_INSTANCE_NUM_MAX; ++dpll_index) { 1317 if (clock_index == INPUT_CLOCK_DPLL_REF(dpll_index)) { 1318 bcm_tdpll_esmc_switch_event_send(unit, stack_id, dpll_index, ql); 1319 } 1320 } 1321 1322 return BCM_E_NONE; 1323 } 1324 1325 /* 1326 * Function: 1327 * bcm_tdpll_input_clock_priority_get() 1328 * Purpose: 1329 * Get input clock priority for reference selection. 1330 * Parameters: 1331 * unit - (IN) Unit number. 1332 * stack_id - (IN) Stack identifier index. 1333 * clock_index - (IN) Input clock index. 1334 * priority - (OUT) Input clock priority. 1335 * Returns: 1336 * BCM_E_XXX - Function status. 1337 * Notes: 1338 */ 1339 int 1340 bcm_common_tdpll_input_clock_priority_get( 1341 int unit, 1342 int stack_id, 1343 int clock_index, 1344 int *priority) 1345 { 1346 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 1347 return BCM_E_PARAM; 1348 } 1349 *priority = INPUT_CLOCK(clock_index).select.priority; 1350 1351 return BCM_E_NONE; 1352 } 1353 1354 /* 1355 * Function: 1356 * bcm_tdpll_input_clock_priority_set() 1357 * Purpose: 1358 * Set input clock priority for reference selection. 1359 * Parameters: 1360 * unit - (IN) Unit number. 1361 * stack_id - (IN) Stack identifier index. 1362 * clock_index - (IN) Input clock index. 1363 * priority - (IN) Input clock priority. 1364 * Returns: 1365 * BCM_E_XXX - Function status. 1366 * Notes: 1367 */ 1368 int 1369 bcm_common_tdpll_input_clock_priority_set( 1370 int unit, 1371 int stack_id, 1372 int clock_index, 1373 int priority) 1374 { 1375 int rv = BCM_E_NONE; 1376 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 1377 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 1378 return rv; 1379 } 1380 1381 INPUT_CLOCK(clock_index).select.priority = priority; 1382 1383 return BCM_E_NONE; 1384 } 1385 1386 /* 1387 * Function: 1388 * bcm_tdpll_input_clock_lockout_get() 1389 * Purpose: 1390 * Get input clock lockout Boolean for reference selection. 1391 * Parameters: 1392 * unit - (IN) Unit number. 1393 * stack_id - (IN) Stack identifier index. 1394 * clock_index - (IN) Input clock index. 1395 * lockout - (OUT) Input clock lockout Boolean. 1396 * Returns: 1397 * BCM_E_XXX - Function status. 1398 * Notes: 1399 */ 1400 int 1401 bcm_common_tdpll_input_clock_lockout_get( 1402 int unit, 1403 int stack_id, 1404 int clock_index, 1405 int *lockout) 1406 { 1407 if (clock_index < 0 || clock_index >= TDPLL_INPUT_CLOCK_NUM_MAX) { 1408 return BCM_E_PARAM; 1409 } 1410 *lockout = INPUT_CLOCK(clock_index).select.lockout; 1411 1412 return BCM_E_NONE; 1413 } 1414 1415 /* 1416 * Function: 1417 * bcm_tdpll_input_clock_lockout_set() 1418 * Purpose: 1419 * Set input clock lockout Boolean for reference selection. 1420 * Parameters: 1421 * unit - (IN) Unit number. 1422 * stack_id - (IN) Stack identifier index. 1423 * clock_index - (IN) Input clock index. 1424 * lockout - (IN) Input clock lockout Boolean. 1425 * Returns: 1426 * BCM_E_XXX - Function status. 1427 * Notes: 1428 */ 1429 int 1430 bcm_common_tdpll_input_clock_lockout_set( 1431 int unit, 1432 int stack_id, 1433 int clock_index, 1434 int lockout) 1435 { 1436 int rv = BCM_E_NONE; 1437 if (BCM_FAILURE(rv = _bcm_common_tdpll_input_clock_index_validate(unit, clock_index))) { 1438 PTP_ERROR_FUNC("_bcm_common_tdpll_input_clock_index_validate()"); 1439 return rv; 1440 } 1441 1442 INPUT_CLOCK(clock_index).select.lockout = lockout ? 1:0; 1443 1444 return BCM_E_NONE; 1445 } 1446 1447 /* 1448 * Function: 1449 * bcm_tdpll_input_clock_monitor_interval_get() 1450 * Purpose: 1451 * Get input clock monitoring interval. 1452 * Parameters: 1453 * unit - (IN) Unit number. 1454 * stack_id - (IN) Stack identifier index. 1455 * monitor_interval - (OUT) Input clock monitoring interval (sec). 1456 * Returns: 1457 * BCM_E_XXX - Function status. 1458 * Notes: 1459 * Monitoring interval defines the period over which fractional frequency error 1460 * of an input clock is calculated for purposes of threshold-based comparison / 1461 * validation. 1462 */ 1463 int 1464 bcm_common_tdpll_input_clock_monitor_interval_get( 1465 int unit, 1466 int stack_id, 1467 uint32 *monitor_interval) 1468 { 1469 *monitor_interval = objdata.monitor_options.interval; 1470 return BCM_E_NONE; 1471 } 1472 1473 /* 1474 * Function: 1475 * bcm_tdpll_input_clock_monitor_interval_set() 1476 * Purpose: 1477 * Set input clock monitoring interval. 1478 * Parameters: 1479 * unit - (IN) Unit number. 1480 * stack_id - (IN) Stack identifier index. 1481 * monitor_interval - (IN) Input clock monitoring interval (sec). 1482 * Returns: 1483 * BCM_E_XXX - Function status. 1484 * Notes: 1485 * Monitoring interval defines the period over which fractional frequency error 1486 * of an input clock is calculated for purposes of threshold-based comparison / 1487 * validation. 1488 */ 1489 int 1490 bcm_common_tdpll_input_clock_monitor_interval_set( 1491 int unit, 1492 int stack_id, 1493 uint32 monitor_interval) 1494 { 1495 monitor_interval = ((monitor_interval < TDPLL_MONITOR_INTERVAL_SEC_MIN) ? 1496 TDPLL_MONITOR_INTERVAL_SEC_MIN : 1497 (monitor_interval > TDPLL_MONITOR_INTERVAL_SEC_MAX) ? 1498 TDPLL_MONITOR_INTERVAL_SEC_MAX : monitor_interval); 1499 objdata.monitor_options.interval = monitor_interval; 1500 1501 return BCM_E_NONE; 1502 } 1503 1504 /* 1505 * Function: 1506 * bcm_tdpll_input_clock_monitor_threshold_get() 1507 * Purpose: 1508 * Get monitor threshold for input-clock valid classification required 1509 * in reference selection. 1510 * Parameters: 1511 * unit - (IN) Unit number. 1512 * stack_id - (IN) Stack identifier index. 1513 * threshold_type - (IN) Input clock monitoring threshold type. 1514 * threshold - (OUT) Input clock monitoring threshold (ppb). 1515 * Returns: 1516 * BCM_E_XXX - Function status. 1517 * Notes: 1518 */ 1519 int 1520 bcm_common_tdpll_input_clock_monitor_threshold_get( 1521 int unit, 1522 int stack_id, 1523 bcm_tdpll_input_clock_monitor_type_t threshold_type, 1524 uint32 *threshold) 1525 { 1526 switch (threshold_type) { 1527 case bcm_tdpll_input_clock_monitor_type_soft_warn: 1528 *threshold = objdata.monitor_options.soft_warn_threshold_ppb; 1529 break; 1530 case bcm_tdpll_input_clock_monitor_type_hard_accept: 1531 *threshold = objdata.monitor_options.hard_accept_threshold_ppb; 1532 break; 1533 case bcm_tdpll_input_clock_monitor_type_hard_reject: 1534 *threshold = objdata.monitor_options.hard_reject_threshold_ppb; 1535 break; 1536 default: 1537 return BCM_E_PARAM; 1538 } 1539 1540 return BCM_E_NONE; 1541 } 1542 1543 /* 1544 * Function: 1545 * bcm_tdpll_input_clock_monitor_threshold_set() 1546 * Purpose: 1547 * Set monitor threshold for input-clock valid classification required 1548 * in reference selection. 1549 * Parameters: 1550 * unit - (IN) Unit number. 1551 * stack_id - (IN) Stack identifier index. 1552 * threshold_type - (IN) Input-clock monitoring threshold type. 1553 * threshold - (IN) Input-clock monitoring threshold (ppb). 1554 * Returns: 1555 * BCM_E_XXX - Function status. 1556 * Notes: 1557 */ 1558 int 1559 bcm_common_tdpll_input_clock_monitor_threshold_set( 1560 int unit, 1561 int stack_id, 1562 bcm_tdpll_input_clock_monitor_type_t threshold_type, 1563 uint32 threshold) 1564 { 1565 switch (threshold_type) { 1566 case bcm_tdpll_input_clock_monitor_type_soft_warn: 1567 objdata.monitor_options.soft_warn_threshold_ppb = threshold; 1568 break; 1569 case bcm_tdpll_input_clock_monitor_type_hard_accept: 1570 objdata.monitor_options.hard_accept_threshold_ppb = threshold; 1571 break; 1572 case bcm_tdpll_input_clock_monitor_type_hard_reject: 1573 objdata.monitor_options.hard_reject_threshold_ppb = threshold; 1574 break; 1575 default: 1576 return BCM_E_PARAM; 1577 } 1578 1579 return BCM_E_NONE; 1580 } 1581 1582 /* 1583 * Function: 1584 * bcm_tdpll_input_clock_ql_enabled_get() 1585 * Purpose: 1586 * Get QL-enabled Boolean for reference selection. 1587 * Parameters: 1588 * unit - (IN) Unit number. 1589 * stack_id - (IN) Stack identifier index. 1590 * dpll_index - (IN) DPLL instance number. 1591 * ql_enabled - (OUT) QL-enabled Boolean. 1592 * Returns: 1593 * BCM_E_XXX - Function status. 1594 * Notes: 1595 */ 1596 int 1597 bcm_common_tdpll_input_clock_ql_enabled_get( 1598 int unit, 1599 int stack_id, 1600 int dpll_index, 1601 int *ql_enabled) 1602 { 1603 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 1604 return BCM_E_PARAM; 1605 } 1606 *ql_enabled = objdata.selector_options.ql_enabled[dpll_index] ? 1:0; 1607 1608 return BCM_E_NONE; 1609 } 1610 1611 /* 1612 * Function: 1613 * bcm_tdpll_input_clock_ql_enabled_set() 1614 * Purpose: 1615 * Set QL-enabled Boolean for reference selection. 1616 * Parameters: 1617 * unit - (IN) Unit number. 1618 * stack_id - (IN) Stack identifier index. 1619 * dpll_index - (IN) DPLL instance number. 1620 * ql_enabled - (IN) QL-enabled Boolean. 1621 * Returns: 1622 * BCM_E_XXX - Function status. 1623 * Notes: 1624 */ 1625 int 1626 bcm_common_tdpll_input_clock_ql_enabled_set( 1627 int unit, 1628 int stack_id, 1629 int dpll_index, 1630 int ql_enabled) 1631 { 1632 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 1633 return BCM_E_PARAM; 1634 } 1635 objdata.selector_options.ql_enabled[dpll_index] = ql_enabled ? 1:0; 1636 1637 return BCM_E_NONE; 1638 } 1639 1640 /* 1641 * Function: 1642 * bcm_tdpll_input_clock_revertive_get() 1643 * Purpose: 1644 * Get revertive mode Boolean for reference selection and switching. 1645 * Parameters: 1646 * unit - (IN) Unit number. 1647 * stack_id - (IN) Stack identifier index. 1648 * dpll_index - (IN) DPLL instance number. 1649 * revertive - (OUT) Revertive mode Boolean. 1650 * Returns: 1651 * BCM_E_XXX - Function status. 1652 * Notes: 1653 */ 1654 int 1655 bcm_common_tdpll_input_clock_revertive_get( 1656 int unit, 1657 int stack_id, 1658 int dpll_index, 1659 int *revertive) 1660 { 1661 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 1662 return BCM_E_PARAM; 1663 } 1664 *revertive = objdata.switching_options.revertive[dpll_index] ? 1:0; 1665 1666 return BCM_E_NONE; 1667 } 1668 1669 /* 1670 * Function: 1671 * bcm_tdpll_input_clock_revertive_set() 1672 * Purpose: 1673 * Set revertive mode Boolean for reference selection and switching. 1674 * Parameters: 1675 * unit - (IN) Unit number. 1676 * stack_id - (IN) Stack identifier index. 1677 * dpll_index - (IN) DPLL instance number. 1678 * revertive - (IN) Revertive mode Boolean. 1679 * Returns: 1680 * BCM_E_XXX - Function status. 1681 * Notes: 1682 */ 1683 int 1684 bcm_common_tdpll_input_clock_revertive_set( 1685 int unit, 1686 int stack_id, 1687 int dpll_index, 1688 int revertive) 1689 { 1690 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 1691 return BCM_E_PARAM; 1692 } 1693 objdata.switching_options.revertive[dpll_index] = revertive ? 1:0; 1694 1695 return BCM_E_NONE; 1696 } 1697 1698 /* 1699 * Function: 1700 * bcm_tdpll_input_clock_best_get() 1701 * Purpose: 1702 * Get best (i.e. selected) reference for a DPLL instance. 1703 * Parameters: 1704 * unit - (IN) Unit number. 1705 * stack_id - (IN) Stack identifier index. 1706 * dpll_index - (IN) DPLL instance number. 1707 * best_clock - (OUT) Best / preferred input clock index. 1708 * Returns: 1709 * BCM_E_XXX - Function status. 1710 * Notes: 1711 * Best / preferred input clock might not be active reference of DPLL 1712 * instance, e.g. if revertive option is not set. 1713 */ 1714 int 1715 bcm_common_tdpll_input_clock_best_get( 1716 int unit, 1717 int stack_id, 1718 int dpll_index, 1719 int *best_clock) 1720 { 1721 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 1722 return BCM_E_PARAM; 1723 } 1724 *best_clock = objdata.selector_state.selected_clock[dpll_index]; 1725 1726 return BCM_E_NONE; 1727 } 1728 1729 /* 1730 * Function: 1731 * bcm_tdpll_input_clock_dpll_reference_get() 1732 * Purpose: 1733 * Get active reference for a DPLL instance. 1734 * Parameters: 1735 * unit - (IN) Unit number. 1736 * stack_id - (IN) Stack identifier index. 1737 * dpll_index - (IN) DPLL instance number. 1738 * reference - (OUT) Active reference input clock index. 1739 * Returns: 1740 * BCM_E_XXX - Function status. 1741 * Notes: 1742 */ 1743 int 1744 bcm_tdpll_input_clock_dpll_reference_get( 1745 int unit, 1746 int stack_id, 1747 int dpll_index, 1748 int *reference) 1749 { 1750 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 1751 return BCM_E_PARAM; 1752 } 1753 *reference = INPUT_CLOCK_DPLL_REF(dpll_index); 1754 1755 return BCM_E_NONE; 1756 } 1757 1758 /* 1759 * Function: 1760 * bcm_tdpll_input_clock_monitor_callback_register() 1761 * Purpose: 1762 * Register input clock monitoring callback. 1763 * Parameters: 1764 * unit - (IN) Unit number. 1765 * stack_id - (IN) Stack identifier index. 1766 * monitor_cb - (IN) Input clock monitoring callback function pointer. 1767 * Returns: 1768 * BCM_E_XXX - Function status. 1769 * Notes: 1770 * Input clock monitoring callback generates an event to notify user if 1771 * state has changed w.r.t. a threshold criterion. 1772 */ 1773 int 1774 bcm_common_tdpll_input_clock_monitor_callback_register( 1775 int unit, 1776 int stack_id, 1777 bcm_tdpll_input_clock_monitor_cb monitor_cb) 1778 { 1779 objdata.monitor_callback = monitor_cb; 1780 return BCM_E_NONE; 1781 } 1782 1783 /* 1784 * Function: 1785 * bcm_tdpll_input_clock_monitor_callback_unregister() 1786 * Purpose: 1787 * Unregister input clock monitoring callback. 1788 * Parameters: 1789 * unit - (IN) Unit number. 1790 * stack_id - (IN) Stack identifier index. 1791 * Returns: 1792 * BCM_E_XXX - Function status. 1793 * Notes: 1794 * Input clock monitoring callback generates an event to notify user if 1795 * state has changed w.r.t. a threshold criterion. 1796 */ 1797 int 1798 bcm_common_tdpll_input_clock_monitor_callback_unregister( 1799 int unit, 1800 int stack_id) 1801 { 1802 objdata.monitor_callback = NULL; 1803 return BCM_E_NONE; 1804 } 1805 1806 /* 1807 * Function: 1808 * bcm_tdpll_input_clock_selector_callback_register() 1809 * Purpose: 1810 * Register input clock reference selection callback. 1811 * Parameters: 1812 * unit - (IN) Unit number. 1813 * stack_id - (IN) Stack identifier index. 1814 * selector_cb - (IN) Input clock reference selection callback function pointer. 1815 * Returns: 1816 * BCM_E_XXX - Function status. 1817 * Notes: 1818 * Reference selection callback generates an event to notify user if a 1819 * new reference is selected but automatic switching to it is deferred, 1820 * because revertive option is not enabled. 1821 */ 1822 int 1823 bcm_common_tdpll_input_clock_selector_callback_register( 1824 int unit, 1825 int stack_id, 1826 bcm_tdpll_input_clock_selector_cb selector_cb) 1827 { 1828 objdata.selector_callback = selector_cb; 1829 return BCM_E_NONE; 1830 } 1831 1832 /* 1833 * Function: 1834 * bcm_tdpll_input_clock_selector_callback_unregister() 1835 * Purpose: 1836 * Unregister input clock reference selection callback. 1837 * Parameters: 1838 * unit - (IN) Unit number. 1839 * stack_id - (IN) Stack identifier index. 1840 * Returns: 1841 * BCM_E_XXX - Function status. 1842 * Notes: 1843 * Reference selection callback generates an event to notify user if a 1844 * new reference is selected but automatic switching to it is deferred, 1845 * because revertive option is not enabled. 1846 */ 1847 int 1848 bcm_common_tdpll_input_clock_selector_callback_unregister( 1849 int unit, 1850 int stack_id) 1851 { 1852 objdata.selector_callback = NULL; 1853 return BCM_E_NONE; 1854 } 1855 1856 /* 1857 * Function: 1858 * bcm_tdpll_input_clock_callback_register() 1859 * Purpose: 1860 * Register input clock callback for various cb types. 1861 * Parameters: 1862 * unit - (IN) Unit number. 1863 * stack_id - (IN) Stack identifier index. 1864 * type - (IN) callback type - monitor/selector/notification 1865 * callback - (IN) Input clock callback function pointer. 1866 * Returns: 1867 * BCM_E_XXX - Function status. 1868 * Notes: 1869 * This is a unified callback handler register mechanism 1870 * that allows application to register callback functions 1871 * for different callback types i.e., monitor/selector/notification. 1872 */ 1873 int 1874 bcm_common_tdpll_input_clock_callback_register( 1875 int unit, 1876 int stack_id, 1877 bcm_tdpll_callback_type_t type, 1878 bcm_tdpll_input_clock_cb callback) 1879 { 1880 objdata.callback[type] = callback; 1881 return BCM_E_NONE; 1882 } 1883 1884 /* 1885 * Function: 1886 * bcm_tdpll_input_clock_callback_unregister() 1887 * Purpose: 1888 * Unregister input clock callback. 1889 * Parameters: 1890 * unit - (IN) Unit number. 1891 * stack_id - (IN) Stack identifier index. 1892 * callback - (IN) Input clock callback function pointer. 1893 * Returns: 1894 * BCM_E_XXX - Function status. 1895 * Notes: 1896 * Unregister a particular callback handler say 1897 * which is registered for monitor/selector/notification. 1898 */ 1899 int 1900 bcm_common_tdpll_input_clock_callback_unregister( 1901 int unit, 1902 int stack_id, 1903 bcm_tdpll_callback_type_t type) 1904 { 1905 objdata.callback[type] = NULL; 1906 return BCM_E_NONE; 1907 } 1908 1909 1910 /* 1911 * Function: 1912 * bcm_tdpll_input_clock_state_machine() 1913 * Purpose: 1914 * T-DPLL reference selection (as DPC). 1915 * Parameters: 1916 * arg_unit - (IN) Unit number (as void*). 1917 * arg_stack_id - (IN) Stack identifier index (as void*). 1918 * unused0 - (IN) Unused. 1919 * unused1 - (IN) Unused. 1920 * Returns: 1921 * Time until next call 1922 * Notes: 1923 */ 1924 static sal_usecs_t 1925 bcm_tdpll_input_clock_state_machine( 1926 void **arg_unit, 1927 void **arg_stack_id, 1928 void **unused0, 1929 void **unused1) 1930 { 1931 int rv; 1932 int i; 1933 1934 int unit = PTR_TO_INT(*arg_unit); 1935 int stack_id = PTR_TO_INT(*arg_stack_id); 1936 1937 bcm_tdpll_input_clock_selector_cb_data_t cb_data; 1938 bcm_tdpll_input_clock_ref_change_cb_data_t cb_noti_data; 1939 bcm_tdpll_input_clock_cb_data_t cb_data_new; 1940 1941 int rxen = 0; 1942 int update_fw_reqd = 0; 1943 1944 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 1945 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 1946 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 1947 return TDPLL_STATE_MACHINE_DPC_TIME_USEC_IDLE; 1948 } 1949 1950 if (BCM_FAILURE(rv = bcm_tdpll_esmc_rx_enable_get(unit, stack_id, &rxen))) { 1951 PTP_ERROR_FUNC("bcm_tdpll_esmc_rx_enable_get()"); 1952 return TDPLL_STATE_MACHINE_DPC_TIME_USEC_IDLE; 1953 } 1954 1955 /* SyncE input QL timeout processing iff ESMC PDU Rx is enabled. */ 1956 if (rxen && BCM_FAILURE(rv = bcm_tdpll_input_clock_esmc_timeout(unit, stack_id))) { 1957 PTP_ERROR_FUNC("bcm_tdpll_input_clock_esmc_timeout()"); 1958 return TDPLL_STATE_MACHINE_DPC_TIME_USEC_IDLE; 1959 } 1960 1961 if (BCM_FAILURE(rv = bcm_tdpll_input_clock_monitor_gateway(unit, stack_id))) { 1962 PTP_ERROR_FUNC("bcm_tdpll_input_clock_monitor_gateway()"); 1963 return TDPLL_STATE_MACHINE_DPC_TIME_USEC_IDLE; 1964 } 1965 1966 for (i = 0; i < TDPLL_DPLL_INSTANCE_NUM_MAX; ++i) { 1967 /* Reference selection for a DPLL instance. */ 1968 if (BCM_FAILURE(rv = bcm_tdpll_input_clock_reference_selector(i))) { 1969 /* 1970 * UNKNOWN best clock/no usable input clock yielded by reference 1971 * selection procedure. 1972 * 1973 * Force update of DPLL instance's active reference regardless 1974 * of revertive setting. 1975 */ 1976 if (objdata.selector_state.reference_clock[i] >= 0 && 1977 objdata.selector_state.reference_clock[i] < TDPLL_INPUT_CLOCK_NUM_MAX) { 1978 update_fw_reqd = 1; 1979 objdata.selector_state.reference_clock[i] = -1; 1980 1981 if (objdata.callback[bcmTdpllCallbackTypeNotification]) { 1982 cb_noti_data.noti_type = bcmTdpllNotificationTypeRefchange; 1983 cb_noti_data.dpll_index = i; 1984 cb_noti_data.prior_selected_clock = objdata.selector_state.prior_selected_clock[i]; 1985 cb_noti_data.selected_clock = objdata.selector_state.selected_clock[i]; 1986 1987 cb_data_new.callback_type = bcmTdpllCallbackTypeNotification; 1988 cb_data_new.cb_info = (void *)&cb_noti_data; 1989 objdata.callback[bcmTdpllCallbackTypeNotification](unit, stack_id, &cb_data_new); 1990 } 1991 /* Holdover event. */ 1992 bcm_tdpll_esmc_holdover_event_send(unit, stack_id, i); 1993 } else if (objdata.selector_state.reference_clock[i] == -1) { 1994 /* (CONDITIONAL) Holdover event. */ 1995 bcm_tdpll_esmc_holdover_event_send(unit, stack_id, i); 1996 } 1997 } else if (objdata.switching_options.revertive[i] || 1998 objdata.selector_state.reference_clock[i] == -1 || 1999 (INPUT_CLOCK_ACTIVE(i).state & (1 << TDPLL_INPUT_CLOCK_STATE_QL_DNU_BIT)) || 2000 (INPUT_CLOCK_ACTIVE(i).dpll_use[i] == 0) || 2001 (INPUT_CLOCK_ACTIVE(i).state & (1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT)) == 0) { 2002 /* 2003 * Best clock yielded by reference selection procedure. 2004 * 2005 * Conditionally update DPLL instance's active reference if 2006 * - revertive mode is set, 2007 * - no prior active reference, 2008 * - QL-DNU/DUS of active reference clock in QL-enabled mode, 2009 * - prior active reference is no longer a member of set 2010 * of input clocks bound to DPLL instance, 2011 * - prior active reference is invalid/unusable reference. 2012 */ 2013 if (objdata.selector_state.reference_clock[i] != objdata.selector_state.selected_clock[i]) { 2014 update_fw_reqd = 1; 2015 objdata.selector_state.reference_clock[i] = objdata.selector_state.selected_clock[i]; 2016 2017 if (objdata.callback[bcmTdpllCallbackTypeNotification]) { 2018 cb_noti_data.noti_type = bcmTdpllNotificationTypeRefchange; 2019 cb_noti_data.dpll_index = i; 2020 cb_noti_data.prior_selected_clock = objdata.selector_state.prior_selected_clock[i]; 2021 cb_noti_data.selected_clock = objdata.selector_state.selected_clock[i]; 2022 2023 cb_data_new.callback_type = bcmTdpllCallbackTypeNotification; 2024 cb_data_new.cb_info = (void *)&cb_noti_data; 2025 objdata.callback[bcmTdpllCallbackTypeNotification](unit, stack_id, &cb_data_new); 2026 } 2027 2028 /* Reference switch event. */ 2029 bcm_tdpll_esmc_switch_event_send(unit, stack_id, i, INPUT_CLOCK_BEST(i).select.ql); 2030 } 2031 } else { 2032 if (objdata.selector_state.selected_clock[i] != objdata.selector_state.prior_selected_clock[i]) { 2033 cb_data.dpll_index = i; 2034 cb_data.prior_selected_clock = objdata.selector_state.prior_selected_clock[i]; 2035 cb_data.selected_clock = objdata.selector_state.selected_clock[i]; 2036 2037 if (objdata.selector_callback) { 2038 objdata.selector_callback(unit, stack_id, &cb_data); 2039 } 2040 2041 if (objdata.callback[bcmTdpllCallbackTypeSelector]) { 2042 cb_data_new.callback_type = bcmTdpllCallbackTypeSelector; 2043 cb_data_new.cb_info = (void *)&cb_data; 2044 objdata.callback[bcmTdpllCallbackTypeSelector](unit, stack_id, &cb_data_new); 2045 } 2046 2047 if (objdata.callback[bcmTdpllCallbackTypeNotification]) { 2048 cb_noti_data.noti_type = bcmTdpllNotificationTypeRefchange; 2049 cb_noti_data.dpll_index = i; 2050 cb_noti_data.prior_selected_clock = objdata.selector_state.prior_selected_clock[i]; 2051 cb_noti_data.selected_clock = objdata.selector_state.selected_clock[i]; 2052 2053 cb_data_new.callback_type = bcmTdpllCallbackTypeNotification; 2054 cb_data_new.cb_info = (void *)&cb_noti_data; 2055 objdata.callback[bcmTdpllCallbackTypeNotification](unit, stack_id, &cb_data_new); 2056 } 2057 } 2058 } 2059 } 2060 2061 if (1 == update_fw_reqd) { 2062 /* Reference switch. */ 2063 bcm_tdpll_dpll_reference_set(unit, stack_id, 2064 TDPLL_DPLL_INSTANCE_NUM_MAX, 2065 objdata.selector_state.reference_clock); 2066 } 2067 2068 return TDPLL_STATE_MACHINE_DPC_TIME_USEC_DEFAULT; 2069 } 2070 2071 /* 2072 * Function: 2073 * bcm_tdpll_input_clock_esmc_timeout() 2074 * Purpose: 2075 * Check ESMC availability / timeout for SyncE input clocks. 2076 * Parameters: 2077 * unit - (IN) Unit number. 2078 * stack_id - (IN) Stack identifier index. 2079 * Returns: 2080 * BCM_E_XXX - Function status. 2081 * Notes: 2082 */ 2083 static int 2084 bcm_tdpll_input_clock_esmc_timeout( 2085 int unit, 2086 int stack_id) 2087 { 2088 int i; 2089 int rv; 2090 int dpll_index; 2091 int port; 2092 bcm_esmc_network_option_t g781_option; 2093 bcm_esmc_quality_level_t ql_fail; 2094 2095 bcm_esmc_pdu_data_t pdu_data_port; 2096 sal_time_t pdu_timestamp_port; 2097 2098 /* Get ITU-T G.781 networking option. */ 2099 bcm_esmc_g781_option_get(unit, stack_id, &g781_option); 2100 2101 for (i = 0; i < TDPLL_INPUT_CLOCK_NUM_SYNCE; ++i) { 2102 #if defined(BCM_SABER2_SUPPORT) /* SB2 ext.PHY L1 recovery support on portmapped to logical port*/ 2103 EPHY_PORT_MAP(i,INPUT_CLOCK(i+TDPLL_INPUT_CLOCK_NUM_GPIO).l1mux.port, 2104 objdata.phy_port[i+TDPLL_INPUT_CLOCK_NUM_GPIO],port); 2105 #else 2106 if (SOC_IS_QUX(unit) || SOC_IS_QAX(unit) || SOC_IS_QMX(unit) || SOC_IS_GREYHOUND2(unit)) { 2107 port = INPUT_CLOCK(i+TDPLL_INPUT_CLOCK_NUM_GPIO).l1mux.port; 2108 } else { 2109 port = INPUT_CLOCK(i+TDPLL_INPUT_CLOCK_NUM_GPIO).l1mux.port+1; 2110 } 2111 #endif /* BCM_SABER2_SUPPORT */ 2112 if (BCM_FAILURE(rv = bcm_esmc_pdu_port_data_get(unit, stack_id, 2113 port,&pdu_data_port, &pdu_timestamp_port))) { 2114 continue; 2115 } 2116 2117 if ((_bcm_ptp_monotonic_time() - pdu_timestamp_port) > TDPLL_ESMC_FAILURE_TIMEOUT_SEC) { 2118 /* 2119 * Elapsed time since prior ESMC PDU exceeds 5 sec. timeout per ITU-T G.8264. 2120 * Set QL to do not use (DNU) to signal a failure. 2121 */ 2122 switch (g781_option) { 2123 case bcm_esmc_network_option_g781_I: 2124 ql_fail = bcm_esmc_g781_I_ql_dnu; 2125 break; 2126 case bcm_esmc_network_option_g781_II: 2127 ql_fail = bcm_esmc_g781_II_ql_dus; 2128 break; 2129 case bcm_esmc_network_option_g781_III: 2130 ql_fail = bcm_esmc_g781_III_ql_sec; /* ? */ 2131 break; 2132 default: 2133 return BCM_E_PARAM; 2134 } 2135 2136 for (dpll_index = 0; dpll_index < TDPLL_DPLL_INSTANCE_NUM_MAX; ++dpll_index) { 2137 if ((i+TDPLL_INPUT_CLOCK_NUM_GPIO) == INPUT_CLOCK_DPLL_REF(dpll_index)) { 2138 /* DPLL selected reference failure. Transmit ESMC event PDU. */ 2139 bcm_tdpll_esmc_switch_event_send(unit, stack_id, dpll_index, ql_fail); 2140 } 2141 } 2142 2143 /* Update SyncE input clock QL. */ 2144 INPUT_CLOCK(i+TDPLL_INPUT_CLOCK_NUM_GPIO).select.ql = ql_fail; 2145 } 2146 } 2147 2148 return BCM_E_NONE; 2149 } 2150 2151 /* 2152 * Function: 2153 * bcm_tdpll_input_clock_reference_selector() 2154 * Purpose: 2155 * Identify best input clock to serve as a reference for DPLL instance. 2156 * Parameters: 2157 * dpll_index - (IN) DPLL instance number. 2158 * Returns: 2159 * BCM_E_XXX - Function status. 2160 * Notes: 2161 */ 2162 static int 2163 bcm_tdpll_input_clock_reference_selector( 2164 int dpll_index) 2165 { 2166 int el; 2167 int unknown_best_clock = 0; 2168 2169 int ql; 2170 int qlbest; 2171 int ql_dnu; /* QL do-not-use. */ 2172 2173 /* Argument checking and error handling. */ 2174 if (dpll_index < 0 || dpll_index >= TDPLL_DPLL_INSTANCE_NUM_MAX) { 2175 return BCM_E_PARAM; 2176 } 2177 2178 objdata.selector_state.prior_selected_clock[dpll_index] = 2179 objdata.selector_state.selected_clock[dpll_index]; 2180 2181 ql_dnu = (objdata.selector_options.ql_enabled[dpll_index] && 2182 (INPUT_CLOCK_BEST(dpll_index).select.ql == bcm_esmc_g781_I_ql_dnu || 2183 INPUT_CLOCK_BEST(dpll_index).select.ql == bcm_esmc_g781_II_ql_dus)) ? 1:0; 2184 2185 if (0 == INPUT_CLOCK_BEST(dpll_index).dpll_use[dpll_index] || 2186 0 == (INPUT_CLOCK_BEST(dpll_index).state & (1 << TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT)) || 2187 0 == (INPUT_CLOCK_BEST(dpll_index).state & (1 << TDPLL_INPUT_CLOCK_STATE_TSAVAIL_BIT)) || 2188 0 == (INPUT_CLOCK_BEST(dpll_index).state & (1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT)) || 2189 1 == INPUT_CLOCK_BEST(dpll_index).select.lockout || 2190 1 == ql_dnu) { 2191 /* 2192 * Prior best input clock is not associated with this DPLL instance. 2193 * OR prior best input clock is either not enabled or not valid. 2194 */ 2195 unknown_best_clock = 1; 2196 2197 /* Re-initialize preferred clock to unknown DPLL logical instance. */ 2198 for (el = 0; el < TDPLL_INPUT_CLOCK_NUM_MAX; ++el) { 2199 if (INPUT_CLOCK(el).dpll_use[dpll_index]) { 2200 objdata.selector_state.selected_clock[dpll_index] = -1; 2201 break; 2202 } 2203 } 2204 } 2205 2206 for (el = 0; el < TDPLL_INPUT_CLOCK_NUM_MAX; ++el) { 2207 ql_dnu = (objdata.selector_options.ql_enabled[dpll_index] && 2208 (INPUT_CLOCK(el).select.ql == bcm_esmc_g781_I_ql_dnu || 2209 INPUT_CLOCK(el).select.ql == bcm_esmc_g781_II_ql_dus)) ? 1:0; 2210 2211 /* Set QL-DNU/DUS flag. */ 2212 if (ql_dnu) { 2213 INPUT_CLOCK(el).state |= (1 << TDPLL_INPUT_CLOCK_STATE_QL_DNU_BIT); 2214 } else { 2215 INPUT_CLOCK(el).state &= ~(1 << TDPLL_INPUT_CLOCK_STATE_QL_DNU_BIT); 2216 } 2217 2218 if (0 == INPUT_CLOCK(el).dpll_use[dpll_index] || 2219 0 == (INPUT_CLOCK(el).state & (1 << TDPLL_INPUT_CLOCK_STATE_ENABLE_BIT)) || 2220 0 == (INPUT_CLOCK(el).state & (1 << TDPLL_INPUT_CLOCK_STATE_TSAVAIL_BIT)) || 2221 0 == (INPUT_CLOCK(el).state & (1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT)) || 2222 1 == INPUT_CLOCK(el).select.lockout || 2223 1 == ql_dnu) { 2224 /* 2225 * Input clock is not associated with this DPLL instance. 2226 * OR input clock is either not enabled or not valid. 2227 */ 2228 continue; 2229 } 2230 2231 if (1 == unknown_best_clock) { 2232 unknown_best_clock = 0; 2233 objdata.selector_state.selected_clock[dpll_index] = el; 2234 } 2235 2236 if (1 == objdata.selector_options.ql_enabled[dpll_index]) { 2237 /* QL-enabled selection. */ 2238 ql = INPUT_CLOCK(el).select.ql & 0xf; 2239 qlbest = INPUT_CLOCK_BEST(dpll_index).select.ql & 0xf; 2240 2241 if (ql < qlbest) { 2242 /* 2243 * PRIMARY SELECTION CRITERION. 2244 * Higher quality level (lower numerical value) than selected 2245 * reference clock. 2246 */ 2247 objdata.selector_state.selected_clock[dpll_index] = el; 2248 } else if (ql == qlbest && 2249 INPUT_CLOCK(el).select.priority < INPUT_CLOCK_BEST(dpll_index).select.priority) { 2250 /* 2251 * SECONDARY SELECTION CRITERION. 2252 * Equal QL, higher priority (lower numerical value) than selected 2253 * reference clock. 2254 */ 2255 objdata.selector_state.selected_clock[dpll_index] = el; 2256 } else if (ql == qlbest && 2257 INPUT_CLOCK(el).select.priority == INPUT_CLOCK_BEST(dpll_index).select.priority && 2258 INPUT_CLOCK(el).index < INPUT_CLOCK_BEST(dpll_index).index) { 2259 /* 2260 * TERTIARY SELECTION CRITERION. 2261 * Equal (QL, priority), lesser clock index than selected 2262 * reference clock. 2263 */ 2264 objdata.selector_state.selected_clock[dpll_index] = el; 2265 } 2266 } else { 2267 /* QL-disabled selection. */ 2268 if (INPUT_CLOCK(el).select.priority < INPUT_CLOCK_BEST(dpll_index).select.priority) { 2269 objdata.selector_state.selected_clock[dpll_index] = el; 2270 } else if (INPUT_CLOCK(el).select.priority == INPUT_CLOCK_BEST(dpll_index).select.priority && 2271 INPUT_CLOCK(el).index < INPUT_CLOCK_BEST(dpll_index).index) { 2272 /* 2273 * Equal priority, lesser clock index than selected 2274 * reference clock. 2275 */ 2276 objdata.selector_state.selected_clock[dpll_index] = el; 2277 } 2278 } 2279 } 2280 2281 if (g_apts_enabled && (g_apts_usr_cfgd_source_state & bcmPtpClockAptsSourceSynceInternalDpll)){ 2282 if ((1 == unknown_best_clock) || 2283 ((objdata.selector_state.selected_clock[dpll_index] <= BCM_TDPLL_INPUT_CLOCK_NUM_GPIO) && 2284 (objdata.selector_state.selected_clock[dpll_index] >= BCM_TDPLL_INPUT_CLOCK_NUM_1588))) { 2285 /* Synce is not available from internal TDPLL */ 2286 g_apts_current_source_state &= _bcm_ptp_apts_avail_ptp_gps; 2287 } else { 2288 g_apts_current_source_state |= _bcm_ptp_apts_avail_synce; 2289 } 2290 _bcm_ptp_apts_update_current_mode(); 2291 } 2292 2293 if (1 == unknown_best_clock) { 2294 return BCM_E_NOT_FOUND; 2295 } else { 2296 return BCM_E_NONE; 2297 } 2298 } 2299 2300 static int 2301 bcm_tdpll_input_clock_monitor_gateway( 2302 int unit, 2303 int stack_id) 2304 { 2305 int rv; 2306 int i; 2307 2308 /* Get input clock monitoring data. */ 2309 if (BCM_FAILURE(rv = bcm_tdpll_input_clock_monitor_data_get(unit, stack_id))) { 2310 PTP_ERROR_FUNC("bcm_tdpll_input_clock_monitor_data_get()"); 2311 return rv; 2312 } 2313 2314 for (i = 0; i < TDPLL_INPUT_CLOCK_NUM_MAX; ++i) { 2315 if (BCM_FAILURE(rv = bcm_tdpll_input_clock_monitor_calc(unit, stack_id, 2316 &INPUT_CLOCK(i)))) { 2317 PTP_ERROR_FUNC("bcm_tdpll_input_clock_monitor_calc()"); 2318 return rv; 2319 } 2320 if (BCM_FAILURE(rv = bcm_tdpll_input_clock_monitor_eval(unit, stack_id, 2321 &INPUT_CLOCK(i)))) { 2322 PTP_ERROR_FUNC("bcm_tdpll_input_clock_monitor_eval()"); 2323 return rv; 2324 } 2325 } 2326 2327 return BCM_E_NONE; 2328 } 2329 2330 /* 2331 * Function: 2332 * bcm_tdpll_input_clock_monitor_data_get() 2333 * Purpose: 2334 * Get input clock prescreen state and timestamp event data. 2335 * Parameters: 2336 * unit - (IN) Unit number. 2337 * stack_id - (IN) Stack identifier index. 2338 * Returns: 2339 * BCM_E_XXX - Function status. 2340 * Notes: 2341 * Timestamps form basis for fractional frequency error measurements 2342 * used in input clock monitoring. 2343 */ 2344 static int 2345 bcm_tdpll_input_clock_monitor_data_get( 2346 int unit, 2347 int stack_id) 2348 { 2349 int rv; 2350 int i; 2351 int index; 2352 2353 uint8 resp[PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_MONITOR_DATA_SIZE_OCTETS] = {0}; 2354 int resp_len = PTP_MGMTMSG_PAYLOAD_INPUT_CLOCK_MONITOR_DATA_SIZE_OCTETS; 2355 2356 bcm_ptp_port_identity_t portid; 2357 2358 if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, stack_id, 2359 PTP_CLOCK_NUMBER_DEFAULT, PTP_CLOCK_PORT_NUMBER_DEFAULT))) { 2360 PTP_ERROR_FUNC("_bcm_ptp_function_precheck()"); 2361 return rv; 2362 } 2363 2364 if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, stack_id, 2365 PTP_CLOCK_NUMBER_DEFAULT, PTP_IEEE1588_ALL_PORTS, &portid))) { 2366 PTP_ERROR_FUNC("bcm_common_ptp_clock_port_identity_get()"); 2367 return rv; 2368 } 2369 2370 if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, 2371 &portid, PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_INPUT_CLOCK_MONITOR_DATA, 2372 0, 0, resp, &resp_len))) { 2373 PTP_ERROR_FUNC("_bcm_ptp_management_message_send()"); 2374 return rv; 2375 } 2376 2377 /* 2378 * Parse response. 2379 * Octet 0...5 : Custom management message key/identifier. 2380 * BCM<null><null><null>. 2381 * Octet 6...9 : Input clock 0 usable reference (FW classification). 2382 * Octet 10...17 : Input clock 0 elapsed time (ns). 2383 * Octet 18...25 : Input clock 0 TS event time (ns). 2384 * Octet 26...33 : Input clock 0 TS event number. 2385 * Octet 34...37 : Input clock 1 usable reference (FW classification). 2386 * Octet 38...45 : Input clock 1 elapsed time (ns). 2387 * Octet 46...53 : Input clock 1 TS event time (ns). 2388 * Octet 54...61 : Input clock 1 TS event number. 2389 * Octet 62...65 : Input clock 2 usable reference (FW classification). 2390 * Octet 66...73 : Input clock 2 elapsed time (ns). 2391 * Octet 74...81 : Input clock 2 TS event time (ns). 2392 * Octet 82...89 : Input clock 2 TS event number. 2393 * Octet 90...93 : Input clock 3 usable reference (FW classification). 2394 * Octet 94...101 : Input clock 3 elapsed time (ns). 2395 * Octet 102...109 : Input clock 3 TS event time (ns). 2396 * Octet 110...117 : Input clock 3 TS event number. 2397 * Octet 118...121 : Input clock 4 usable reference (FW classification). 2398 * Octet 122...129 : Input clock 4 elapsed time (ns). 2399 * Octet 130...137 : Input clock 4 TS event time (ns). 2400 * Octet 138...145 : Input clock 4 TS event number. 2401 * Octet 146...149 : Input clock 5 usable reference (FW classification). 2402 * Octet 150...157 : Input clock 5 elapsed time (ns). 2403 * Octet 158...165 : Input clock 5 TS event time (ns). 2404 * Octet 166...173 : Input clock 5 TS event number. 2405 * Octet 174...177 : Input clock 6 usable reference (FW classification). 2406 * Octet 178...185 : Input clock 6 elapsed time (ns). 2407 * Octet 186...193 : Input clock 6 TS event time (ns). 2408 * Octet 194...201 : Input clock 6 TS event number. 2409 * Octet 202...205 : Input clock 7 usable reference (FW classification). 2410 * Octet 206...213 : Input clock 7 elapsed time (ns). 2411 * Octet 214...221 : Input clock 7 TS event time (ns). 2412 * Octet 222...229 : Input clock 7 TS event number. 2413 * Octet 230...233 : Input clock 8 usable reference (FW classification). 2414 * Octet 234...241 : Input clock 8 elapsed time (ns). 2415 * Octet 242...249 : Input clock 8 TS event time (ns). 2416 * Octet 250...257 : Input clock 8 TS event number. 2417 * Octet 257...261 : Input clock 9 usable reference (FW classification). 2418 * Octet 262...269 : Input clock 9 elapsed time (ns). 2419 * Octet 270...277 : Input clock 9 TS event time (ns). 2420 * Octet 278...285 : Input clock 9 TS event number. 2421 * 2422 * NOTES: 2423 * Input clock TS event times are most recent timestamps. 2424 * 2425 * Input clock elapsed times are nanonseconds since the prior TS event. 2426 * If clocks are "perfect" and timestamper is tracking, elapsed times 2427 * will equal 1B nanoseconds, i.e. one second. 2428 */ 2429 i = 6; /* Advance cursor past custom management message identifier. */ 2430 2431 for (index = 0; index < TDPLL_INPUT_CLOCK_NUM_MAX; ++index) { 2432 objdata.prescreen_valid[index] = _bcm_ptp_uint32_read(resp + i) ? 1:0; 2433 i += 4; 2434 2435 INPUT_CLOCK(index).monitor.tsevent_dt = _bcm_ptp_uint64_read(resp + i); 2436 i += 8; 2437 INPUT_CLOCK(index).monitor.tsevent_time = _bcm_ptp_uint64_read(resp + i); 2438 i += 8; 2439 INPUT_CLOCK(index).monitor.tsevent_num = _bcm_ptp_uint64_read(resp + i); 2440 i += 8; 2441 } 2442 2443 return BCM_E_NONE; 2444 } 2445 2446 static int 2447 bcm_tdpll_input_clock_monitor_calc( 2448 int unit, 2449 int stack_id, 2450 bcm_tdpll_input_clock_t *input_clock) 2451 { 2452 2453 /* Argument checking and error handling. */ 2454 if (NULL == input_clock) { 2455 return BCM_E_NOT_FOUND; 2456 } 2457 2458 /* 2459 * Update elapsed time measurement iff new TS event data are available. 2460 * 2461 * NOTE: Frequency f over a monitoring interval [t0,tN] is given by: 2462 * 2463 * mN 2464 * f = --------- , where m equals number of input clock edges 2465 * (tN - t0) per second and N equals number of seconds. 2466 * 2467 * Or, in terms of N subintervals [t0,t1], [t1,t2], ... [tN-1,tN] 2468 * 2469 * mN 2470 * f = --------------------------------------------------------- 2471 * (tN - tN-1) + (tN-1 - tN-2) + ... + (t2 - t1) + (t1 - t0) 2472 * 2473 * N 2474 * f = --------------------------------------------------------- 2475 * (tN - tN-1) + (tN-1 - tN-2) + ... + (t2 - t1) + (t1 - t0) 2476 * ----------- ------------- --------- --------- 2477 * m m m m 2478 * 2479 * Subinterval frequency fi equals (by definition): 2480 * m 2481 * fi = ------------- 2482 * t(i) - t(i-1) 2483 * 2484 * Effective frequency f over monitoring interval, which includes 2485 * N subintervals, is a function of N subinterval frequencies: 2486 * 2487 * N 2488 * f = --------------------- 2489 * 1 1 1 2490 * --- + --- + ... + --- 2491 * f1 f2 fN 2492 * 2493 * 1 1 1 1 1 2494 * - = - (--- + --- + ... + ---) 2495 * f N f1 f2 fN 2496 * 2497 * Normalized subinterval frequency (fni) is obtained by dividing 2498 * by the number of input clock edges per second, (m). Normalized 2499 * frequency during one-second subinterval i is the reciprocal of 2500 * elapsed time t(i) - t(i-1). 2501 * 2502 * 1 1 1 1 1 2503 * - = --- (--- + --- + ... + ---) 2504 * f mN fn1 fn2 fnN 2505 * 2506 * 1 1 | | 2507 * - = --- |(tN - tN-1) + (tN-1 - tN-2) + ... + (t2 - t1) + (t1 - t0)| 2508 * f mN | | 2509 * 2510 * NB: t0, t1, ..., tN are local OCXO reference times (open-loop) 2511 * and are unobservable if the timestamp counter is steered. 2512 * 2513 * ts0, ts1, ..., tsN are local OCXO reference times (closed- 2514 * loop) and include the effects of timestamper increments Xi 2515 * as the timestamper frequency control is dynamically varied 2516 * to track a selected reference clock. 2517 * 2518 * ts(i) - ts(i-1) = (1 + Xi) ( t(i) - t(i-1) ) 2519 * 2520 * ts(i) - ts(i-1) 2521 * t(i) - t(i-1) = --------------- 2522 * 1 + Xi 2523 * 2524 * For input clock monitoring purposes, objective is to undo effects of 2525 * active, closed-loop steering of timestamper, and thus decouple input 2526 * clock frequency estimates from the selected reference. The resultant 2527 * frequency monitoring results are w.r.t. open-loop local OCXO, i.e. 2528 * sans timestamper increment control influences. 2529 * 2530 * 1 1 |(tsN - tsN-1) (tsN-1 - tsN-2) (ts2 - ts1) (ts1 - ts0)| 2531 * - = --- |------------- + --------------- + ... + ----------- + -----------| 2532 * f mN | 1 + XN 1 + XN-2 1 + X2 1 + X1 | 2533 * 2534 * Without loss of generality, the soln can omit mN scaling by factoring 2535 * it out of the reference clock frequency in fractional frequency error. 2536 * Calculation done in terms of accumulated, open-loop elapsed time, i.e. 2537 * with corrections to remove effects of timestamper increment control. 2538 * 2539 * NOTE: Solution currently has free-running timestamp counter for T-DPLL. 2540 * The TS frequency corrections are zero by definition, and the open 2541 * loop timestamps are directly measurable. 2542 */ 2543 2544 if (COMPILER_64_LE(input_clock->monitor.tsevent_num, input_clock->monitor.prior_evnum)) { 2545 /* Increment number of consecutive missing events. Do not rollover. */ 2546 if (input_clock->monitor.num_missing_tsevent < ((uint32)-1)) { 2547 input_clock->monitor.num_missing_tsevent++; 2548 } 2549 2550 if (input_clock->monitor.num_missing_tsevent > 3) { 2551 input_clock->state &= ~(1 << TDPLL_INPUT_CLOCK_STATE_TSAVAIL_BIT); 2552 input_clock->monitor.prior_evnum = input_clock->monitor.tsevent_num; 2553 /* Missing timestamps - Frequency equals zero; period is infinite.*/ 2554 COMPILER_64_ALLONES(input_clock->monitor.dt_ns); 2555 COMPILER_64_SET(input_clock->monitor.dtref_ns, 0, 1000000000); 2556 } 2557 2558 return BCM_E_NONE; 2559 } 2560 2561 input_clock->monitor.prior_evnum = input_clock->monitor.tsevent_num; 2562 2563 /* Reset number of consecutive missing events. */ 2564 input_clock->monitor.num_missing_tsevent = 0; 2565 input_clock->state |= (1 << TDPLL_INPUT_CLOCK_STATE_TSAVAIL_BIT); 2566 2567 COMPILER_64_ADD_64(input_clock->monitor.dt_sum_ns, input_clock->monitor.tsevent_dt); 2568 COMPILER_64_ADD_32(input_clock->monitor.dtref_sum_ns, 1000000000); 2569 2570 input_clock->monitor.numev_sum++; 2571 2572 if (input_clock->monitor.numev_sum >= objdata.monitor_options.interval) { 2573 input_clock->monitor.dt_ns = input_clock->monitor.dt_sum_ns; 2574 input_clock->monitor.dtref_ns = input_clock->monitor.dtref_sum_ns; 2575 2576 COMPILER_64_ZERO(input_clock->monitor.dt_sum_ns); 2577 COMPILER_64_ZERO(input_clock->monitor.dtref_sum_ns); 2578 input_clock->monitor.numev_sum = 0; 2579 } 2580 2581 return BCM_E_NONE; 2582 } 2583 2584 static int 2585 bcm_tdpll_input_clock_monitor_eval( 2586 int unit, 2587 int stack_id, 2588 bcm_tdpll_input_clock_t *input_clock) 2589 { 2590 uint64 ocxodt_us; 2591 uint32 ocxodt_uslo; 2592 2593 uint64 errabs; 2594 uint64 errval, errlim; 2595 2596 uint16 q0, q1; 2597 int freqerr_sign; 2598 2599 int prior_monitor_state; 2600 bcm_tdpll_input_clock_monitor_cb_data_t cb_data; 2601 bcm_tdpll_input_clock_cb_data_t cb_data_new; 2602 2603 int64 servo_freq_correction_pbb; 2604 2605 if (NULL == input_clock) { 2606 return BCM_E_NOT_FOUND; 2607 } 2608 2609 /* 2610 * Calculate fractional frequency error, X, of a telecom DPLL input clock. 2611 * 2612 * X = (f - fR)/fR, where fR equals reference frequency. 2613 * 2614 * OCXO timestamps (ti0,ti1) acquired from firmware are times in system's 2615 * local OCXO timeframe corresponding to TS EVENTS of input clock. 2616 * 2617 * f = mN/(ti1 - ti0), where mN is number of T-DPLL input clock edges. 2618 * m = Number of T-DPLL input clock edges per sec. 2619 * N = Number of (one-second) periods, monitoring 2620 * window duration. 2621 * 2622 * OCXO timestamps (to0,to1) correspond to prescribed monitoring interval. 2623 * 2624 * fR = mN/(to1 - to0), where mN is number of T-DPLL input clock edges. 2625 * m = Number of T-DPLL input clock edges per sec. 2626 * N = Number of (one-second) periods, monitoring 2627 * window duration. 2628 * 2629 * ------------------------------------------------------------------------- 2630 * mN mN 2631 * ----------- - ----------- 2632 * (ti1 - ti0) (to1 - to0) 2633 * X = ------------------------- 2634 * mN 2635 * ----------- 2636 * (to1 - to0) 2637 * 2638 * (to1 - to0) 2639 * X = ----------- - 1 2640 * (ti1 - ti0) 2641 * 2642 * (to1 - to0) - (ti1 - ti0) 2643 * X = ------------------------- 2644 * (ti1 - ti0) 2645 * 2646 * (REF dt - CLK_i dt) 2647 * X = ---------------------- 2648 * CLK_i dt 2649 * 2650 * |REF dt - CLK_i dt| |TS Interval Error| 2651 * |X| = ------------------- = ------------------- 2652 * CLK_i dt CLK_i dt 2653 */ 2654 2655 if (COMPILER_64_GE(input_clock->monitor.dtref_ns, input_clock->monitor.dt_ns)) { 2656 freqerr_sign = 1; 2657 errabs = input_clock->monitor.dtref_ns; 2658 COMPILER_64_SUB_64(errabs, input_clock->monitor.dt_ns); 2659 } else { 2660 freqerr_sign = -1; 2661 errabs = input_clock->monitor.dt_ns; 2662 COMPILER_64_SUB_64(errabs, input_clock->monitor.dtref_ns); 2663 } 2664 2665 /* 2666 * CLASSIFICATION. 2667 * Alarm threshold exceedance criteria. 2668 * 2669 * |TS Interval Error| (ns) Threshold (ppb) 2670 * ------------------------ > --------------- ? 2671 * CLK_i dt (ns) 10^9 2672 * 2673 * or equivalently with SDK 64-bit math compliant multiplicands and divisors. 2674 * 2675 * Threshold (ppb) x CLK_i dt (ns) 2676 * |TS Interval Error| (ns) x 10^6 > ------------------------------- ? 2677 * 10^3 2678 */ 2679 errval = errabs; 2680 COMPILER_64_UMUL_32(errval, (uint32)TDPLL_USEC_PER_SEC); 2681 2682 /* Soft-limit WARN threshold criterion. */ 2683 prior_monitor_state = input_clock->monitor.over_soft_warn_threshold ? 1:0; 2684 2685 errlim = input_clock->monitor.dt_ns; 2686 COMPILER_64_UMUL_32(errlim, objdata.monitor_options.soft_warn_threshold_ppb); 2687 errlim = _bcm_ptp_llu_div(errlim, 1000); 2688 input_clock->monitor.over_soft_warn_threshold = COMPILER_64_GE(errval, errlim) ? 1:0; 2689 2690 if (input_clock->monitor.over_soft_warn_threshold != prior_monitor_state) { 2691 /* Input clock monitoring state change (FALSE --> TRUE or TRUE --> FALSE). */ 2692 cb_data.index = input_clock->index; 2693 cb_data.monitor_type = bcm_tdpll_input_clock_monitor_type_soft_warn; 2694 cb_data.monitor_value = input_clock->monitor.over_soft_warn_threshold; 2695 if (objdata.monitor_callback) { 2696 objdata.monitor_callback(unit, stack_id, &cb_data); 2697 } 2698 2699 if (objdata.callback[bcmTdpllCallbackTypeMonitor]) { 2700 cb_data_new.callback_type = bcmTdpllCallbackTypeMonitor; 2701 cb_data_new.cb_info = (void *)&cb_data; 2702 objdata.callback[bcmTdpllCallbackTypeMonitor](unit, stack_id, &cb_data_new); 2703 } 2704 } 2705 2706 /* Hard-limit ACCEPT threshold criterion. */ 2707 prior_monitor_state = input_clock->monitor.under_hard_accept_threshold ? 1:0; 2708 2709 errlim = input_clock->monitor.dt_ns; 2710 COMPILER_64_UMUL_32(errlim, objdata.monitor_options.hard_accept_threshold_ppb); 2711 errlim = _bcm_ptp_llu_div(errlim, 1000); 2712 input_clock->monitor.under_hard_accept_threshold = COMPILER_64_LT(errval, errlim) ? 1:0; 2713 2714 if (input_clock->monitor.under_hard_accept_threshold != prior_monitor_state) { 2715 /* Input clock monitoring state change (FALSE --> TRUE or TRUE --> FALSE). */ 2716 cb_data.index = input_clock->index; 2717 cb_data.monitor_type = bcm_tdpll_input_clock_monitor_type_hard_accept; 2718 cb_data.monitor_value = input_clock->monitor.under_hard_accept_threshold; 2719 if (objdata.monitor_callback) { 2720 objdata.monitor_callback(unit, stack_id, &cb_data); 2721 } 2722 2723 if (objdata.callback[bcmTdpllCallbackTypeMonitor]) { 2724 cb_data_new.callback_type = bcmTdpllCallbackTypeMonitor; 2725 cb_data_new.cb_info = (void *)&cb_data; 2726 objdata.callback[bcmTdpllCallbackTypeMonitor](unit, stack_id, &cb_data_new); 2727 } 2728 } 2729 2730 /* Hard-limit REJECT threshold criterion. */ 2731 prior_monitor_state = input_clock->monitor.over_hard_reject_threshold ? 1:0; 2732 2733 errlim = input_clock->monitor.dt_ns; 2734 COMPILER_64_UMUL_32(errlim, objdata.monitor_options.hard_reject_threshold_ppb); 2735 errlim = _bcm_ptp_llu_div(errlim, 1000); 2736 input_clock->monitor.over_hard_reject_threshold = COMPILER_64_GE(errval, errlim) ? 1:0; 2737 2738 if (input_clock->monitor.over_hard_reject_threshold != prior_monitor_state) { 2739 /* Input clock monitoring state change (FALSE --> TRUE or TRUE --> FALSE). */ 2740 cb_data.index = input_clock->index; 2741 cb_data.monitor_type = bcm_tdpll_input_clock_monitor_type_hard_reject; 2742 cb_data.monitor_value = input_clock->monitor.over_hard_reject_threshold; 2743 if (objdata.monitor_callback) { 2744 objdata.monitor_callback(unit, stack_id, &cb_data); 2745 } 2746 2747 if (objdata.callback[bcmTdpllCallbackTypeMonitor]) { 2748 cb_data_new.callback_type = bcmTdpllCallbackTypeMonitor; 2749 cb_data_new.cb_info = (void *)&cb_data; 2750 objdata.callback[bcmTdpllCallbackTypeMonitor](unit, stack_id, &cb_data_new); 2751 } 2752 } 2753 2754 /* Classify input clock (valid/invalid). */ 2755 if (input_clock->monitor.over_hard_reject_threshold || 2756 (0 == objdata.prescreen_valid[input_clock->index])) { 2757 input_clock->state &= ~(1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT); 2758 } else if (input_clock->monitor.under_hard_accept_threshold) { 2759 input_clock->state |= (1 << TDPLL_INPUT_CLOCK_STATE_VALID_BIT); 2760 } 2761 2762 /* Estimate input clock fractional frequency error. */ 2763 ocxodt_us = _bcm_ptp_llu_div(input_clock->monitor.dt_ns, 1000); 2764 ocxodt_uslo = COMPILER_64_LO(ocxodt_us); 2765 2766 if (COMPILER_64_HI(ocxodt_us) || ocxodt_uslo == 0) { 2767 input_clock->monitor.freq_error_ppb = TDPLL_FREQUENCY_ERROR_MAX_PPB*freqerr_sign; 2768 } else { 2769 q0 = (ocxodt_uslo > 65536) ? ((ocxodt_uslo/65536) + 1):1; 2770 q1 = (ocxodt_uslo > q0) ? (ocxodt_uslo/q0):1; 2771 2772 errval = _bcm_ptp_llu_div(errval, q0); 2773 errval = _bcm_ptp_llu_div(errval, q1); 2774 input_clock->monitor.freq_error_ppb = COMPILER_64_LO(errval)*freqerr_sign; 2775 } 2776 2777 /* As per disucssion with Architect, in case of TS0/TS1 combined mode with PTP hybrid mode 2778 * where TS1 frequency corrected with synce recovered frequency, actual frequency of any input 2779 * will be signed addition of computed frequency offset by TDPLL monitoring algorithm and applied 2780 * frequency correction of currently selected synce reference. TDPLL frequency monitoring algorithm 2781 * will be modified for same. There will no change in existing phase monitoring computation. For example, 2782 * if synce recovered clock applies +100 pbb frequency offset, and for any particular input, TDPLL computes 2783 * frequency offset of +200pbb then, actual frequency with respect to unsteered clock with be 2784 * (+100pbb + 200pbb) = 300pbb. 2785 */ 2786 if(_bcm_ptp_bcm_servo_synce_freq_corr_get_in_combined_mode(unit, stack_id, &servo_freq_correction_pbb) 2787 == BCM_E_NONE) { 2788 input_clock->monitor.freq_error_ppb += servo_freq_correction_pbb; 2789 } 2790 2791 2792 2793 return BCM_E_NONE; 2794 } 2795 2796 #endif /* defined(INCLUDE_PTP) */