Exemplo n.º 1
0
/* ppi->port_idx port is synchronized to Ebest Table 16 (9.3.5) of the spec. */
static void s1(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann)
{
	struct DSParent *parent = DSPAR(ppi);
	struct DSTimeProperties *prop = DSPRO(ppi);

	/* Current DS */
	DSCUR(ppi)->stepsRemoved = ann->stepsRemoved + 1;

	/* Parent DS */
	parent->parentPortIdentity = hdr->sourcePortIdentity;
	parent->grandmasterIdentity = ann->grandmasterIdentity;
	parent->grandmasterClockQuality = ann->grandmasterClockQuality;
	parent->grandmasterPriority1 = ann->grandmasterPriority1;
	parent->grandmasterPriority2 = ann->grandmasterPriority2;

	/* Timeproperties DS */
	prop->timeSource = ann->timeSource;
	if (prop->currentUtcOffset != ann->currentUtcOffset) {
		pp_diag(ppi, bmc, 1, "New UTC offset: %i\n",
			ann->currentUtcOffset);
		prop->currentUtcOffset = ann->currentUtcOffset;
		ppi->t_ops->set(ppi, NULL);
	}

	/* FIXME: can't we just copy the bit keeping values? */
	prop->currentUtcOffsetValid = ((hdr->flagField[1] & FFB_UTCV)	!= 0);
	prop->leap59 = ((hdr->flagField[1] & FFB_LI59) != 0);
	prop->leap61 = ((hdr->flagField[1] & FFB_LI61) != 0);
	prop->timeTraceable = ((hdr->flagField[1] & FFB_TTRA) != 0);
	prop->frequencyTraceable = ((hdr->flagField[1] & FFB_FTRA) != 0);
	prop->ptpTimescale = ((hdr->flagField[1] & FFB_PTP) != 0);

	if (pp_hooks.s1)
		pp_hooks.s1(ppi, hdr, ann);
}
Exemplo n.º 2
0
int bmc(struct pp_instance *ppi)
{
	struct pp_frgn_master *frgn_master = ppi->frgn_master;
	int i, best;

	if (!ppi->frgn_rec_num)
		if (ppi->state == PPS_MASTER)	{
			m1(ppi);
			return ppi->state;
		}

	/* Find Erbest, 9.3.2.3 */
	for (i = 1, best = 0; i < ppi->frgn_rec_num; i++)
		if (bmc_dataset_cmp(ppi, &frgn_master[i], &frgn_master[best])
		    < 0)
			best = i;

	pp_diag(ppi, bmc, 1,"Best foreign master is %i/%i\n", best,
		ppi->frgn_rec_num);
	if (ppi->frgn_rec_best != best) {
		ppi->frgn_rec_best = best;
		bmc_update_ebest(GLBS(ppi));
	}

	return bmc_state_decision(ppi, &frgn_master[best]);
}
Exemplo n.º 3
0
int wrs_read_calibration_data(struct pp_instance *ppi,
	uint32_t *delta_tx, uint32_t *delta_rx, int32_t *fix_alpha,
	int32_t *clock_period)
{
	struct hal_port_state *p;
	/* The following fields come from struct hexp_port_state */
	uint32_t port_delta_tx, port_delta_rx;
	int32_t port_fix_alpha;

	p = pp_wrs_lookup_port(ppi->iface_name);
	if (!p)
		return WR_HW_CALIB_NOT_FOUND;

	if(!p->calib.tx_calibrated || !p->calib.rx_calibrated)
		return WR_HW_CALIB_NOT_FOUND;

	/*
	 * Like in wrs_net_init, we build fields that were in
	 * hexp_port_state from the "real" hal_port_state in the same
	 * way as the HAL itself was doing to fill the RPC structure.
	 * Formulas copied from libwr/hal_shmem.c (get_exported_state).
	 */
	port_delta_tx = p->calib.delta_tx_phy
		+ p->calib.sfp.delta_tx_ps + p->calib.delta_tx_board;
	port_delta_rx = p->calib.delta_rx_phy
		+ p->calib.sfp.delta_rx_ps + p->calib.delta_rx_board;
	port_fix_alpha =  (double)pow(2.0, 40.0) *
		((p->calib.sfp.alpha + 1.0) / (p->calib.sfp.alpha + 2.0)
		 - 0.5);

	pp_diag(ppi, servo, 1, "deltas: tx=%d, rx=%d\n",
		port_delta_tx, port_delta_rx);

	if(delta_tx)
		*delta_tx = port_delta_tx;
	if(delta_rx)
		*delta_rx = port_delta_rx;
	if(fix_alpha)
		*fix_alpha = port_fix_alpha;
	if(clock_period)
		*clock_period =  16000; /* REF_CLOCK_PERIOD_PS */
	return WR_HW_CALIB_OK;
}
Exemplo n.º 4
0
int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
	int e = 0; /* error var, to check errors in msg handling */
	MsgHeader *hdr = &ppi->received_ptp_header;
	MsgDelayResp resp;
	int d1, d2;

	if (ppi->is_new_state) {
		pp_servo_init(ppi);

		if (pp_hooks.new_slave)
			e = pp_hooks.new_slave(ppi, pkt, plen);
		if (e)
			goto out;

		ppi->waiting_for_follow = FALSE;

		pp_timeout_restart_annrec(ppi);

		pp_timeout_rand(ppi, PP_TO_DELAYREQ,
				DSPOR(ppi)->logMinDelayReqInterval);
	}

	if (plen == 0)
		goto out;

	switch (hdr->messageType) {

	case PPM_ANNOUNCE:
		e = st_com_slave_handle_announce(ppi, pkt, plen);
		break;

	case PPM_SYNC:
		e = st_com_slave_handle_sync(ppi, pkt, plen);
		break;

	case PPM_FOLLOW_UP:
		e = st_com_slave_handle_followup(ppi, pkt, plen);
		break;

	case PPM_DELAY_REQ:
		/* Being slave, we are not waiting for a delay request */
		break;

	case PPM_DELAY_RESP:

		e = (plen < PP_DELAY_RESP_LENGTH);

		if (e)
			break;

		msg_unpack_delay_resp(pkt, &resp);

		if ((memcmp(&DSPOR(ppi)->portIdentity.clockIdentity,
			&resp.requestingPortIdentity.clockIdentity,
			PP_CLOCK_IDENTITY_LENGTH) == 0) &&
			((ppi->sent_seq[PPM_DELAY_REQ]) ==
				hdr->sequenceId) &&
			(DSPOR(ppi)->portIdentity.portNumber ==
			resp.requestingPortIdentity.portNumber)
			&& ppi->is_from_cur_par) {

			to_TimeInternal(&ppi->t4, &resp.receiveTimestamp);

			/*
			 * FIXME: how is correctionField handled in t3/t4?
			 * I think the master should consider it when
			 * generating t4, and report back a modified t4
			 */

			if (pp_hooks.handle_resp)
				e = pp_hooks.handle_resp(ppi);
			else
				pp_servo_got_resp(ppi);
			if (e)
				goto out;

			ppi->log_min_delay_req_interval =
				hdr->logMessageInterval;

		} else {
			pp_diag(ppi, frames, 2, "pp_slave : "
			     "Delay Resp doesn't match Delay Req\n");
		}

		break;

	/*
	 * We are not supporting pdelay (not configured to, see
	 * 9.5.13.1, p 106), so all the code about pdelay is removed
	 * as a whole by one commit in our history. It can be recoverd
	 * and fixed if needed
	 */

	default:
		/* disregard, nothing to do */
		break;

	}

