Commit accb9676 authored by baujc's avatar baujc

L1Sync extension update after WR extension review

parent f7205dab
......@@ -57,7 +57,6 @@ int l1e_unpack_signal(struct pp_instance *ppi, void *pkt, int plen);
/*
* These structures are used as extension-specific data in the DSPort
* ()
*/
typedef struct { /*draft P1588_v_29: page 100 and 333-335 */
/* configurable members */
......@@ -124,67 +123,47 @@ static inline L1SyncOptParamsPortDS_t *L1E_DSPOR_OP(struct pp_instance *ppi)
/****************************************************************************************/
/* l1e_servo interface */
#define L1E_SERVO_RESET_DATA_SIZE (sizeof(struct l1e_servo_state)-offsetof(struct l1e_servo_state,reset_address))
#define L1E_SERVO_RESET_DATA(servo) memset(&servo->reset_address,0,L1E_SERVO_RESET_DATA_SIZE);
struct l1e_servo_state {
/* Values used by snmp. Values are increased at servo update when
* erroneous condition occurs. */
uint32_t n_err_state;
uint32_t n_err_offset;
uint32_t n_err_delta_rtt;
/* ----- All data after this line will cleared during a servo reset */
int reset_address;
/* These fields are used by servo code, after setting at init time */
int32_t clock_period_ps;
/* Following fields are for monitoring/diagnostics (use w/ shmem) */
int64_t delayMM_ps;
int32_t cur_setpoint_ps;
int64_t delayMS_ps;
int tracking_enabled;
int64_t skew_ps;
int64_t offsetMS_ps;
/* These fields are used by servo code, across iterations */
int64_t prev_delayMS_ps;
int missed_iters;
};
/* Prototypes */
int l1e_servo_init(struct pp_instance *ppi);
void l1e_servo_reset(struct pp_instance *ppi);
void l1e_servo_enable_tracking(int enable);
int l1e_servo_got_sync(struct pp_instance *ppi);
int l1e_servo_got_resp(struct pp_instance *ppi);
int l1e_servo_got_presp(struct pp_instance *ppi);
int l1e_servo_update(struct pp_instance *ppi);
uint8_t l1e_creat_L1Sync_bitmask(int tx_coh, int rx_coh, int congru);
void l1e_print_L1Sync_basic_bitmaps(struct pp_instance *ppi,
uint8_t configed, uint8_t active, char* text);
void l1e_servo_enable_tracking(int enable);
int l1e_update_correction_values(struct pp_instance *ppi);
int l1e_run_state_machine(struct pp_instance *ppi);
int l1e_run_state_machine(struct pp_instance *ppi, void *buf, int len);
/* All data used as extension ppsi l1sync must be put here */
struct l1e_data {
struct l1e_servo_state servo_state;
wrh_servo_t servo; /* As to be in the first place in this structure */
};
static inline struct l1e_servo_state *L1E_SRV(struct pp_instance *ppi)
{
return &((struct l1e_data *)ppi->ext_data)->servo_state;
}
static inline int l1e_get_rx_tmo_ms(L1SyncBasicPortDS_t * bds) {
return (4 << (bds->logL1SyncInterval + 8)) * bds->L1SyncReceiptTimeout;
}
extern struct pp_ext_hooks l1e_ext_hooks;
/* Servo routines */
static inline int l1e_servo_init(struct pp_instance *ppi) {
return wrh_servo_init(ppi);
}
static inline void l1e_servo_reset(struct pp_instance *ppi) {
wrh_servo_reset(ppi);
}
static inline int l1e_servo_got_sync(struct pp_instance *ppi) {
return wrh_servo_got_sync(ppi);
}
static inline int l1e_servo_got_resp(struct pp_instance *ppi) {
return wrh_servo_got_resp(ppi);
}
static inline int l1e_servo_got_presp(struct pp_instance *ppi) {
return wrh_servo_got_presp(ppi);
}
/* Timer indexes */
extern int l1eTmoTxSync;
extern int l1eTmoRxSync;
......
......@@ -38,33 +38,6 @@ void l1e_print_L1Sync_basic_bitmaps(struct pp_instance *ppi, uint8_t configed,
((active & L1E_CONGRUENT) == L1E_CONGRUENT));
}
/* update DS values of latencies and delay coefficient
* - these values are provided by HW (i.e. HAL) depending on SFPs, wavelenghts, etc
* - these values are stored in configurable data sets
* - the values from data sets are used in calculations
*/
int l1e_update_correction_values(struct pp_instance *ppi)
{
struct l1e_servo_state *s = L1E_SRV(ppi);
pp_diag(ppi, ext, 2, "hook: %s -- ext %i\n", __func__, ppi->protocol_extension);
/* read the interesting values from HW (i.e. HAL)*/
if ( WRH_OPER()->read_corr_data(ppi,
NULL,
&s->clock_period_ps,
NULL) != WRH_HW_CALIB_OK){
pp_diag(ppi, ext, 2, "hook: %s -- cannot read calib values\n",
__func__);
return -1;
}
pp_diag(ppi, ext, 2, "ML- Updated correction values: Clock period=%d [ps]\n",
s->clock_period_ps);
return 0;
}
/* open is global; called from "pp_init_globals" */
static int l1e_open(struct pp_instance *ppi, struct pp_runtime_opts *rt_opts)
{
......@@ -131,11 +104,7 @@ static int l1e_handle_signaling(struct pp_instance * ppi, void *buf, int len)
pp_timeout_set(ppi, L1E_TIMEOUT_RX_SYNC, l1e_get_rx_tmo_ms(bds));
bds->L1SyncLinkAlive = TRUE;
if ( ppi->link_state==PP_LSTATE_PROTOCOL_DETECTION ||
ppi->link_state==PP_LSTATE_FAILURE) {
ppi->link_state=PP_LSTATE_IN_PROGRESS;
ppi->ext_enabled=TRUE; // Force L1SYNC extension as L1SYNC messages are received
}
lstate_enable_extension(ppi);
}
return 0;
}
......@@ -216,7 +185,7 @@ static void l1e_state_change(struct pp_instance *ppi) {
/* In PPSI we go to DISABLE state when the link is down */
/* For the time being, it should be done like this because fsm is not called when the link is down */
L1E_DSPOR(ppi)->basic.next_state=L1SYNC_DISABLED; /* Force L1Sync DISABLE state */
l1e_run_state_machine(ppi);
l1e_run_state_machine(ppi,NULL,0);
break;
case PPS_INITIALIZING :
L1E_DSPOR(ppi)->basic.L1SyncState=L1E_DSPOR(ppi)->basic.next_state=L1SYNC_DISABLED;
......@@ -240,7 +209,9 @@ static int l1e_require_precise_timestamp(struct pp_instance *ppi) {
}
static int l1e_get_tmo_lstate_detection(struct pp_instance *ppi) {
return l1e_get_rx_tmo_ms(L1E_DSPOR_BS(ppi));
return is_externalPortConfigurationEnabled(DSDEF(ppi)) ?
10000 : /* 10s: externalPortConfiguration enable means no ANN_RECEIPT timeout */
l1e_get_rx_tmo_ms(L1E_DSPOR_BS(ppi));
}
/* The global structure used by ppsi */
......
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Jean-Claude BAU & Maciej Lipinski
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <stdint.h>
#include <inttypes.h>
#include <ppsi/ppsi.h>
#include "l1e-constants.h"
#include <libwr/shmem.h>
#include "../proto-standard/common-fun.h"
static const char *l1e_servo_state_name[] = {
[L1E_UNINITIALIZED] = "Uninitialized",
[L1E_SYNC_NSEC] = "SYNC_NSEC",
[L1E_SYNC_TAI] = "SYNC_SEC",
[L1E_SYNC_PHASE] = "SYNC_PHASE",
[L1E_TRACK_PHASE] = "TRACK_PHASE",
[L1E_WAIT_OFFSET_STABLE] = "WAIT_OFFSET_STABLE",
};
/* Enable tracking by default. Disabling the tracking is used for demos. */
static int l1e_tracking_enabled = 1;
extern struct pp_time faulty_stamps[6]; /* if unused, dropped at link time */
/* prototypes */
static int __l1e_servo_update(struct pp_instance *ppi);
/* External data */
extern struct wrs_shm_head *ppsi_head;
void l1e_servo_enable_tracking(int enable)
{
l1e_tracking_enabled = enable;
}
int l1e_servo_init(struct pp_instance *ppi)
{
struct l1e_servo_state *s=L1E_SRV(ppi);
struct pp_servo *gs=SRV(ppi);
pp_servo_init(ppi); // Initialize the standard servo data
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
/* Update correction data in data sets*/
if (l1e_update_correction_values(ppi) < 0)
return -1;
/*
* Do not reset cur_setpoint, but trim it to be less than one tick.
* The softpll code uses the module anyways, but if we unplug-replug
* the fiber it will always increase, so don't scare the user
*/
if (s->cur_setpoint_ps > s->clock_period_ps)
s->cur_setpoint_ps %= s->clock_period_ps;
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
s->missed_iters = 0;
gs->state = L1E_SYNC_TAI;
strcpy(SRV(ppi)->servo_state_name, l1e_servo_state_name[SRV(ppi)->state]);
gs->flags |= PP_SERVO_FLAG_VALID;
gs->update_count = 0;
ppi->t_ops->get(ppi, &SRV(ppi)->update_time);
s->tracking_enabled = l1e_tracking_enabled;
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 0;
}
void l1e_servo_reset(struct pp_instance *ppi)
{
if ( ppi->ext_enabled ) {
struct l1e_servo_state *s=L1E_SRV(ppi);
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
ppi->flags = 0;
L1E_SERVO_RESET_DATA(s);
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
}
}
/**
* SYNC/FOLLOW_UP messages have been received: t1/t2 are available
*/
int l1e_servo_got_sync(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
gs->t1=ppi->t1;apply_faulty_stamp(ppi,1);
gs->t2=ppi->t2;apply_faulty_stamp(ppi,2);
if ( is_delayMechanismP2P(ppi) && gs->got_sync) {
gs->got_sync=0;
__l1e_servo_update(ppi);
}else {
gs->got_sync=1;
}
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 0;
}
/**
* DELAY_RESPONSE message has been received: t3/t4 are available
*/
int l1e_servo_got_resp(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
int ret;
static int errcount=0;
if ( !gs->got_sync )
return 0; /* t1 & t2 not available yet */
gs->got_sync=0;
if ( is_timestamps_incorrect(ppi,&errcount,0xC /* mask=t3&t4 */) )
return 0;
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
gs->t3 = ppi->t3; apply_faulty_stamp(ppi,3);
gs->t4 = ppi->t4; apply_faulty_stamp(ppi,4);
ret=__l1e_servo_update(ppi);
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return ret;
}
/**
* PDELAY_RESPONSE_FUP message has been received: t3/t4/t5/t6 are available
*/
int l1e_servo_got_presp(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
static int errcount=0;
if ( is_timestamps_incorrect(ppi,&errcount,0x3C /* mask=&t3&t4&t5&t6 */) )
return 0;
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
gs->t3 = ppi->t3; apply_faulty_stamp(ppi,3);
gs->t4 = ppi->t4; apply_faulty_stamp(ppi,4);
gs->t5 = ppi->t5; apply_faulty_stamp(ppi,5);
gs->t6 = ppi->t6; apply_faulty_stamp(ppi,6);
gs->got_sync=1;
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 1;
}
static int __l1e_servo_update(struct pp_instance *ppi)
{
l1e_ext_portDS_t *pds=L1E_DSPOR(ppi);
struct pp_servo *gs=SRV(ppi);
struct l1e_servo_state *s=L1E_SRV(ppi);
int remaining_offset;
int32_t offset_ticks;
int64_t prev_delayMM_ps = 0;
int locking_poll_ret;
struct pp_time offsetMS ;
int32_t offset_ps;
if ( gs->state==L1E_UNINITIALIZED )
return 0;
prev_delayMM_ps = s->delayMM_ps;
if ( !pp_servo_calculate_delays(ppi) )
return 0;
s->delayMM_ps=pp_time_to_picos(&gs->delayMM);
offsetMS=gs->offsetFromMaster;
s->offsetMS_ps=pp_time_to_picos(&offsetMS);
s->tracking_enabled = l1e_tracking_enabled;
// Servo updated
gs->update_count++;
ppi->t_ops->get(ppi, &gs->update_time);
if (pds->basic.L1SyncState != L1SYNC_UP)
return 1; /* State is not UP. We have to wait before to start the synchronisation */
locking_poll_ret = WRH_OPER()->locking_poll(ppi);
if (locking_poll_ret != WRH_SPLL_READY
&& locking_poll_ret != WRH_SPLL_CALIB_NOT_READY) {
pp_diag(ppi, servo, 1, "PLL out of lock\n");
/* TODO check
* DSPOR(ppi)->doRestart = TRUE; */
}
/* After each action on the hardware, we must verify if it is over. */
if (!WRH_OPER()->adjust_in_progress()) {
gs->flags &= ~PP_SERVO_FLAG_WAIT_HW;
} else {
pp_diag(ppi, servo, 1, "servo:busy\n");
return 1;
}
/* So, we didn't return. Choose the right state */
if (offsetMS.secs) {/* so bad... */
gs->state = L1E_SYNC_TAI;
pp_diag(ppi, servo, 2, "offsetMS: %li sec ...\n",
(long)offsetMS.secs);
} else {
pp_time_hardwarize(&offsetMS, s->clock_period_ps,
&offset_ticks, &offset_ps);
pp_diag(ppi, servo, 2, "offsetMS: %li sec %09li ticks (%li ps)\n",
(long)offsetMS.secs, (long)offset_ticks,
(long)offset_ps);
if (offset_ticks) /* not that bad */
gs->state = L1E_SYNC_NSEC;
/* else, let the states below choose the sequence */
}
/* update string state name */
strcpy(gs->servo_state_name, l1e_servo_state_name[gs->state]);
pp_diag(ppi, servo, 1, "l1e_servo state: %s%s\n",
l1e_servo_state_name[gs->state],
gs->flags & PP_SERVO_FLAG_WAIT_HW ? " (wait for hw)" : "");
switch (gs->state) {
case L1E_SYNC_TAI:
WRH_OPER()->adjust_counters(offsetMS.secs, 0);
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
/*
* If nsec wrong, code above forces SYNC_NSEC,
* Else, we must ensure we leave this status towards
* fine tuning
*/
gs->state = L1E_SYNC_PHASE;
break;
case L1E_SYNC_NSEC:
WRH_OPER()->adjust_counters(0, offset_ticks);
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->state = L1E_SYNC_PHASE;
break;
case L1E_SYNC_PHASE:
pp_diag(ppi, servo, 2, "oldsetp %i, offset %i:%04i\n",
s->cur_setpoint_ps, offset_ticks,
offset_ps);
s->cur_setpoint_ps += offset_ps;
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->state = L1E_WAIT_OFFSET_STABLE;
if (CONFIG_ARCH_IS_WRS) {
/*
* Now, let's fix system time. We pass here
* once only, so that's the best place to do
* it. We use current WR time.
* */
struct pp_time t;
ppi->t_ops->get(ppi,&t);
unix_time_ops.set(ppi, &t);
pp_diag(ppi, time, 1, "system time set to %s TAI\n",
time_to_string(&t));
}
break;
case L1E_WAIT_OFFSET_STABLE:
/* ts_to_picos() below returns phase alone */
remaining_offset = abs(pp_time_to_picos(&offsetMS));
if(remaining_offset < WRH_SERVO_OFFSET_STABILITY_THRESHOLD) {
WRH_OPER()->enable_timing_output(GLBS(ppi),1);
s->prev_delayMS_ps = s->delayMS_ps;
gs->state = L1E_TRACK_PHASE;
} else {
s->missed_iters++;
}
if (s->missed_iters >= 10) {
s->missed_iters = 0;
gs->state = L1E_SYNC_PHASE;
}
break;
case L1E_TRACK_PHASE:
s->skew_ps = s->delayMS_ps - s->prev_delayMS_ps;
/* Can be disabled for manually tweaking and testing */
if(l1e_tracking_enabled) {
if (abs(offset_ps) >
2 * WRH_SERVO_OFFSET_STABILITY_THRESHOLD) {
gs->state = L1E_SYNC_PHASE;
break;
}
// adjust phase towards offset = 0 make ck0 0
s->cur_setpoint_ps += (offset_ps / 4);
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
pp_diag(ppi, time, 1, "adjust phase %i\n",
s->cur_setpoint_ps);
s->prev_delayMS_ps = s->delayMS_ps;
}
break;
}
gs->servo_locked=gs->state==L1E_TRACK_PHASE;
/* Increase number of servo updates with state different than
* L1E_TRACK_PHASE. (Used by SNMP) */
if (gs->state != L1E_TRACK_PHASE)
s->n_err_state++;
/* Increase number of servo updates with offset exceeded
* SNMP_MAX_OFFSET_PS (Used by SNMP) */
if (abs(s->offsetMS_ps) > SNMP_MAX_OFFSET_PS)
s->n_err_offset++;
/* Increase number of servo updates with delta rtt exceeded
* SNMP_MAX_DELTA_RTT_PS (Used by SNMP) */
if (abs(prev_delayMM_ps - s->delayMM_ps) > SNMP_MAX_DELTA_RTT_PS)
s->n_err_delta_rtt++;
return 1;
}
......@@ -52,7 +52,7 @@ static l1e_state_machine_t le1_state_actions[] ={
* It is used to send signaling messages.
* It returns the ext-specific timeout value
*/
int l1e_run_state_machine(struct pp_instance *ppi) {
int l1e_run_state_machine(struct pp_instance *ppi, void *buf, int len) {
L1SyncBasicPortDS_t * basicDS=L1E_DSPOR_BS(ppi);
Enumeration8 nextState=basicDS->next_state;
Boolean newState=nextState!=basicDS->L1SyncState;
......@@ -281,7 +281,7 @@ static int l1e_handle_state_idle(struct pp_instance *ppi, Boolean new_state){
if ( !le1_evt_L1_SYNC_ENABLED(ppi) || le1_evt_L1_SYNC_RESET(ppi) ) {
/* Go to DISABLE state */
l1e_portDS->basic.next_state=L1SYNC_DISABLED;
ppi->link_state=PP_LSTATE_FAILURE;
lstate_set_link_failure(ppi);
return 0; /* Treatment required asap */
}
if ( le1_evt_LINK_OK(ppi) ) {
......@@ -372,13 +372,14 @@ static int l1e_handle_state_up(struct pp_instance *ppi, Boolean new_state){
/* State initialization */
if ( new_state ) {
WRH_OPER()->enable_ptracker(ppi);
WRH_SRV(ppi)->readyForSync=TRUE;
}
/* Check if state transition needed */
if ( !le1_evt_LINK_OK(ppi) ) {
/* Go to IDLE state */
next_state=L1SYNC_IDLE;
ppi->link_state=PP_LSTATE_FAILURE;
lstate_set_link_failure(ppi);
}
if ( !le1_evt_CONFIG_OK(ppi) ) {
/* Return to LINK_ALIVE state */
......@@ -396,8 +397,8 @@ static int l1e_handle_state_up(struct pp_instance *ppi, Boolean new_state){
}
/* Iterative treatment */
ppi->link_state=PP_LSTATE_LINKED;
l1e_update_correction_values(ppi);
lstate_set_link_established(ppi);
wrh_update_correction_values(ppi);
l1e_send_sync_msg(ppi,0);
return pp_next_delay_2(ppi,L1E_TIMEOUT_TX_SYNC, L1E_TIMEOUT_RX_SYNC); /* Return the shorter timeout */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment