openbcm

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

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