out:
	if (e == 0)
		e = st_com_execute_slave(ppi);

	if (pp_timeout_z(ppi, PP_TO_DELAYREQ)) {
		e = msg_issue_delay_req(ppi);

		ppi->t3 = ppi->last_snt_time;

		/* Restart the timeout for next time */
		pp_timeout_rand(ppi, PP_TO_DELAYREQ,
				DSPOR(ppi)->logMinDelayReqInterval);

		/* Add latency */
		add_TimeInternal(&ppi->t3,
				 &ppi->t3,
				 &OPTS(ppi)->outbound_latency);
	}

	if (e) {
		ppi->next_state = PPS_FAULTY;
		return 0;
	}

	/* Leaving this state */
	if (ppi->next_state != ppi->state) {
		pp_timeout_clr(ppi, PP_TO_ANN_RECEIPT);
		pp_timeout_clr(ppi, PP_TO_DELAYREQ);

		pp_servo_init(ppi);
	}
	d1 = d2 = pp_ms_to_timeout(ppi, PP_TO_ANN_RECEIPT);
	if (ppi->timeouts[PP_TO_DELAYREQ])
		d2 = pp_ms_to_timeout(ppi, PP_TO_DELAYREQ);
	ppi->next_delay = d1 < d2 ? d1 : d2;
	return 0;
}
Exemplo n.º 5
0
/* State decision algorithm 9.3.3 Fig 26 */
static int bmc_state_decision(struct pp_instance *ppi,
							  struct pp_frgn_master *m)
{
	int cmpres;
	struct pp_frgn_master myself;

