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

servo.c (56049B)


      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:    servo.c
      8  *
      9  * Purpose: 
     10  *
     11  * Functions:
     12  *      bcm_common_ptp_servo_configuration_get
     13  *      bcm_common_ptp_servo_configuration_set
     14  *      bcm_common_ptp_servo_status_get
     15  *      bcm_common_ptp_phase_offset_set
     16  *      bcm_common_ptp_phase_offset_get
     17  *
     18  *      _bcm_ptp_servo_start
     19  *      _bcm_ptp_servo_restart
     20  *      _bcm_ptp_servo_stop
     21  *      _bcm_ptp_servo_ipdv_configuration_get
     22  *      _bcm_ptp_servo_ipdv_configuration_set
     23  *      _bcm_ptp_servo_performance_get
     24  *      _bcm_ptp_servo_ipdv_performance_get
     25  *      _bcm_ptp_servo_performance_data_clear
     26  */
     27 
     28 #if defined(INCLUDE_PTP)
     29 
     30 #include <bcm/ptp.h>
     31 #include <bcm_int/common/ptp.h>
     32 #include <bcm_int/ptp_common.h>
     33 #include <bcm/error.h>
     34 
     35 static const bcm_ptp_port_identity_t portid_all = 
     36     {{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, PTP_IEEE1588_ALL_PORTS};
     37 
     38 /*
     39  * Function:
     40  *      _bcm_ptp_servo_start
     41  * Purpose:
     42  *      Start PTP time synchronization servo.
     43  * Parameters:
     44  *      unit      - (IN) Unit number.
     45  *      ptp_id    - (IN) PTP stack ID.
     46  *      clock_num - (IN) PTP clock number.
     47  * Returns:
     48  *      BCM_E_XXX - Function status.
     49  * Notes:
     50  */
     51 int 
     52 _bcm_ptp_servo_start(
     53     int unit, 
     54     bcm_ptp_stack_id_t ptp_id,
     55     int clock_num)
     56 {   
     57     int rv = BCM_E_UNAVAIL;
     58     
     59     uint8 payload[PTP_MGMTMSG_PAYLOAD_MIN_PROPRIETARY_MSG_SIZE_OCTETS] = {0};
     60     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
     61     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
     62     int i = 0;
     63     
     64     bcm_ptp_port_identity_t portid;     
     65     
     66     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
     67             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
     68         return rv;   
     69     }
     70 
     71     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
     72             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
     73         /* On error, target message to (all clocks, all ports) portIdentity. */
     74         portid = portid_all;
     75     }
     76     
     77     /* 
     78      * Make payload.
     79      *    Octet 0...5 : Custom management message key/identifier. 
     80      *                  BCM<null><null><null>.
     81      */
     82     i = 0;
     83     payload[i++] = 'B';
     84     payload[i++] = 'C';
     85     payload[i++] = 'M';
     86     
     87     rv = _bcm_ptp_management_message_send(unit, ptp_id, clock_num, 
     88             &portid, PTP_MGMTMSG_CMD, PTP_MGMTMSG_ID_SERVO_START, 
     89             payload, PTP_MGMTMSG_PAYLOAD_MIN_PROPRIETARY_MSG_SIZE_OCTETS, 
     90             resp, &resp_len);
     91     
     92     return rv;
     93 }
     94 
     95 /*
     96  * Function:
     97  *      _bcm_ptp_servo_restart
     98  * Purpose:
     99  *      Restart PTP time synchronization servo.
    100  * Parameters:
    101  *      unit      - (IN) Unit number.
    102  *      ptp_id    - (IN) PTP stack ID.
    103  *      clock_num - (IN) PTP clock number.
    104  * Returns:
    105  *      BCM_E_XXX - Function status.
    106  * Notes:
    107  */
    108 int 
    109 _bcm_ptp_servo_restart(
    110     int unit, 
    111     bcm_ptp_stack_id_t ptp_id,
    112     int clock_num)
    113 {   
    114     /* Note: this is currently a No-op in the servo */
    115     int rv = BCM_E_UNAVAIL;
    116     
    117     uint8 payload[PTP_MGMTMSG_PAYLOAD_MIN_PROPRIETARY_MSG_SIZE_OCTETS] = {0};
    118     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    119     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    120     int i = 0;
    121     
    122     bcm_ptp_port_identity_t portid;     
    123     
    124     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    125             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    126         return rv;   
    127     }
    128 
    129     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    130             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    131         /* On error, target message to (all clocks, all ports) portIdentity. */
    132         portid = portid_all;
    133     }
    134     
    135     /* 
    136      * Make payload.
    137      *    Octet 0...5 : Custom management message key/identifier. 
    138      *                  BCM<null><null><null>.
    139      */
    140     i = 0;
    141     payload[i++] = 'B';
    142     payload[i++] = 'C';
    143     payload[i++] = 'M';
    144     
    145     rv = _bcm_ptp_management_message_send(unit, ptp_id, clock_num, 
    146             &portid, PTP_MGMTMSG_CMD, PTP_MGMTMSG_ID_SERVO_RESTART, 
    147             payload, PTP_MGMTMSG_PAYLOAD_MIN_PROPRIETARY_MSG_SIZE_OCTETS, 
    148             resp, &resp_len);
    149     
    150     return rv;
    151 }
    152 
    153 /*
    154  * Function:
    155  *      _bcm_ptp_servo_stop
    156  * Purpose:
    157  *      Stop PTP time synchronization servo.
    158  * Parameters:
    159  *      unit      - (IN) Unit number.
    160  *      ptp_id    - (IN) PTP stack ID.
    161  *      clock_num - (IN) PTP clock number.
    162  * Returns:
    163  *      BCM_E_XXX - Function status.
    164  * Notes:
    165  */
    166 int 
    167 _bcm_ptp_servo_stop(
    168     int unit, 
    169     bcm_ptp_stack_id_t ptp_id,
    170     int clock_num)
    171 {   
    172 
    173     /* Firmware does not support SERVO STOP. */
    174     return BCM_E_UNAVAIL;
    175 }
    176 
    177 /*
    178  * Function:
    179  *      bcm_common_ptp_servo_configuration_get
    180  * Purpose:
    181  *      Get PTP servo configuration properties.
    182  * Parameters:
    183  *      unit      - (IN)  Unit number.
    184  *      ptp_id    - (IN)  PTP stack ID.
    185  *      clock_num - (IN)  PTP clock number.
    186  *      config    - (OUT) PTP servo configuration properties.
    187  * Returns:
    188  *      BCM_E_XXX - Function status.
    189  * Notes:
    190  */
    191 int 
    192 bcm_common_ptp_servo_configuration_get(
    193     int unit, 
    194     bcm_ptp_stack_id_t ptp_id,
    195     int clock_num,
    196     bcm_ptp_servo_config_t *config)
    197 {   
    198     int rv = BCM_E_UNAVAIL;
    199     
    200     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    201     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    202     int i = 0;
    203 
    204     bcm_ptp_port_identity_t portid;
    205 
    206     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
    207             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    208         return rv;
    209     }
    210 
    211     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    212             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    213         /* On error, target message to (all clocks, all ports) portIdentity. */
    214         portid = portid_all;
    215     }
    216     
    217     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id, 
    218             clock_num, &portid, 
    219             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_CONFIGURATION, 
    220             0, 0, resp, &resp_len))) {
    221         return rv;
    222     }
    223     
    224     
    225     /*
    226      * Parse response.
    227      *    Octet 0...5   : Custom management message key/identifier. 
    228      *                    BCM<null><null><null>.
    229      *    Octet 6...9   : Oscillator type.    
    230      *    Octet 10...13 : PTP transport mode.
    231      *    Octet 14...17 : Phase Mode.
    232      *    Octet 18...21 : Freq. correction sampled hourly (times 1E+12).
    233      *    Octet 22...29 : Timestamp of freq. correction measurement (sec).
    234      *    Octet 30...33 : Timestamp of freq. correction measurement (nsec).
    235      *    Octet 34...37 : Flags
    236      *    Octet 38...45 : RFU
    237      *    Octet 46...49 : RFU
    238      *    Octet 50...53 : Bridge time.    
    239      *    Octet 54...57 : Filter Profile
    240      */
    241     i = 6;    
    242     config->osc_type = (bcm_ptp_osc_type_t)_bcm_ptp_uint32_read(resp+i);
    243     i += sizeof(uint32); 
    244     config->transport_mode = (bcm_ptp_transport_mode_t)_bcm_ptp_uint32_read(resp+i);
    245     i += sizeof(uint32);
    246     config->ptp_phase_mode = _bcm_ptp_uint32_read(resp+i);
    247     i += sizeof(uint32);
    248     config->freq_corr = _bcm_ptp_uint32_read(resp+i);
    249     i += sizeof(uint32);   
    250     config->freq_corr_time.seconds = _bcm_ptp_uint64_read(resp+i);
    251     i += sizeof(uint64);   
    252     config->freq_corr_time.nanoseconds = _bcm_ptp_uint32_read(resp+i);
    253     i += sizeof(uint32);  
    254     config->flags = _bcm_ptp_uint32_read(resp+i);
    255     config->servo = (config->flags & 0x0f);
    256     config->flags >>= 4;
    257     i += sizeof(uint32);   
    258     /* RFU */
    259     i += sizeof(uint64);   
    260     /* RFU */
    261     i += sizeof(uint32);   
    262     config->bridge_time = _bcm_ptp_uint32_read(resp+i);
    263     if (resp_len >= PTP_MGMTMSG_PAYLOAD_SERVO_CONFIGURATION_SIZE_OCTETS) {
    264         i += sizeof(uint32);
    265         config->filter_profile = _bcm_ptp_uint32_read(resp+i);
    266     } else {
    267         config->filter_profile = 0;
    268     }
    269     return rv;
    270 }
    271 
    272 /*
    273  * Function:
    274  *      bcm_common_ptp_servo_configuration_set
    275  * Purpose:
    276  *      Set PTP servo configuration properties.
    277  * Parameters:
    278  *      unit      - (IN) Unit number.
    279  *      ptp_id    - (IN) PTP stack ID.
    280  *      clock_num - (IN) PTP clock number.
    281  *      config    - (IN) PTP servo configuration properties.
    282  * Returns:
    283  *      BCM_E_XXX - Function status.
    284  * Notes:
    285  */
    286 int 
    287 bcm_common_ptp_servo_configuration_set(
    288     int unit, 
    289     bcm_ptp_stack_id_t ptp_id,
    290     int clock_num,
    291     bcm_ptp_servo_config_t *config)
    292 {   
    293 #ifdef BCM_PTP_EXT_SERVO_SUPPORT
    294     bcm_ptp_clock_info_t *clock_info;
    295 #endif
    296     int rv = BCM_E_UNAVAIL;
    297 
    298     uint8 payload[PTP_MGMTMSG_PAYLOAD_SERVO_CONFIGURATION_SIZE_OCTETS] = {0};
    299     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    300     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    301     int i = 0;
    302     
    303     bcm_ptp_port_identity_t portid;
    304     
    305     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    306             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    307         return rv;   
    308     }
    309     
    310     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    311             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    312         /* On error, target message to (all clocks, all ports) portIdentity. */
    313         portid = portid_all;
    314     }
    315 
    316 #if defined(BCM_PTP_INTERNAL_STACK_SUPPORT)
    317     if (SOC_HAS_PTP_INTERNAL_STACK_SUPPORT(unit)) {
    318         /* PTPPP firmware supports only bcm servo */
    319         if (BCM_SUCCESS(rv = _bcm_ptp_check_firmware_exist("PTP_BRCM_SERVO"))) {
    320             if (bcmPTPServoTypeBCM != config->servo) {
    321                 LOG_ERROR(BSL_LS_BCM_COMMON,
    322                           (BSL_META_U(unit,
    323                                   "PTP Phase profile firmware supports only Broadcom Servo \n")));
    324                 return BCM_E_PARAM;
    325             }
    326         }
    327     }
    328     
    329 #endif /* defined(BCM_PTP_INTERNAL_STACK_SUPPORT) */
    330 
    331 #ifdef BCM_PTP_EXT_SERVO_SUPPORT
    332     clock_info = &_bcm_common_ptp_unit_array[unit].stack_array[ptp_id].clock_array[clock_num].clock_info;
    333 
    334     if (PTP_CLOCK_IS_G8275P1_PROF(clock_info) && (bcmPTPServoTypeBCM != config->servo))
    335     {
    336         LOG_ERROR(BSL_LS_BCM_COMMON,
    337                           (BSL_META_U(unit, "Telecom phase profile supported only with Broadcom Servo \n")));
    338         return BCM_E_PARAM;
    339 	}
    340 
    341     _bcm_common_ptp_unit_array[unit].stack_array[ptp_id].clock_array[clock_num].servo_type = config->servo;
    342     if (config->osc_type != bcmPTPOscTypeOCXO) {
    343       /* Reinitialize servo w/ updated osc type  */
    344       if (BCM_FAILURE(rv = _bcm_ptp_servo_deinit(unit, ptp_id, clock_num))) {
    345         PTP_ERROR_FUNC("_bcm_ptp_servo_deinit()");
    346       }
    347       if (BCM_FAILURE(rv = _bcm_ptp_servo_init(unit, ptp_id, clock_num, config->osc_type))) {
    348         PTP_ERROR_FUNC("_bcm_ptp_servo_init()");
    349       }
    350     }
    351     else {
    352       LOG_INFO(BSL_LS_BCM_PTP,
    353         (BSL_META_U(unit, " Servo initialized w/ OCXO\n")));
    354     }
    355 #endif /* BCM_PTP_EXT_SERVO_SUPPORT */
    356 
    357     /*
    358      * Make payload.
    359      *    Octet 0...5   : Custom management message key/identifier. 
    360      *                    BCM<null><null><null>.
    361      *    Octet 6...9   : Oscillator type.    
    362      *    Octet 10...13 : PTP transport mode.
    363      *    Octet 14...17 : Phase Mode.
    364      *    Octet 18...21 : Freq. correction sampled hourly (times 1E+12).
    365      *    Octet 22...29 : Timestamp of freq. correction measurement (sec).
    366      *    Octet 30...33 : Timestamp of freq. correction measurement (nsec).
    367      *    Octet 34...37 : Freq. calibration from factory (times 1E+12).
    368      *    Octet 38...45 : Timestamp of freq. calibration at factory (sec).
    369      *    Octet 46...49 : Timestamp of freq. calibration at factory (nsec).
    370      *    Octet 50...53 : Bridge time.    
    371      *    Octet 54...57 : filter profile
    372      */
    373     i = 0;
    374     payload[i++] = 'B';
    375     payload[i++] = 'C';
    376     payload[i++] = 'M';
    377     i += 3;
    378     _bcm_ptp_uint32_write(payload+i, config->osc_type);
    379     i += sizeof(uint32);
    380     _bcm_ptp_uint32_write(payload+i, config->transport_mode);
    381     i += sizeof(uint32);
    382     _bcm_ptp_uint32_write(payload+i, config->ptp_phase_mode);
    383     i += sizeof(uint32);
    384     _bcm_ptp_uint32_write(payload+i, config->freq_corr);
    385     i += sizeof(uint32);
    386     _bcm_ptp_uint64_write(payload+i, config->freq_corr_time.seconds);
    387     i += sizeof(uint64);
    388     _bcm_ptp_uint32_write(payload+i, config->freq_corr_time.nanoseconds);
    389     i += sizeof(uint32);
    390     _bcm_ptp_uint32_write(payload+i, (config->servo | (config->flags << 4)));
    391     i += sizeof(uint32);
    392     /* RFU */
    393     i += sizeof(uint64);
    394     /* RFU */
    395     i += sizeof(uint32);
    396     _bcm_ptp_uint32_write(payload+i, config->bridge_time);
    397     i += sizeof(uint32);
    398     _bcm_ptp_uint32_write(payload+i, config->filter_profile);
    399     
    400     rv = _bcm_ptp_management_message_send(unit, ptp_id, clock_num, 
    401             &portid, PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_SERVO_CONFIGURATION, 
    402             payload, PTP_MGMTMSG_PAYLOAD_SERVO_CONFIGURATION_SIZE_OCTETS, 
    403             resp, &resp_len);
    404     
    405     return rv;
    406 }
    407 
    408 /*
    409  * Function:
    410  *      bcm_common_ptp_servo_threshold_get
    411  * Purpose:
    412  *      Get PTP servo threshold properties.
    413  * Parameters:
    414  *      unit      - (IN)  Unit number.
    415  *      ptp_id    - (IN)  PTP stack ID.
    416  *      clock_num - (IN)  PTP clock number.
    417  *      threshold    - (OUT) PTP servo configuration properties.
    418  * Returns:
    419  *      BCM_E_XXX - Function status.
    420  * Notes:
    421  */
    422 int
    423 bcm_common_ptp_servo_threshold_get(
    424     int unit,
    425     bcm_ptp_stack_id_t ptp_id,
    426     int clock_num,
    427     bcm_ptp_servo_threshold_t *threshold)
    428 {
    429     int rv = BCM_E_UNAVAIL;
    430  
    431     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    432     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
    433     int i = 0;
    434 
    435     bcm_ptp_port_identity_t portid; 
    436  
    437     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
    438             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    439         return rv;
    440     }
    441 
    442     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
    443             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    444         /* On error, target message to (all clocks, all ports) portIdentity. */
    445         portid = portid_all;
    446     }
    447 
    448     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
    449             clock_num, &portid,
    450             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_THRESHOLD,
    451             0, 0, resp, &resp_len))) {
    452         return rv;
    453     }
    454 
    455     if (resp_len < PTP_MGMTMSG_PAYLOAD_SERVO_THRESHOLD_SIZE_OCTETS) {
    456         /* Internal error : message too short to contain correct data. */
    457         return BCM_E_INTERNAL;
    458     }
    459 
    460     /*
    461      * Parse response.
    462      *    Octet 0...5   : Custom management message key/identifier.
    463      *                    BCM<null><null><null>.
    464      *    Octet 6...9   : Frequency Lock Threshold.
    465      *    Octet 10...13 : Frequency Unlock Threshold.
    466      *    Octet 14...17 : Phase Lock Threshold.
    467      *    Octet 18...21 : Phase Unlock Threshold.
    468      */
    469     i = 6;
    470     threshold->bcmPtpServoThresholdFreqLock = _bcm_ptp_uint32_read(resp+i);
    471     i += sizeof(uint32); 
    472     threshold->bcmPtpServoThresholdFreqUnlock = _bcm_ptp_uint32_read(resp+i);
    473     i += sizeof(uint32); 
    474     threshold->bcmPtpServoThresholdPhaseLock = _bcm_ptp_uint32_read(resp+i);
    475     i += sizeof(uint32); 
    476     threshold->bcmPtpServoThresholdPhaseUnlock = _bcm_ptp_uint32_read(resp+i);
    477     
    478     return rv;
    479 }
    480 
    481 
    482 /*
    483  * Function:
    484  *      bcm_common_ptp_servo_threshold_set
    485  * Purpose:
    486  *      Set PTP servo threshold properties.
    487  * Parameters:
    488  *      unit      - (IN) Unit number.
    489  *      ptp_id    - (IN) PTP stack ID.
    490  *      clock_num - (IN) PTP clock number.
    491  *      threshold - (IN) PTP servo threshold properties.
    492  * Returns:
    493  *      BCM_E_XXX - Function status.
    494  * Notes:
    495  */
    496 int
    497 bcm_common_ptp_servo_threshold_set(
    498     int unit,
    499     bcm_ptp_stack_id_t ptp_id,
    500     int clock_num,
    501     bcm_ptp_servo_threshold_t *threshold)
    502 {
    503     int rv = BCM_E_UNAVAIL;
    504  
    505     uint8 payload[PTP_MGMTMSG_PAYLOAD_SERVO_THRESHOLD_SIZE_OCTETS] = {0};
    506     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    507     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
    508     int i = 0;
    509 
    510     bcm_ptp_port_identity_t portid;
    511 
    512     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
    513             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    514         return rv;
    515     }
    516 
    517     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
    518             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    519         /* On error, target message to (all clocks, all ports) portIdentity. */
    520         portid = portid_all;
    521     }
    522  
    523     /*
    524      * Make payload.
    525      *    Octet 0...5   : Custom management message key/identifier.
    526      *    Octet 6...9   : Frequency Lock Threshold.
    527      *    Octet 10...13 : Frequency Unlock Threshold.
    528      *    Octet 14...17 : Phase Lock Threshold.
    529      *    Octet 18...21 : Phase Unlock Threshold.
    530      */
    531     i = 0;
    532     payload[i++] = 'B';
    533     payload[i++] = 'C';
    534     payload[i++] = 'M';
    535     i +=3;
    536     _bcm_ptp_uint32_write(payload+i, threshold->bcmPtpServoThresholdFreqLock);
    537     i += sizeof(uint32); 
    538     _bcm_ptp_uint32_write(payload+i, threshold->bcmPtpServoThresholdFreqUnlock);
    539     i += sizeof(uint32); 
    540     _bcm_ptp_uint32_write(payload+i, threshold->bcmPtpServoThresholdPhaseLock);
    541     i += sizeof(uint32); 
    542     _bcm_ptp_uint32_write(payload+i, threshold->bcmPtpServoThresholdPhaseUnlock);
    543 
    544     rv = _bcm_ptp_management_message_send(unit, ptp_id, clock_num,
    545             &portid, PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_SERVO_THRESHOLD,
    546             payload, PTP_MGMTMSG_PAYLOAD_SERVO_THRESHOLD_SIZE_OCTETS,
    547             resp, &resp_len);
    548  
    549     return rv;
    550 }
    551 
    552 /*
    553  * Function:
    554  *      _bcm_ptp_servo_ipdv_configuration_get
    555  * Purpose:
    556  *      Get PTP servo IP packet delay variation (IPDV) configuration properties.
    557  * Parameters:
    558  *      unit      - (IN)  Unit number.
    559  *      ptp_id    - (IN)  PTP stack ID.
    560  *      clock_num - (IN)  PTP clock number.
    561  *      config    - (OUT) PTP servo IPDV configuration properties.
    562  * Returns:
    563  *      BCM_E_XXX - Function status.
    564  * Notes:
    565  */
    566 int 
    567 _bcm_ptp_servo_ipdv_configuration_get(
    568     int unit, 
    569     bcm_ptp_stack_id_t ptp_id,
    570     int clock_num,
    571     _bcm_ptp_ipdv_config_t *config)
    572 {   
    573     int rv = BCM_E_UNAVAIL;
    574     
    575     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    576     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    577     int i = 0;
    578 
    579     bcm_ptp_port_identity_t portid;     
    580     
    581     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    582             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    583         return rv;   
    584     }
    585     
    586     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    587             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    588         /* On error, target message to (all clocks, all ports) portIdentity. */
    589         portid = portid_all;
    590     }
    591     
    592     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id, 
    593             clock_num, &portid, 
    594             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_IPDV_CONFIGURATION, 
    595             0, 0, resp, &resp_len))) {
    596         return rv;
    597     }
    598     
    599     if (resp_len < PTP_MGMTMSG_PAYLOAD_SERVO_IPDV_CONFIGURATION_SIZE_OCTETS) {
    600         /* Internal error : message too short to contain correct data. */
    601         return BCM_E_INTERNAL;
    602     }
    603     
    604     /*
    605      * Parse response.
    606      *    Octet 0...5   : Custom management message key/identifier. 
    607      *                    BCM<null><null><null>.
    608      *    Octet 6...7   : IPDV observation interval.    
    609      *    Octet 8...11  : IPDV threshold (nsec).
    610      *    Octet 12...13 : IPDV pacing factor.
    611      */
    612     i = 6;
    613     config->observation_interval = _bcm_ptp_uint16_read(resp+i);
    614     i += sizeof(uint16);   
    615     config->threshold = (int32)_bcm_ptp_uint32_read(resp+i);
    616     i += sizeof(uint32);   
    617     config->pacing_factor = _bcm_ptp_uint16_read(resp+i);
    618     
    619     
    620     return rv;
    621 }
    622 
    623 /*
    624  * Function:
    625  *      _bcm_ptp_servo_ipdv_configuration_set
    626  * Purpose:
    627  *      Set PTP servo IP packet delay variation (IPDV) configuration properties.
    628  * Parameters:
    629  *      unit      - (IN) Unit number.
    630  *      ptp_id    - (IN) PTP stack ID.
    631  *      clock_num - (IN) PTP clock number.
    632  *      config    - (IN) PTP servo IPDV configuration properties.
    633  * Returns:
    634  *      BCM_E_XXX - Function status.
    635  * Notes:
    636  */
    637 int 
    638 _bcm_ptp_servo_ipdv_configuration_set(
    639     int unit, 
    640     bcm_ptp_stack_id_t ptp_id,
    641     int clock_num,
    642     const _bcm_ptp_ipdv_config_t config)
    643 {   
    644     int rv = BCM_E_UNAVAIL;
    645     
    646     uint8 payload[PTP_MGMTMSG_PAYLOAD_SERVO_IPDV_CONFIGURATION_SIZE_OCTETS] = {0};
    647     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    648     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    649     int i = 0;
    650     
    651     bcm_ptp_port_identity_t portid;     
    652         
    653     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    654             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    655         return rv;   
    656     }
    657     
    658     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    659             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    660         /* On error, target message to (all clocks, all ports) portIdentity. */
    661         portid = portid_all;
    662     }
    663     
    664     /*
    665      * Parse response.
    666      *    Octet 0...5   : Custom management message key/identifier. 
    667      *                    BCM<null><null><null>.
    668      *    Octet 6...7   : IPDV observation interval.    
    669      *    Octet 8...11  : IPDV threshold (nsec).
    670      *    Octet 12...13 : IPDV pacing factor.
    671      */
    672     i = 0;
    673     payload[i++] = 'B';
    674     payload[i++] = 'C';
    675     payload[i++] = 'M';
    676     i += 3;
    677     _bcm_ptp_uint16_write(payload+i, config.observation_interval);
    678     i += sizeof(uint16);    
    679     _bcm_ptp_uint32_write(payload+i, (uint32)config.threshold);
    680     i += sizeof(uint32);    
    681     _bcm_ptp_uint16_write(payload+i, config.pacing_factor);
    682     
    683     rv = _bcm_ptp_management_message_send(unit, ptp_id, clock_num, 
    684             &portid, PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_SERVO_IPDV_CONFIGURATION, 
    685             payload, PTP_MGMTMSG_PAYLOAD_SERVO_IPDV_CONFIGURATION_SIZE_OCTETS, 
    686             resp, &resp_len);
    687     
    688     return rv;
    689 }
    690 
    691 /*
    692  * Function:
    693  *      _bcm_ptp_servo_performance_get
    694  * Purpose:
    695  *      Get PTP servo performance data / metrics.
    696  * Parameters:
    697  *      unit      - (IN)  Unit number.
    698  *      ptp_id    - (IN)  PTP stack ID.
    699  *      clock_num - (IN)  PTP clock number.
    700  *      perf      - (OUT) PTP servo performance data / metrics.
    701  * Returns:
    702  *      BCM_E_XXX - Function status.
    703  * Notes:
    704  */
    705 int 
    706 _bcm_ptp_servo_performance_get(
    707     int unit, 
    708     bcm_ptp_stack_id_t ptp_id,
    709     int clock_num,
    710     _bcm_ptp_servo_performance_t *perf)
    711 {   
    712     int rv = BCM_E_UNAVAIL;
    713     
    714     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    715     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    716     int i = 0;
    717 
    718     bcm_ptp_port_identity_t portid;     
    719     
    720     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    721             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    722         return rv;   
    723     }
    724     
    725     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    726             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    727         /* On error, target message to (all clocks, all ports) portIdentity. */
    728         portid = portid_all;
    729     }
    730     
    731     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id, 
    732             clock_num, &portid, 
    733             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_PERFORMANCE, 
    734             0, 0, resp, &resp_len))) {
    735         return rv;
    736     }
    737     
    738     if (resp_len < PTP_MGMTMSG_PAYLOAD_SERVO_PERFORMANCE_SIZE_OCTETS) {
    739         /* Internal error : message too short to contain correct data. */
    740         return BCM_E_INTERNAL;
    741     }
    742     
    743     /*
    744      * Parse response.
    745      *    Octet 0...5     : Custom management message key/identifier. 
    746      *                      BCM<null><null><null>.
    747      *    Octet 6         : FLL state enumeration.
    748      *    Octet 7...10    : FLL state duration (sec).
    749      *    Octet 11...18   : Forward flow weight.
    750      *    Octet 19...22   : Forward flow transient-free (900 sec window).
    751      *    Octet 23...26   : Forward flow transient-free (3600 sec window).
    752      *    Octet 27...34   : Forward flow transactions used (%).
    753      *    Octet 35...42   : Forward flow operational min TDEV (nsec).
    754      *    Octet 43...50   : Forward Mafie.
    755      *    Octet 51...58   : Forward flow min cluster width (nsec).
    756      *    Octet 59...66   : Forward flow mode width (nsec).
    757      *    Octet 67...74   : Reverse flow weight.
    758      *    Octet 75...78   : Reverse flow transient-free (900 sec window).
    759      *    Octet 79...82   : Reverse flow transient-free (3600 sec window).
    760      *    Octet 83...90   : Reverse flow transactions used (%).
    761      *    Octet 91...98   : Reverse flow operational min TDEV (nsec).
    762      *    Octet 99...106  : Reverse Mafie.
    763      *    Octet 107...114 : Reverse flow min cluster width (nsec).
    764      *    Octet 115...122 : Reverse flow mode width (nsec).
    765      *    Octet 123...130 : Frequency correction (ppb).
    766      *    Octet 131...138 : Phase correction (ppb).
    767      *    Octet 139...146 : Output TDEV estimate (nsec).
    768      *    Octet 147...154 : Output MDEV estimate (ppb).
    769      *    Octet 155...162 : Residual phase error (nsec).
    770      *    Octet 163...170 : Minimum round trip delay (nsec).
    771      *    Octet 171...172 : Sync packet rate (pkts/sec).
    772      *    Octet 173...174 : Delay packet rate (pkts/sec).
    773      *    Octet 175...182 : Forward IPDV % below threshold.
    774      *    Octet 183...190 : Forward maximum IPDV (usec).
    775      *    Octet 191...198 : Forward interpacket jitter (usec).
    776      *    Octet 199...206 : Reverse IPDV % below threshold.
    777      *    Octet 207...214 : Reverse maximum IPDV (usec).
    778      *    Octet 215...222 : Reverse interpacket jitter (usec). 
    779      */
    780     i = 6;
    781     perf->status.servo_state = (bcm_ptp_servo_state_t)resp[i++];
    782     perf->status.servo_state_dur = _bcm_ptp_uint32_read(resp+i);
    783     i += sizeof(uint32);
    784     perf->fwd_weight = _bcm_ptp_uint64_read(resp+i);
    785     i += sizeof(uint64);
    786     perf->fwd_trans_free_900 = _bcm_ptp_uint32_read(resp+i);
    787     i += sizeof(uint32);
    788     perf->fwd_trans_free_3600 = _bcm_ptp_uint32_read(resp+i);
    789     i += sizeof(uint32);
    790     perf->fwd_pct = _bcm_ptp_uint64_read(resp+i);
    791     i += sizeof(uint64);
    792     perf->fwd_min_Tdev = _bcm_ptp_uint64_read(resp+i);
    793     i += sizeof(uint64);
    794     perf->fwd_Mafie = _bcm_ptp_uint64_read(resp+i);
    795     i += sizeof(uint64);
    796     perf->fwd_min_cluster_width = _bcm_ptp_uint64_read(resp+i);
    797     i += sizeof(uint64);
    798     perf->fwd_mode_width = _bcm_ptp_uint64_read(resp+i);
    799     i += sizeof(uint64);
    800     perf->rev_weight = _bcm_ptp_uint64_read(resp+i);
    801     i += sizeof(uint64);
    802     perf->rev_trans_free_900 = _bcm_ptp_uint32_read(resp+i);
    803     i += sizeof(uint32);
    804     perf->rev_trans_free_3600 = _bcm_ptp_uint32_read(resp+i);
    805     i += sizeof(uint32);
    806     perf->rev_pct = _bcm_ptp_uint64_read(resp+i);
    807     i += sizeof(uint64);
    808     perf->rev_min_Tdev = _bcm_ptp_uint64_read(resp+i);
    809     i += sizeof(uint64);
    810     perf->rev_Mafie = _bcm_ptp_uint64_read(resp+i);
    811     i += sizeof(uint64);
    812     perf->rev_min_cluster_width = _bcm_ptp_uint64_read(resp+i);
    813     i += sizeof(uint64);
    814     perf->rev_mode_width = _bcm_ptp_uint64_read(resp+i);
    815     i += sizeof(uint64);
    816     perf->freq_correction = _bcm_ptp_int64_read(resp+i);
    817     i += sizeof(uint64);
    818     perf->phase_correction = _bcm_ptp_int64_read(resp+i);
    819     i += sizeof(uint64);
    820     perf->tdev_estimate = _bcm_ptp_uint64_read(resp+i);
    821     i += sizeof(uint64);
    822     perf->mdev_estimate = _bcm_ptp_uint64_read(resp+i);
    823     i += sizeof(uint64);
    824     perf->residual_phase_error = _bcm_ptp_int64_read(resp+i);
    825     i += sizeof(uint64);
    826     perf->min_round_trip_delay = _bcm_ptp_uint64_read(resp+i);
    827     i += sizeof(uint64);
    828     perf->fwd_pkt_rate = _bcm_ptp_uint16_read(resp+i);
    829     i += sizeof(uint16);
    830     perf->rev_pkt_rate = _bcm_ptp_uint16_read(resp+i);
    831     i += sizeof(uint16);
    832     perf->ipdv_data.fwd_pct = _bcm_ptp_uint64_read(resp+i);
    833     i += sizeof(uint64);
    834     perf->ipdv_data.fwd_max = _bcm_ptp_uint64_read(resp+i);
    835     i += sizeof(uint64);
    836     perf->ipdv_data.fwd_jitter = _bcm_ptp_uint64_read(resp+i);
    837     i += sizeof(uint64);
    838     perf->ipdv_data.rev_pct = _bcm_ptp_uint64_read(resp+i);
    839     i += sizeof(uint64);
    840     perf->ipdv_data.rev_max = _bcm_ptp_uint64_read(resp+i);
    841     i += sizeof(uint64);
    842     perf->ipdv_data.rev_jitter = _bcm_ptp_uint64_read(resp+i);
    843 
    844     /* Get TDEV/MDEV from CTDEV if not available from the servo: */
    845     if ((COMPILER_64_HI(perf->tdev_estimate) == 0xffffffff) &&
    846         (COMPILER_64_LO(perf->tdev_estimate) == 0xffffffff)) {
    847         /* Get TDEV estimate with tau = 128 */
    848         if (_bcm_ptp_ctdev_get(unit, ptp_id, clock_num, 128, &perf->tdev_estimate) == BCM_E_NONE) {
    849             /* Estimate MDEV: TDEV * sqrt(3) / tau ~= TDEV / 74  */
    850             perf->mdev_estimate = _bcm_ptp_llu_div(perf->tdev_estimate, 74);
    851         } else {
    852             /* No CTDEV data */
    853             COMPILER_64_ZERO(perf->tdev_estimate);
    854             COMPILER_64_ZERO(perf->mdev_estimate);
    855         }
    856     }
    857     
    858     return rv;
    859 }
    860 
    861 /*
    862  * Function:
    863  *      _bcm_ptp_servo_ipdv_performance_get
    864  * Purpose:
    865  *      Get PTP servo IP packet delay variation (IPDV) performance data / metrics.
    866  * Parameters:
    867  *      unit      - (IN)  Unit number.
    868  *      ptp_id    - (IN)  PTP stack ID.
    869  *      clock_num - (IN)  PTP clock number.
    870  *      perf      - (OUT) PTP servo IPDV performance data / metrics.
    871  * Returns:
    872  *      BCM_E_XXX - Function status.
    873  * Notes:
    874  */
    875 int 
    876 _bcm_ptp_servo_ipdv_performance_get(
    877     int unit, 
    878     bcm_ptp_stack_id_t ptp_id,
    879     int clock_num,
    880     _bcm_ptp_ipdv_performance_t *perf)
    881 {   
    882     int rv = BCM_E_UNAVAIL;
    883     
    884     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    885     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    886     int i = 0;
    887 
    888     bcm_ptp_port_identity_t portid;     
    889     
    890     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    891             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    892         return rv;   
    893     }
    894     
    895     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    896             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    897         /* On error, target message to (all clocks, all ports) portIdentity. */
    898         portid = portid_all;
    899     }
    900     
    901     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id, 
    902             clock_num, &portid, 
    903             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_IPDV_PERFORMANCE, 
    904             0, 0, resp, &resp_len))) {
    905         return rv;
    906     }
    907     
    908     if (resp_len < PTP_MGMTMSG_PAYLOAD_SERVO_IPDV_PERFORMANCE_SIZE_OCTETS) {
    909         /* Internal error : message too short to contain correct data. */
    910         return BCM_E_INTERNAL;
    911     }
    912     
    913     /*
    914      * Parse response.
    915      *    Octet 0...5   : Custom management message key/identifier. 
    916      *                    BCM<null><null><null>.
    917      *    Octet 6...13  : Forward IPDV % below threshold.
    918      *    Octet 14...21 : Forward maximum IPDV (usec).
    919      *    Octet 22...29 : Forward interpacket jitter (usec).
    920      *    Octet 30...37 : Reverse IPDV % below threshold.
    921      *    Octet 38...45 : Reverse maximum IPDV (usec).
    922      *    Octet 46...53 : Reverse interpacket jitter (usec). 
    923      */
    924     i = 6;
    925     perf->fwd_pct = _bcm_ptp_uint64_read(resp+i);
    926     i += sizeof(uint64);
    927     perf->fwd_max = _bcm_ptp_uint64_read(resp+i);
    928     i += sizeof(uint64);
    929     perf->fwd_jitter = _bcm_ptp_uint64_read(resp+i);
    930     i += sizeof(uint64);
    931     perf->rev_pct = _bcm_ptp_uint64_read(resp+i);
    932     i += sizeof(uint64);
    933     perf->rev_max = _bcm_ptp_uint64_read(resp+i);
    934     i += sizeof(uint64);
    935     perf->rev_jitter = _bcm_ptp_uint64_read(resp+i);
    936     
    937     return rv;
    938 }
    939 
    940 /*
    941  * Function:
    942  *      _bcm_ptp_servo_performance_data_clear
    943  * Purpose:
    944  *      Clear (reset) PTP servo performance data / metrics.
    945  * Parameters:
    946  *      unit      - (IN) Unit number.
    947  *      ptp_id    - (IN) PTP stack ID.
    948  *      clock_num - (IN) PTP clock number.
    949  * Returns:
    950  *      BCM_E_XXX - Function status.
    951  * Notes:
    952  */
    953 int 
    954 _bcm_ptp_servo_performance_data_clear(
    955     int unit, 
    956     bcm_ptp_stack_id_t ptp_id,
    957     int clock_num)
    958 {   
    959     int rv = BCM_E_UNAVAIL;
    960     
    961     uint8 payload[PTP_MGMTMSG_PAYLOAD_MIN_PROPRIETARY_MSG_SIZE_OCTETS] = {0};
    962     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
    963     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
    964     int i = 0;
    965     
    966     bcm_ptp_port_identity_t portid;     
    967     
    968     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
    969             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
    970         return rv;   
    971     }
    972 
    973     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
    974             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
    975         /* On error, target message to (all clocks, all ports) portIdentity. */
    976         portid = portid_all;
    977     }
    978     
    979     /* 
    980      * Make payload.
    981      *    Octet 0...5 : Custom management message key/identifier. 
    982      *                  BCM<null><null><null>.
    983      */
    984     i = 0;
    985     payload[i++] = 'B';
    986     payload[i++] = 'C';
    987     payload[i++] = 'M';
    988     
    989     rv = _bcm_ptp_management_message_send(unit, ptp_id, clock_num, 
    990             &portid, PTP_MGMTMSG_CMD, PTP_MGMTMSG_ID_SERVO_COUNTERS_CLEAR, 
    991             payload, PTP_MGMTMSG_PAYLOAD_MIN_PROPRIETARY_MSG_SIZE_OCTETS, 
    992             resp, &resp_len);
    993     
    994     return rv;
    995 }
    996 
    997 /*
    998  * Function:
    999  *      bcm_common_ptp_servo_status_get
   1000  * Purpose:
   1001  *      Get PTP servo state and status information.
   1002  * Parameters:
   1003  *      unit      - (IN)  Unit number.
   1004  *      ptp_id    - (IN)  PTP stack ID.
   1005  *      clock_num - (IN)  PTP clock number.
   1006  *      status    - (OUT) PTP servo state and status information.
   1007  * Returns:
   1008  *      BCM_E_XXX - Function status.
   1009  * Notes:
   1010  */
   1011 int 
   1012 bcm_common_ptp_servo_status_get(
   1013     int unit, 
   1014     bcm_ptp_stack_id_t ptp_id,
   1015     int clock_num,
   1016     bcm_ptp_servo_status_t *status)
   1017 {   
   1018     int rv = BCM_E_UNAVAIL;
   1019     
   1020     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1021     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
   1022     int i = 0;
   1023 
   1024     bcm_ptp_port_identity_t portid;     
   1025     
   1026     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
   1027             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1028         return rv;   
   1029     }
   1030     
   1031     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
   1032             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1033         /* On error, target message to (all clocks, all ports) portIdentity. */
   1034         portid = portid_all;
   1035     }
   1036     
   1037     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id, 
   1038             clock_num, &portid, 
   1039             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_STATUS, 
   1040             0, 0, resp, &resp_len))) {
   1041         return rv;
   1042     }
   1043     
   1044     if (resp_len < PTP_MGMTMSG_PAYLOAD_SERVO_STATUS_SIZE_OCTETS) {
   1045         /* Internal error : message too short to contain correct data. */
   1046         return BCM_E_INTERNAL;
   1047     }
   1048     
   1049     /*
   1050      * Parse response.
   1051      *    Octet 0...5     : Custom management message key/identifier. 
   1052      *                      BCM<null><null><null>.
   1053      *    Octet 6         : FLL state enumeration.
   1054      *    Octet 7...10    : FLL state duration (sec).
   1055      *    Octet 11...14        : Locked Status enumeration.
   1056      */
   1057     i = 6;
   1058 
   1059     status->servo_state = (bcm_ptp_servo_state_t)resp[i++];
   1060     status->servo_state_dur = _bcm_ptp_uint32_read(resp+i);
   1061     i += 4;
   1062     status->lock_status = (bcm_ptp_servo_lock_status_t)resp[i];
   1063 
   1064 
   1065     return rv;
   1066 }
   1067 
   1068 /*
   1069  * Function:
   1070  *      _bcm_ptp_servo_state_set
   1071  * Purpose:
   1072  *      set PTP servo state and status information.
   1073  * Parameters:
   1074  *      unit      - (IN)  Unit number.
   1075  *      ptp_id    - (IN)  PTP stack ID.
   1076  *      clock_num - (IN)  PTP clock number.
   1077  *      state     - (IN)  PTP ext-servo's state.
   1078  * Returns:
   1079  *      BCM_E_XXX - Function status.
   1080  * Notes:
   1081  */
   1082 int 
   1083 _bcm_ptp_servo_state_set(
   1084     int unit, 
   1085     bcm_ptp_stack_id_t ptp_id,
   1086     int clock_num,
   1087     int servo_state)
   1088 {   
   1089     int rv = BCM_E_UNAVAIL;
   1090     
   1091     uint8 payload[32] = {0};
   1092     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1093     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS; 
   1094     int i = 0;
   1095 
   1096     bcm_ptp_port_identity_t portid;     
   1097     
   1098     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id, 
   1099             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1100         return rv;   
   1101     }
   1102     
   1103     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id, 
   1104             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1105         /* On error, target message to (all clocks, all ports) portIdentity. */
   1106         portid = portid_all;
   1107     }
   1108 
   1109     i = 0;
   1110     payload[i++] = 'B';
   1111     payload[i++] = 'C';
   1112     payload[i++] = 'M';
   1113     payload[i++] = '\0';
   1114     payload[i++] = '\0';
   1115     payload[i++] = '\0';
   1116 
   1117     _bcm_ptp_uint32_write(payload + i, servo_state);
   1118     i += 4;
   1119 
   1120     rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1121             clock_num, &portid,
   1122             PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_SERVO_STATUS,
   1123             payload, i,
   1124             resp, &resp_len);
   1125     
   1126     return rv;
   1127 }
   1128 
   1129 /*
   1130  * Function:
   1131  *      bcm_common_ptp_phase_offset_set
   1132  * Purpose:
   1133  *      Set phase offsets for path asymmetry compensation
   1134  * Parameters:
   1135  *      unit - Unit number 
   1136  *      ptp_id - PTP stack ID
   1137  *      clock_num - PTP clock number
   1138  *      *offset - PTP servo phase holdover state offsets
   1139  * Returns:
   1140  *      int
   1141  * Notes:
   1142  */
   1143 
   1144 int
   1145 bcm_common_ptp_phase_offset_set(
   1146      int unit,
   1147      bcm_ptp_stack_id_t ptp_id,
   1148      int clock_num,
   1149      const bcm_ptp_phase_offset_t *offset) 
   1150 {
   1151     int rc;
   1152     bcm_ptp_phase_holdover_state_t state;
   1153     state.phase_slew_rate_ppb    = offset->phase_slew_rate_ppb;
   1154     state.sync_phase_offset_ns   = offset->sync_phase_offset_ns;
   1155     state.reported_phase_offset  = offset->reported_phase_offset;
   1156     state.delta_phase_offset     = offset->delta_phase_offset;
   1157     state.fixed_phase_offset     = offset->fixed_phase_offset;
   1158     state.use_fixed_phase_offset = offset->use_fixed_phase_offset;
   1159 
   1160     rc = _bcm_ptp_phase_holdover_set(unit, ptp_id, clock_num, &state);
   1161     
   1162     return (rc);
   1163 }
   1164 
   1165 /*
   1166  * Function:
   1167  *      bcm_common_ptp_phase_offset_get
   1168  * Purpose:
   1169  *      Get phase offsets for path asymmetry compensation
   1170  * Parameters:
   1171  *      unit - Unit number 
   1172  *      ptp_id - PTP stack ID
   1173  *      clock_num - PTP clock number
   1174  *      *offset - PTP servo phase holdover state offsets
   1175  * Returns:
   1176  *      int
   1177  * Notes:
   1178  */
   1179 
   1180 int
   1181 bcm_common_ptp_phase_offset_get(
   1182      int unit,
   1183      bcm_ptp_stack_id_t ptp_id,
   1184      int clock_num,
   1185      bcm_ptp_phase_offset_t *offset) 
   1186 {
   1187     int rc;
   1188     bcm_ptp_phase_holdover_state_t state;
   1189 
   1190 
   1191     rc = _bcm_ptp_phase_holdover_get(unit, ptp_id, clock_num, &state);
   1192 
   1193     offset->reported_phase_offset = state.reported_phase_offset;
   1194     offset->delta_phase_offset = state.delta_phase_offset;
   1195     offset->fixed_phase_offset = state.fixed_phase_offset;
   1196     offset->use_fixed_phase_offset = state.use_fixed_phase_offset;
   1197     offset->phase_slew_rate_ppb = state.phase_slew_rate_ppb;
   1198     offset->sync_phase_offset_ns = state.sync_phase_offset_ns;
   1199 
   1200     return (rc);
   1201 }
   1202 
   1203 
   1204 /*
   1205  * Function:
   1206  *      _bcm_ptp_servo_phase_offset_get
   1207  * Purpose:
   1208  *      Get phase offsets for external servo
   1209  * Parameters:
   1210  *      unit      - (IN)  Unit number.
   1211  *      ptp_id    - (IN)  PTP stack ID.
   1212  *      clock_num - (IN)  PTP clock number.
   1213  *      state     - (OUT) PTP servo phase holdover state
   1214  * Returns:
   1215  *      BCM_E_XXX - Function status.
   1216  * Notes:
   1217  */
   1218 int
   1219 _bcm_ptp_servo_phase_offset_get(
   1220     int unit,
   1221     bcm_ptp_stack_id_t ptp_id,
   1222     int clock_num,
   1223     int64 *phase_offset)
   1224 {
   1225     int rv;
   1226     int i;
   1227 
   1228     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1229     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
   1230 
   1231     bcm_ptp_port_identity_t portid;
   1232 
   1233     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
   1234             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1235         return rv;
   1236     }
   1237 
   1238     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
   1239             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1240         /* On error, target message to (all clocks, all ports) portIdentity. */
   1241         portid = portid_all;
   1242     }
   1243 
   1244     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1245             clock_num, &portid,
   1246             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_SERVO_PHASE_OFFSET,
   1247             0, 0, resp, &resp_len))) {
   1248         return rv;
   1249     }
   1250 
   1251     /*
   1252      * Parse response.
   1253      *    Octet 0...5   : Custom management message key/identifier.
   1254      *                    BCM<null><null><null>.
   1255      *    Octet 6...13  : Reported phase offset.
   1256      */
   1257     i = 6;
   1258     *phase_offset = _bcm_ptp_int64_read(resp + i);
   1259     i += 8;
   1260 
   1261     return BCM_E_NONE;
   1262 }
   1263 
   1264 /*
   1265  * Function:  _bcm_ptp_servo_phase_offset_set
   1266  *      
   1267  * Purpose:
   1268  *      Set phase offsets for path asymmetry compensation.
   1269  * Parameters:
   1270  *      unit      - (IN)  Unit number.
   1271  *      ptp_id    - (IN)  PTP stack ID.
   1272  *      clock_num - (IN)  PTP clock number.
   1273  *      state     - (IN) PTP servo phase holdover state
   1274  * Returns:
   1275  *      BCM_E_XXX - Function status.
   1276  * Notes:
   1277  */
   1278 #ifndef __KERNEL__
   1279 int
   1280 _bcm_ptp_servo_phase_offset_set(
   1281     int unit,
   1282     bcm_ptp_stack_id_t ptp_id,
   1283     int clock_num,
   1284     const double *phase_offset)
   1285 #else
   1286 int
   1287 _bcm_ptp_servo_phase_offset_set(
   1288     int unit,
   1289     bcm_ptp_stack_id_t ptp_id,
   1290     int clock_num,
   1291     const int64 *phase_offset)
   1292 #endif /* __KERNEL__ */
   1293 {
   1294     int rv;
   1295     int i;
   1296     int64 phase_off;
   1297 
   1298     uint8 payload[PTP_MGMTMSG_PAYLOAD_PHASE_OFFSET_SIZE_OCTETS] = {0};
   1299     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1300     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
   1301 
   1302     bcm_ptp_port_identity_t portid;
   1303 
   1304     if(g_apts_enabled &&
   1305             (g_apts_current_op_mode != bcmPtpClockAptsModeSyncEHoldover) &&
   1306             (g_apts_current_op_mode != bcmPtpClockAptsModeHoldoverHoldover)){
   1307         /* Do not apply phase corrections from servo */
   1308         rv = BCM_E_NONE;
   1309         return rv;
   1310     }
   1311     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
   1312             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1313         return rv;
   1314     }
   1315 
   1316     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
   1317             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1318         /* On error, target message to (all clocks, all ports) portIdentity. */
   1319         portid = portid_all;
   1320     }
   1321 
   1322     phase_off = *phase_offset;
   1323 
   1324 #ifndef __KERNEL__
   1325     LOG_INFO(BSL_LS_BCM_PTP,
   1326             (BSL_META_U(unit, "servo phase offset set[%lf] phase_off[%lld: %llx]\n"),
   1327                 (double)*phase_offset, (long long int)phase_off, (long long unsigned int)phase_off));
   1328 #else
   1329     LOG_INFO(BSL_LS_BCM_PTP,
   1330             (BSL_META_U(unit, "servo phase offset phase_off[%lld: %llx]\n"),
   1331                 (long long int)phase_off, (long long unsigned int)phase_off));
   1332 #endif /* __KERNEL__ */
   1333     /*
   1334      * Make payload.
   1335      *    Octet 0...5   : Custom management message key/identifier.
   1336      *                    BCM<null><null><null>.
   1337      *    Octet 6...13 : phase  offset.
   1338      */
   1339     i = 0;
   1340     payload[i++] = 'B';
   1341     payload[i++] = 'C';
   1342     payload[i++] = 'M';
   1343     payload[i++] = '\0';
   1344     payload[i++] = '\0';
   1345     payload[i++] = '\0';
   1346 
   1347     _bcm_ptp_int64_write(payload + i, phase_off);
   1348     i += 8;
   1349 
   1350     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1351             clock_num, &portid,
   1352             PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_SERVO_PHASE_OFFSET,
   1353             payload, PTP_MGMTMSG_PAYLOAD_SERVO_PHASE_OFFSET_SIZE_OCTETS,
   1354             resp, &resp_len))) {
   1355         return rv;
   1356     }
   1357 
   1358     return BCM_E_NONE;
   1359 }
   1360 
   1361 /*
   1362  * Function:
   1363  *      _bcm_ptp_phase_holdover_get
   1364  * Purpose:
   1365  *      Get phase offsets for path asymmetry compensation.
   1366  * Parameters:
   1367  *      unit      - (IN)  Unit number.
   1368  *      ptp_id    - (IN)  PTP stack ID.
   1369  *      clock_num - (IN)  PTP clock number.
   1370  *      state     - (OUT) PTP servo phase holdover state
   1371  * Returns:
   1372  *      BCM_E_XXX - Function status.
   1373  * Notes:
   1374  */
   1375 int
   1376 _bcm_ptp_phase_holdover_get(
   1377     int unit,
   1378     bcm_ptp_stack_id_t ptp_id,
   1379     int clock_num,
   1380     bcm_ptp_phase_holdover_state_t *state)
   1381 {
   1382     int rv;
   1383     int i;
   1384 
   1385     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1386     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
   1387 
   1388     bcm_ptp_port_identity_t portid;
   1389 
   1390     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
   1391             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1392         return rv;
   1393     }
   1394 
   1395     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
   1396             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1397         /* On error, target message to (all clocks, all ports) portIdentity. */
   1398         portid = portid_all;
   1399     }
   1400 
   1401     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1402             clock_num, &portid,
   1403             PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_PHASE_OFFSET,
   1404             0, 0, resp, &resp_len))) {
   1405         return rv;
   1406     }
   1407 
   1408     /*
   1409      * Parse response.
   1410      *    Octet 0...5   : Custom management message key/identifier.
   1411      *                    BCM<null><null><null>.
   1412      *    Octet 6...13  : Reported phase offset.
   1413      *    Octet 14...21 : Delta offset.
   1414      *    Octet 22...29 : Fixed phase offset.
   1415      *    Octet 30...33 : Use fixed phase offset flag.
   1416      *    Octet 34...37 : Phase slew rate - maximum phase offset correction rate.
   1417      *    Octet 38...41 : Sync phase offst - maximum phase offset correction
   1418      *                    via rate-limited phase slew.
   1419      */
   1420     i = 6;
   1421     state->reported_phase_offset = _bcm_ptp_int64_read(resp + i);
   1422     i += 8;
   1423     state->delta_phase_offset = _bcm_ptp_int64_read(resp + i);
   1424     i += 8;
   1425     state->fixed_phase_offset = _bcm_ptp_int64_read(resp + i);
   1426     i += 8;
   1427     state->use_fixed_phase_offset = _bcm_ptp_uint32_read(resp + i);
   1428     i += 4;
   1429     state->phase_slew_rate_ppb = _bcm_ptp_uint32_read(resp + i);
   1430     i += 4;
   1431     state->sync_phase_offset_ns = _bcm_ptp_uint32_read(resp + i);
   1432 
   1433     return BCM_E_NONE;
   1434 }
   1435 
   1436 /*
   1437  * Function:
   1438  *      _bcm_ptp_phase_holdover_set
   1439  * Purpose:
   1440  *      Set phase offsets for path asymmetry compensation.
   1441  * Parameters:
   1442  *      unit      - (IN)  Unit number.
   1443  *      ptp_id    - (IN)  PTP stack ID.
   1444  *      clock_num - (IN)  PTP clock number.
   1445  *      state     - (IN) PTP servo phase holdover state
   1446  * Returns:
   1447  *      BCM_E_XXX - Function status.
   1448  * Notes:
   1449  */
   1450 int
   1451 _bcm_ptp_phase_holdover_set(
   1452     int unit,
   1453     bcm_ptp_stack_id_t ptp_id,
   1454     int clock_num,
   1455     const bcm_ptp_phase_holdover_state_t *state)
   1456 {
   1457     int rv;
   1458     int i;
   1459 
   1460     uint8 payload[PTP_MGMTMSG_PAYLOAD_PHASE_OFFSET_SIZE_OCTETS] = {0};
   1461     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1462     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
   1463 
   1464     bcm_ptp_port_identity_t portid;
   1465 
   1466     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
   1467             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1468         return rv;
   1469     }
   1470 
   1471     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
   1472             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1473         /* On error, target message to (all clocks, all ports) portIdentity. */
   1474         portid = portid_all;
   1475     }
   1476 
   1477     /*
   1478      * Make payload.
   1479      *    Octet 0...5   : Custom management message key/identifier.
   1480      *                    BCM<null><null><null>.
   1481      *    Octet 6...13 : Delta offset.
   1482      *    Octet 14...21 : Fixed phase offset.
   1483      *    Octet 22...25 : Use fixed phase offset flag.
   1484      *    Octet 26...29 : Phase slew rate - maximum phase offset correction rate.
   1485      *    Octet 30...33 : Sync phase offst - maximum phase offset correction
   1486      *                    via rate-limited phase slew.
   1487      */
   1488     i = 0;
   1489     payload[i++] = 'B';
   1490     payload[i++] = 'C';
   1491     payload[i++] = 'M';
   1492     payload[i++] = '\0';
   1493     payload[i++] = '\0';
   1494     payload[i++] = '\0';
   1495 
   1496     _bcm_ptp_int64_write(payload + i, state->delta_phase_offset);
   1497     i += 8;
   1498     _bcm_ptp_int64_write(payload + i, state->fixed_phase_offset);
   1499     i += 8;
   1500     if (state->use_fixed_phase_offset) {
   1501         _bcm_ptp_uint32_write(payload + i, 1);
   1502     } else {
   1503         _bcm_ptp_uint32_write(payload + i, 0);
   1504     }
   1505     i += 4;
   1506     _bcm_ptp_uint32_write(payload + i, state->phase_slew_rate_ppb);
   1507     i += 4;
   1508     _bcm_ptp_uint32_write(payload + i, state->sync_phase_offset_ns);
   1509 
   1510     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1511             clock_num, &portid,
   1512             PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_PHASE_OFFSET,
   1513             payload, PTP_MGMTMSG_PAYLOAD_PHASE_OFFSET_SIZE_OCTETS,
   1514             resp, &resp_len))) {
   1515         return rv;
   1516     }
   1517 
   1518     return BCM_E_NONE;
   1519 }
   1520 
   1521 /*
   1522  * Function:
   1523  *      _bcm_ptp_freq_corr_get
   1524  * Purpose:
   1525  *      Gets current frequency offsets
   1526  * Parameters:
   1527  *      unit            - (IN) Unit number.
   1528  *      ptp_id          - (IN) PTP stack ID.
   1529  *      clock_num       - (IN) PTP clock number.
   1530  *      freq_corr_ppt   - (IN) Servo-issued frequency correction
   1531  *      offset_freq_ppt - (IN) User-specified frequency offset
   1532  * Returns:
   1533  *      BCM_E_XXX - Function status.
   1534  * Notes:
   1535  *      The current frequency offset is (freq_corr_ppt + offset_freq_ppt)
   1536  */
   1537 int
   1538 _bcm_ptp_freq_corr_get(
   1539     int unit,
   1540     bcm_ptp_stack_id_t ptp_id,
   1541     int clock_num,
   1542     int32 *freq_corr_ppt,
   1543     int32 *offset_freq_ppt)
   1544 {
   1545     int rv;
   1546 
   1547     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1548     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
   1549     uint8 *curs;
   1550 
   1551     bcm_ptp_port_identity_t portid;
   1552 
   1553     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
   1554             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1555         return rv;
   1556     }
   1557 
   1558     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
   1559             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1560         /* On error, target message to (all clocks, all ports) portIdentity. */
   1561         portid = portid_all;
   1562     }
   1563 
   1564     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1565             clock_num, &portid, PTP_MGMTMSG_GET, PTP_MGMTMSG_ID_FREQUENCY,
   1566             0, 0, resp, &resp_len))) {
   1567         return rv;
   1568     }
   1569 
   1570     /*
   1571      * Parse response.
   1572      *    Octet 0...5   : Custom management message key/identifier.
   1573      *                    BCM<null><null><null>.
   1574      *    Octet 6...9   : Frequency Correction in PPT (* 1e-12)
   1575      *    Octet 10...13 : Frequency Offset from Servo's correction in PPT
   1576      */
   1577     if (resp_len < 6 + 4 + 4) {
   1578         return BCM_E_FAIL;
   1579     }
   1580 
   1581     curs = resp + 6;     /* after BCM\0\0\0 */
   1582     *freq_corr_ppt = _bcm_ptp_uint32_read(curs);  curs += 4;
   1583     *offset_freq_ppt = _bcm_ptp_uint32_read(curs);  curs += 4;
   1584 
   1585     return BCM_E_NONE;
   1586 }
   1587 
   1588 
   1589 /*
   1590  * Function:
   1591  *      _bcm_ptp_freq_corr_set
   1592  * Purpose:
   1593  *      Gets current frequency offsets
   1594  * Parameters:
   1595  *      unit            - (IN) Unit number.
   1596  *      ptp_id          - (IN) PTP stack ID.
   1597  *      clock_num       - (IN) PTP clock number.
   1598  *      freq_corr_ppt   - (IN) Servo-issued frequency correction
   1599  *      offset_freq_ppt - (IN) User-specified frequency offset
   1600  * Returns:
   1601  *      BCM_E_XXX - Function status.
   1602  * Notes:
   1603  *      The current frequency offset is (freq_corr_ppt + offset_freq_ppt)
   1604  *      If the servo is updating its frequency correction estimate, the
   1605  *      user-supplied 'freq_corr_ppt' value will be overwritten with that
   1606  *      new estimate.
   1607  */
   1608 #ifdef BCM_PTP_EXT_SERVO_SUPPORT
   1609 int
   1610 _bcm_ptp_freq_corr_set(
   1611     int unit,
   1612     bcm_ptp_stack_id_t ptp_id,
   1613     int clock_num,
   1614     double freq_corr_ppb,
   1615     double freq_offset_ppb)
   1616 #else
   1617 int
   1618 _bcm_ptp_freq_corr_set(
   1619     int unit,
   1620     bcm_ptp_stack_id_t ptp_id,
   1621     int clock_num,
   1622     int32 freq_corr_ppt,
   1623     int32 freq_offset_ppt)
   1624 #endif /* BCM_PTP_EXT_SERVO_SUPPORT */
   1625 {
   1626     int rv;
   1627     int i;
   1628 
   1629 #ifdef BCM_PTP_EXT_SERVO_SUPPORT
   1630     int32 freq_corr_ppt;
   1631     int32 freq_offset_ppt;
   1632 #endif /* BCM_PTP_EXT_SERVO_SUPPORT */
   1633 
   1634     uint8 payload[PTP_MGMTMSG_PAYLOAD_PHASE_OFFSET_SIZE_OCTETS] = {0};
   1635     uint8 resp[PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS];
   1636     int resp_len = PTP_MGMTMSG_RESP_MAX_SIZE_OCTETS;
   1637 
   1638     bcm_ptp_port_identity_t portid;
   1639 
   1640     if (g_apts_enabled &&
   1641             (g_apts_current_op_mode != bcmPtpClockAptsModeGpsGps) &&
   1642             (g_apts_current_op_mode != bcmPtpClockAptsModePtpPtp)){
   1643         /* Do not apply frequency corrections from servo */
   1644         rv = BCM_E_NONE;
   1645         return rv;
   1646     }
   1647 
   1648     if (BCM_FAILURE(rv = _bcm_ptp_function_precheck(unit, ptp_id,
   1649             clock_num, PTP_CLOCK_PORT_NUMBER_DEFAULT))) {
   1650         return rv;
   1651     }
   1652 
   1653     if (BCM_FAILURE(rv = bcm_common_ptp_clock_port_identity_get(unit, ptp_id,
   1654             clock_num, PTP_IEEE1588_ALL_PORTS, &portid))) {
   1655         /* On error, target message to (all clocks, all ports) portIdentity. */
   1656         portid = portid_all;
   1657     }
   1658 
   1659     /*
   1660      * Make payload.
   1661      *    Octet 0...5   : Custom management message key/identifier.
   1662      *                    BCM<null><null><null>.
   1663      *    Octet 6...9   : Frequency Correction in PPT (* 1e-12)
   1664      *    Octet 10...13 : Frequency Offset from Servo's correction in PPT
   1665      */
   1666     i = 0;
   1667     payload[i++] = 'B';
   1668     payload[i++] = 'C';
   1669     payload[i++] = 'M';
   1670     payload[i++] = '\0';
   1671     payload[i++] = '\0';
   1672     payload[i++] = '\0';
   1673 
   1674 #ifdef BCM_PTP_EXT_SERVO_SUPPORT
   1675     freq_corr_ppt   = (freq_corr_ppb * 1000);
   1676 	freq_offset_ppt = (freq_offset_ppb * 1000);
   1677 
   1678     LOG_INFO(BSL_LS_BCM_PTP,
   1679             (BSL_META_U(unit, " freq corr set: freq_correction_ppb[%lf : 0x%016llx] freq_corr_offset_ppb[%lf : %llx]\n"), 
   1680 		        freq_corr_ppb, (unsigned long long int)freq_corr_ppb, freq_offset_ppb, (unsigned long long int)freq_offset_ppb)); 
   1681 #endif /* BCM_PTP_EXT_SERVO_SUPPORT */
   1682 
   1683     _bcm_ptp_uint32_write(payload + i, freq_corr_ppt);   i += 4;
   1684     _bcm_ptp_uint32_write(payload + i, freq_offset_ppt); i += 4;
   1685 
   1686     if (BCM_FAILURE(rv = _bcm_ptp_management_message_send(unit, ptp_id,
   1687             clock_num, &portid,
   1688             PTP_MGMTMSG_SET, PTP_MGMTMSG_ID_FREQUENCY,
   1689             payload, PTP_MGMTMSG_PAYLOAD_FREQUENCY_SIZE_OCTETS,
   1690             resp, &resp_len))) {
   1691         return rv;
   1692     }
   1693 
   1694     return BCM_E_NONE;
   1695 }
   1696 
   1697 /*
   1698  * Function:
   1699  *      _bcm_ptp_servo_type_get
   1700  * Purpose:
   1701  *      Derive the servo type based on the provided profile
   1702  * Parameters:
   1703  *      profile_type - (IN) clock profile: 8265.1, 8275.1, def-1588 etc.
   1704  *      servo - (OUT) Servo type [bcm||other] for the provided
   1705  *                    clock profile
   1706  * Returns:
   1707  *      BCM_E_XXX - Function status.
   1708  * Notes:
   1709  *      Add new profiles to the list as they are introduced in future
   1710  *      update the servo types as introduced in future
   1711  */
   1712 int
   1713 _bcm_ptp_servo_type_get (uint32 profile_type, uint32 *servo)
   1714 {
   1715     int rv = BCM_E_NONE;
   1716 
   1717     switch (profile_type) {
   1718     case e_PtpProfType_8265p1:
   1719     case e_PtpProfType_8275p2:
   1720         *servo = bcmPTPServoTypeExt;
   1721         break;
   1722 
   1723     case e_PtpProfType_8275p1:
   1724     /*case e_PtpProfType_8273p2:*/
   1725         *servo = bcmPTPServoTypeBCM;
   1726         break;
   1727 
   1728     default:
   1729         rv = BCM_E_UNAVAIL;;
   1730     }
   1731     return rv ;
   1732 }
   1733 
   1734 /*
   1735  * Function:
   1736  *     _bcm_ptp_servo_synce_freq_corr_get_in_combined_mode
   1737  * Purpose:
   1738  *     Get the brcm servo's freq correction in TS0/TS1 combined mode
   1739  * Parameters:
   1740  * Returns:
   1741  *      BCM_E_XXX - Function status.
   1742  * Notes:
   1743  */
   1744 int
   1745 _bcm_ptp_bcm_servo_synce_freq_corr_get_in_combined_mode(int unit, int stack_id, int64 *servo_freq_correction_pbb)
   1746 {
   1747     int rv = BCM_E_NONE;
   1748 
   1749     _bcm_ptp_stack_info_t *stack_p;
   1750     _bcm_ptp_info_t *ptp_info_p;
   1751     _bcm_ptp_servo_performance_t perf;
   1752     bcm_ptp_clock_info_t clock_info;
   1753     uint32 profile_type;
   1754     uint32 servo = 0;
   1755 
   1756     SET_PTP_INFO;
   1757     stack_p = &ptp_info_p->stack_info[stack_id];
   1758 
   1759     if (!(stack_p->flags & BCM_PTP_STACK_TIMESTAMPER_COMBINED_MODE))
   1760     {
   1761         return BCM_E_UNAVAIL;
   1762     }
   1763 
   1764     if(BCM_FAILURE(bcm_ptp_clock_get(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, &clock_info))) {
   1765         return rv;
   1766     }
   1767     profile_type = ((clock_info.flags >> 8) & 0x0F);
   1768     _bcm_ptp_servo_type_get(profile_type, &servo);
   1769 
   1770     if (servo != bcmPTPServoTypeBCM) {
   1771         return BCM_E_UNAVAIL;
   1772     }
   1773 
   1774     if(BCM_FAILURE(_bcm_ptp_servo_performance_get(unit, stack_id, PTP_CLOCK_NUMBER_DEFAULT, &perf))) {
   1775         return BCM_E_UNAVAIL;
   1776     }
   1777     *servo_freq_correction_pbb =  perf.freq_correction/(int64)PTP_SERVO_FREQ_CORRECTION_FIXEDPOINT_SCALEFACTOR;
   1778 
   1779     return rv ;
   1780 }
   1781 
   1782 
   1783 #endif /* defined(INCLUDE_PTP)*/