	if (ppi->master_only)
		goto master;

	if (ppi->slave_only)
		goto slave;

	if ((!ppi->frgn_rec_num) && (ppi->state == PPS_LISTENING))
		return PPS_LISTENING;

	/* copy local information to a foreign_master structure */
	copy_d0(ppi, &myself);

	/* dataset_cmp is "a - b" but lower values win */
	cmpres = bmc_dataset_cmp(ppi, &myself, m);

	if (DSDEF(ppi)->clockQuality.clockClass < 128) {
		if (cmpres < 0)
			goto master;
		if (cmpres > 0)
			goto passive;
	}
	if (cmpres < 0)
		goto master;
	if (cmpres > 0) {
		if (DSDEF(ppi)->numberPorts == 1)
			goto slave; /* directly skip to ordinary clock handling */
		else
			goto check_boundary_clk;
	}

	pp_diag(ppi, bmc, 1,"%s: error\n", __func__);

	/*  MB: Is this the return code below correct? */
	/*  Anyway, it's a valid return code. */
	return PPS_FAULTY;

check_boundary_clk:
	if (ppi->port_idx == GLBS(ppi)->ebest_idx) /* This port is the Ebest */
		goto slave;

	/* If idcmp returns 0, it means that this port is not the best because
		* Ebest is better by topology than Erbest */
	if (!idcmp(&myself.ann.grandmasterIdentity,
			&m->ann.grandmasterIdentity))
		goto passive;
	else
		goto master;

passive:
	p1(ppi, &m->hdr, &m->ann);
	pp_diag(ppi, bmc, 1,"%s: passive\n", __func__);
	return PPS_PASSIVE;

master:
	m1(ppi);
	pp_diag(ppi, bmc, 1,"%s: master\n", __func__);
	return PPS_MASTER;

slave:
	s1(ppi, &m->hdr, &m->ann);
	pp_diag(ppi, bmc, 1,"%s: slave\n", __func__);
	return PPS_SLAVE;

}
Exemplo n.º 6
0
/*
 * Data set comparison between two foreign masters. Return similar to
 * memcmp().  However, lower values take precedence, so in A-B (like
 * in comparisons,   > 0 means B wins (and < 0 means A wins).
 */
static int bmc_dataset_cmp(struct pp_instance *ppi,
			   struct pp_frgn_master *a,
			   struct pp_frgn_master *b)
{
	struct ClockQuality *qa, *qb;
	struct MsgAnnounce *aa = &a->ann;
	struct MsgAnnounce *ab = &b->ann;
	struct ClockIdentity *ida = &a->hdr.sourcePortIdentity.clockIdentity;
	struct ClockIdentity *idb = &b->hdr.sourcePortIdentity.clockIdentity;
	struct ClockIdentity *idparent;
	int diff;

	/* dataset_cmp is called several times, so report only at level 2 */
	pp_diag(ppi, bmc, 2,"%s\n", __func__);

	if (!idcmp(&aa->grandmasterIdentity, &ab->grandmasterIdentity)) {

		/* The grandmaster is the same: part 2, fig 28, page 90. */

		diff = aa->stepsRemoved - ab->stepsRemoved;
		if (diff > 1 || diff < -1)
			return diff;

		idparent = &DSPAR(ppi)->parentPortIdentity.clockIdentity;

		if (diff > 0) {
			if (!idcmp(ida, idparent)) {
				pp_diag(ppi, bmc, 1,"%s:%i: Error 1\n",
					__func__, __LINE__);
				return 0;
			}
			return 1;

		}
		if (diff < 0) {
			if (!idcmp(idb, idparent)) {
				pp_diag(ppi, bmc, 1,"%s:%i: Error 1\n",
					__func__, __LINE__);
				return 0;
			}
			return -1;
		}
		/* stepsRemoved is equal, compare identities */
		diff = idcmp(ida, idb);
		if (!diff) {
			pp_diag(ppi, bmc, 1,"%s:%i: Error 2\n", __func__, __LINE__);
			return 0;
		}
		return diff;
	}

	/* The grandmasters are different: part 1, fig 27, page 89. */
	qa = &aa->grandmasterClockQuality;
	qb = &ab->grandmasterClockQuality;

	if (aa->grandmasterPriority1 != ab->grandmasterPriority1)
		return aa->grandmasterPriority1 - ab->grandmasterPriority1;

	if (qa->clockClass != qb->clockClass)
		return qa->clockClass - qb->clockClass;

	if (qa->clockAccuracy != qb->clockAccuracy)
		return qa->clockAccuracy - qb->clockAccuracy;

	if (qa->offsetScaledLogVariance != qb->offsetScaledLogVariance)
		return qa->clockClass - qb->clockClass;

	if (aa->grandmasterPriority2 != ab->grandmasterPriority2)
		return aa->grandmasterPriority2 - ab->grandmasterPriority2;

	return idcmp(&aa->grandmasterIdentity, &ab->grandmasterIdentity);
}
Exemplo n.º 7
0
/*
 * Log means messages
 */
void pp_timeout_log(struct pp_instance *ppi, int index)
{
	pp_diag(ppi, time, 1, "timeout expired: %s\n", timeout_names[index]);
}
Exemplo n.º 8
0
int pp_faulty(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
	pp_diag(ppi, fsm, 1, "Faulty state detected\n");
	ppi->next_state = PPS_INITIALIZING;
	return 0;
}
Exemplo n.º 9
0
int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
	unsigned char *id, *mac;
	struct DSPort *port = DSPOR(ppi);
	struct pp_runtime_opts *opt = OPTS(ppi);
	int ret = 0;

	if (ppi->n_ops->init(ppi) < 0) /* it must handle being called twice */
		goto failure;

	/* Clock identity comes from mac address with 0xff:0xfe intermixed */
	id = (unsigned char *)&DSDEF(ppi)->clockIdentity;
	mac = NP(ppi)->ch[PP_NP_GEN].addr;
	id[0] = mac[0];
	id[1] = mac[1];
	id[2] = mac[2];
	id[3] = 0xff;
	id[4] = 0xfe;
	id[5] = mac[3];
	id[6] = mac[4];
	id[7] = mac[5];

	/*
	 * Initialize port data set
	 */
	memcpy(&port->portIdentity.clockIdentity,
		&DSDEF(ppi)->clockIdentity, PP_CLOCK_IDENTITY_LENGTH);
	port->portIdentity.portNumber = 1;
	port->logMinDelayReqInterval = PP_DEFAULT_DELAYREQ_INTERVAL;
	port->logAnnounceInterval = opt->announce_intvl;
	port->announceReceiptTimeout = PP_DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
	port->logSyncInterval = opt->sync_intvl;
	port->versionNumber = PP_VERSION_PTP;

	if (pp_hooks.init)
		ret = pp_hooks.init(ppi, pkt, plen);
	if (ret) {
		pp_diag(ppi, ext, 1, "%s: can't init extension\n", __func__);
		goto failure;
	}

	if (ret) {
		pp_diag(ppi, time, 1, "%s: can't init timers\n", __func__);
		goto failure;
	}
	pp_init_clock(ppi);

	pp_diag(ppi, bmc, 1, "clock class = %d\n",
			DSDEF(ppi)->clockQuality.clockClass);
	pp_diag(ppi, bmc, 1, "clock accuracy = %d\n",
			DSDEF(ppi)->clockQuality.clockAccuracy);

	m1(ppi);

	msg_pack_header(ppi, ppi->tx_ptp); /* This is used for all tx */

	if (!ppi->master_only)
		ppi->next_state = PPS_LISTENING;
	else
		ppi->next_state = PPS_MASTER;
	return 0;

failure:
	ppi->next_delay = 1000; /* wait 1s before retrying */
	return 0;
}