Blame clock.c

Packit 9c3e7e
/**
Packit 9c3e7e
 * @file clock.c
Packit 9c3e7e
 * @note Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
Packit 9c3e7e
 *
Packit 9c3e7e
 * This program is free software; you can redistribute it and/or modify
Packit 9c3e7e
 * it under the terms of the GNU General Public License as published by
Packit 9c3e7e
 * the Free Software Foundation; either version 2 of the License, or
Packit 9c3e7e
 * (at your option) any later version.
Packit 9c3e7e
 *
Packit 9c3e7e
 * This program is distributed in the hope that it will be useful,
Packit 9c3e7e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 9c3e7e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 9c3e7e
 * GNU General Public License for more details.
Packit 9c3e7e
 *
Packit 9c3e7e
 * You should have received a copy of the GNU General Public License along
Packit 9c3e7e
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit 9c3e7e
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 9c3e7e
 */
Packit 9c3e7e
#include <errno.h>
Packit Service aa6626
#include <time.h>
Packit 9c3e7e
#include <linux/net_tstamp.h>
Packit 9c3e7e
#include <poll.h>
Packit 9c3e7e
#include <stdlib.h>
Packit 9c3e7e
#include <string.h>
Packit 9c3e7e
#include <sys/queue.h>
Packit 9c3e7e
Packit 9c3e7e
#include "address.h"
Packit 9c3e7e
#include "bmc.h"
Packit 9c3e7e
#include "clock.h"
Packit 9c3e7e
#include "clockadj.h"
Packit 9c3e7e
#include "clockcheck.h"
Packit 9c3e7e
#include "foreign.h"
Packit 9c3e7e
#include "filter.h"
Packit 9c3e7e
#include "missing.h"
Packit 9c3e7e
#include "msg.h"
Packit 9c3e7e
#include "phc.h"
Packit 9c3e7e
#include "port.h"
Packit 9c3e7e
#include "servo.h"
Packit 9c3e7e
#include "stats.h"
Packit 9c3e7e
#include "print.h"
Packit 9c3e7e
#include "rtnl.h"
Packit 9c3e7e
#include "tlv.h"
Packit 9c3e7e
#include "tsproc.h"
Packit 9c3e7e
#include "uds.h"
Packit 9c3e7e
#include "util.h"
Packit 9c3e7e
Packit 9c3e7e
#define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */
Packit 9c3e7e
#define POW2_41 ((double)(1ULL << 41))
Packit 9c3e7e
Packit 9c3e7e
struct port {
Packit 9c3e7e
	LIST_ENTRY(port) list;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct freq_estimator {
Packit 9c3e7e
	tmv_t origin1;
Packit 9c3e7e
	tmv_t ingress1;
Packit 9c3e7e
	unsigned int max_count;
Packit 9c3e7e
	unsigned int count;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct clock_stats {
Packit 9c3e7e
	struct stats *offset;
Packit 9c3e7e
	struct stats *freq;
Packit 9c3e7e
	struct stats *delay;
Packit 9c3e7e
	unsigned int max_count;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct clock_subscriber {
Packit 9c3e7e
	LIST_ENTRY(clock_subscriber) list;
Packit 9c3e7e
	uint8_t events[EVENT_BITMASK_CNT];
Packit 9c3e7e
	struct PortIdentity targetPortIdentity;
Packit 9c3e7e
	struct address addr;
Packit 9c3e7e
	UInteger16 sequenceId;
Packit 9c3e7e
	time_t expiration;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct clock {
Packit 9c3e7e
	enum clock_type type;
Packit 9c3e7e
	struct config *config;
Packit 9c3e7e
	clockid_t clkid;
Packit 9c3e7e
	struct servo *servo;
Packit 9c3e7e
	enum servo_type servo_type;
Packit 9c3e7e
	int (*dscmp)(struct dataset *a, struct dataset *b);
Packit 9c3e7e
	struct defaultDS dds;
Packit 9c3e7e
	struct dataset default_dataset;
Packit 9c3e7e
	struct currentDS cur;
Packit 9c3e7e
	struct parent_ds dad;
Packit 9c3e7e
	struct timePropertiesDS tds;
Packit 9c3e7e
	struct ClockIdentity ptl[PATH_TRACE_MAX];
Packit 9c3e7e
	struct foreign_clock *best;
Packit 9c3e7e
	struct ClockIdentity best_id;
Packit 9c3e7e
	LIST_HEAD(ports_head, port) ports;
Packit 9c3e7e
	struct port *uds_port;
Packit 9c3e7e
	struct pollfd *pollfd;
Packit 9c3e7e
	int pollfd_valid;
Packit 9c3e7e
	int nports; /* does not include the UDS port */
Packit 9c3e7e
	int last_port_number;
Packit 9c3e7e
	int sde;
Packit 9c3e7e
	int free_running;
Packit 9c3e7e
	int freq_est_interval;
Packit 9c3e7e
	int grand_master_capable; /* for 802.1AS only */
Packit 9c3e7e
	int utc_timescale;
Packit 9c3e7e
	int utc_offset_set;
Packit 9c3e7e
	int leap_set;
Packit 9c3e7e
	int kernel_leap;
Packit 9c3e7e
	int utc_offset;
Packit 9c3e7e
	int time_flags;  /* grand master role */
Packit 9c3e7e
	int time_source; /* grand master role */
Packit 9c3e7e
	enum servo_state servo_state;
Packit 9c3e7e
	enum timestamp_type timestamping;
Packit 9c3e7e
	tmv_t master_offset;
Packit 9c3e7e
	tmv_t path_delay;
Packit 9c3e7e
	tmv_t ingress_ts;
Packit 9c3e7e
	tmv_t initial_delay;
Packit 9c3e7e
	struct tsproc *tsproc;
Packit 9c3e7e
	struct freq_estimator fest;
Packit 9c3e7e
	struct time_status_np status;
Packit 9c3e7e
	double master_local_rr; /* maintained when free_running */
Packit 9c3e7e
	double nrr;
Packit 9c3e7e
	struct clock_description desc;
Packit 9c3e7e
	struct clock_stats stats;
Packit 9c3e7e
	int stats_interval;
Packit 9c3e7e
	struct clockcheck *sanity_check;
Packit 9c3e7e
	struct interface uds_interface;
Packit 9c3e7e
	LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct clock the_clock;
Packit 9c3e7e
Packit 9c3e7e
static void handle_state_decision_event(struct clock *c);
Packit 9c3e7e
static int clock_resize_pollfd(struct clock *c, int new_nports);
Packit 9c3e7e
static void clock_remove_port(struct clock *c, struct port *p);
Packit 9c3e7e
Packit 9c3e7e
static void remove_subscriber(struct clock_subscriber *s)
Packit 9c3e7e
{
Packit 9c3e7e
	LIST_REMOVE(s, list);
Packit 9c3e7e
	free(s);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_update_subscription(struct clock *c, struct ptp_message *req,
Packit 9c3e7e
				      uint8_t *bitmask, uint16_t duration)
Packit 9c3e7e
{
Packit 9c3e7e
	struct clock_subscriber *s;
Packit 9c3e7e
	int i, remove = 1;
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
Packit 9c3e7e
	for (i = 0; i < EVENT_BITMASK_CNT; i++) {
Packit 9c3e7e
		if (bitmask[i]) {
Packit 9c3e7e
			remove = 0;
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(s, &c->subscribers, list) {
Packit 9c3e7e
		if (pid_eq(&s->targetPortIdentity,
Packit 9c3e7e
			   &req->header.sourcePortIdentity)) {
Packit 9c3e7e
			/* Found, update the transport address and event
Packit 9c3e7e
			 * mask. */
Packit 9c3e7e
			if (!remove) {
Packit 9c3e7e
				s->addr = req->address;
Packit 9c3e7e
				memcpy(s->events, bitmask, EVENT_BITMASK_CNT);
Packit 9c3e7e
				clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
				s->expiration = now.tv_sec + duration;
Packit 9c3e7e
			} else {
Packit 9c3e7e
				remove_subscriber(s);
Packit 9c3e7e
			}
Packit 9c3e7e
			return;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
	if (remove)
Packit 9c3e7e
		return;
Packit 9c3e7e
	/* Not present yet, add the subscriber. */
Packit 9c3e7e
	s = malloc(sizeof(*s));
Packit 9c3e7e
	if (!s) {
Packit 9c3e7e
		pr_err("failed to allocate memory for a subscriber");
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	s->targetPortIdentity = req->header.sourcePortIdentity;
Packit 9c3e7e
	s->addr = req->address;
Packit 9c3e7e
	memcpy(s->events, bitmask, EVENT_BITMASK_CNT);
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
	s->expiration = now.tv_sec + duration;
Packit 9c3e7e
	s->sequenceId = 0;
Packit 9c3e7e
	LIST_INSERT_HEAD(&c->subscribers, s, list);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_get_subscription(struct clock *c, struct ptp_message *req,
Packit 9c3e7e
				   uint8_t *bitmask, uint16_t *duration)
Packit 9c3e7e
{
Packit 9c3e7e
	struct clock_subscriber *s;
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(s, &c->subscribers, list) {
Packit 9c3e7e
		if (pid_eq(&s->targetPortIdentity,
Packit 9c3e7e
			   &req->header.sourcePortIdentity)) {
Packit 9c3e7e
			memcpy(bitmask, s->events, EVENT_BITMASK_CNT);
Packit 9c3e7e
			clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
			if (s->expiration < now.tv_sec)
Packit 9c3e7e
				*duration = 0;
Packit 9c3e7e
			else
Packit 9c3e7e
				*duration = s->expiration - now.tv_sec;
Packit 9c3e7e
			return;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
	/* A client without entry means the client has no subscriptions. */
Packit 9c3e7e
	memset(bitmask, 0, EVENT_BITMASK_CNT);
Packit 9c3e7e
	*duration = 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_flush_subscriptions(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct clock_subscriber *s, *tmp;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH_SAFE(s, &c->subscribers, list, tmp) {
Packit 9c3e7e
		remove_subscriber(s);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_prune_subscriptions(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct clock_subscriber *s, *tmp;
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
	LIST_FOREACH_SAFE(s, &c->subscribers, list, tmp) {
Packit 9c3e7e
		if (s->expiration <= now.tv_sec) {
Packit 9c3e7e
			pr_info("subscriber %s timed out",
Packit 9c3e7e
				pid2str(&s->targetPortIdentity));
Packit 9c3e7e
			remove_subscriber(s);
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_send_notification(struct clock *c, struct ptp_message *msg,
Packit 9c3e7e
			     enum notification event)
Packit 9c3e7e
{
Packit 9c3e7e
	unsigned int event_pos = event / 8;
Packit 9c3e7e
	uint8_t mask = 1 << (event % 8);
Packit 9c3e7e
	struct port *uds = c->uds_port;
Packit 9c3e7e
	struct clock_subscriber *s;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(s, &c->subscribers, list) {
Packit 9c3e7e
		if (!(s->events[event_pos] & mask))
Packit 9c3e7e
			continue;
Packit 9c3e7e
		/* send event */
Packit 9c3e7e
		msg->header.sequenceId = htons(s->sequenceId);
Packit 9c3e7e
		s->sequenceId++;
Packit 9c3e7e
		msg->management.targetPortIdentity.clockIdentity =
Packit 9c3e7e
			s->targetPortIdentity.clockIdentity;
Packit 9c3e7e
		msg->management.targetPortIdentity.portNumber =
Packit 9c3e7e
			htons(s->targetPortIdentity.portNumber);
Packit 9c3e7e
		msg->address = s->addr;
Packit 9c3e7e
		port_forward_to(uds, msg);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_destroy(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *p, *tmp;
Packit 9c3e7e
Packit 9c3e7e
	clock_flush_subscriptions(c);
Packit 9c3e7e
	LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
Packit 9c3e7e
		clock_remove_port(c, p);
Packit 9c3e7e
	}
Packit 9c3e7e
	port_close(c->uds_port);
Packit 9c3e7e
	free(c->pollfd);
Packit 9c3e7e
	if (c->clkid != CLOCK_REALTIME) {
Packit 9c3e7e
		phc_close(c->clkid);
Packit 9c3e7e
	}
Packit 9c3e7e
	servo_destroy(c->servo);
Packit 9c3e7e
	tsproc_destroy(c->tsproc);
Packit 9c3e7e
	stats_destroy(c->stats.offset);
Packit 9c3e7e
	stats_destroy(c->stats.freq);
Packit 9c3e7e
	stats_destroy(c->stats.delay);
Packit 9c3e7e
	if (c->sanity_check) {
Packit 9c3e7e
		clockcheck_destroy(c->sanity_check);
Packit 9c3e7e
	}
Packit 9c3e7e
	memset(c, 0, sizeof(*c));
Packit 9c3e7e
	msg_cleanup();
Packit 9c3e7e
	tc_cleanup();
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_fault_timeout(struct port *port, int set)
Packit 9c3e7e
{
Packit 9c3e7e
	struct fault_interval i;
Packit 9c3e7e
Packit 9c3e7e
	if (!set) {
Packit 9c3e7e
		pr_debug("clearing fault on port %d", port_number(port));
Packit 9c3e7e
		return port_set_fault_timer_lin(port, 0);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	fault_interval(port, last_fault_type(port), &i);
Packit 9c3e7e
Packit 9c3e7e
	if (i.type == FTMO_LINEAR_SECONDS) {
Packit 9c3e7e
		pr_debug("waiting %d seconds to clear fault on port %d",
Packit 9c3e7e
			 i.val, port_number(port));
Packit 9c3e7e
		return port_set_fault_timer_lin(port, i.val);
Packit 9c3e7e
	} else if (i.type == FTMO_LOG2_SECONDS) {
Packit 9c3e7e
		pr_debug("waiting 2^{%d} seconds to clear fault on port %d",
Packit 9c3e7e
			 i.val, port_number(port));
Packit 9c3e7e
		return port_set_fault_timer_log(port, 1, i.val);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	pr_err("Unsupported fault interval type %d", i.type);
Packit 9c3e7e
	return -1;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_freq_est_reset(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	c->fest.origin1 = tmv_zero();
Packit 9c3e7e
	c->fest.ingress1 = tmv_zero();
Packit 9c3e7e
	c->fest.count = 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_management_send_error(struct port *p,
Packit 9c3e7e
					struct ptp_message *msg, int error_id)
Packit 9c3e7e
{
Packit 9c3e7e
	if (port_management_error(port_identity(p), p, msg, error_id))
Packit 9c3e7e
		pr_err("failed to send management error status");
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/* The 'p' and 'req' paremeters are needed for the GET actions that operate
Packit 9c3e7e
 * on per-client datasets. If such actions do not apply to the caller, it is
Packit 9c3e7e
 * allowed to pass both of them as NULL.
Packit 9c3e7e
 */
Packit 9c3e7e
static int clock_management_fill_response(struct clock *c, struct port *p,
Packit 9c3e7e
					  struct ptp_message *req,
Packit 9c3e7e
					  struct ptp_message *rsp, int id)
Packit 9c3e7e
{
Packit 9c3e7e
	struct grandmaster_settings_np *gsn;
Packit 9c3e7e
	struct management_tlv_datum *mtd;
Packit 9c3e7e
	struct subscribe_events_np *sen;
Packit 9c3e7e
	struct management_tlv *tlv;
Packit 9c3e7e
	struct time_status_np *tsn;
Packit 9c3e7e
	struct tlv_extra *extra;
Packit 9c3e7e
	struct PTPText *text;
Packit 9c3e7e
	int datalen = 0;
Packit 9c3e7e
Packit 9c3e7e
	extra = tlv_extra_alloc();
Packit 9c3e7e
	if (!extra) {
Packit 9c3e7e
		pr_err("failed to allocate TLV descriptor");
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	extra->tlv = (struct TLV *) rsp->management.suffix;
Packit 9c3e7e
Packit 9c3e7e
	tlv = (struct management_tlv *) rsp->management.suffix;
Packit 9c3e7e
	tlv->type = TLV_MANAGEMENT;
Packit 9c3e7e
	tlv->id = id;
Packit 9c3e7e
Packit 9c3e7e
	switch (id) {
Packit 9c3e7e
	case TLV_USER_DESCRIPTION:
Packit 9c3e7e
		text = (struct PTPText *) tlv->data;
Packit 9c3e7e
		text->length = c->desc.userDescription.length;
Packit 9c3e7e
		memcpy(text->text, c->desc.userDescription.text, text->length);
Packit 9c3e7e
		datalen = 1 + text->length;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_DEFAULT_DATA_SET:
Packit 9c3e7e
		memcpy(tlv->data, &c->dds, sizeof(c->dds));
Packit 9c3e7e
		datalen = sizeof(c->dds);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_CURRENT_DATA_SET:
Packit 9c3e7e
		memcpy(tlv->data, &c->cur, sizeof(c->cur));
Packit 9c3e7e
		datalen = sizeof(c->cur);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_PARENT_DATA_SET:
Packit 9c3e7e
		memcpy(tlv->data, &c->dad.pds, sizeof(c->dad.pds));
Packit 9c3e7e
		datalen = sizeof(c->dad.pds);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_TIME_PROPERTIES_DATA_SET:
Packit 9c3e7e
		memcpy(tlv->data, &c->tds, sizeof(c->tds));
Packit 9c3e7e
		datalen = sizeof(c->tds);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_PRIORITY1:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->dds.priority1;
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_PRIORITY2:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->dds.priority2;
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_DOMAIN:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->dds.domainNumber;
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_SLAVE_ONLY:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->dds.flags & DDS_SLAVE_ONLY;
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_CLOCK_ACCURACY:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->dds.clockQuality.clockAccuracy;
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_TRACEABILITY_PROPERTIES:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->tds.flags & (TIME_TRACEABLE|FREQ_TRACEABLE);
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_TIMESCALE_PROPERTIES:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		mtd->val = c->tds.flags & PTP_TIMESCALE;
Packit 9c3e7e
		datalen = sizeof(*mtd);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_TIME_STATUS_NP:
Packit 9c3e7e
		tsn = (struct time_status_np *) tlv->data;
Packit 9c3e7e
		tsn->master_offset = tmv_to_nanoseconds(c->master_offset);
Packit 9c3e7e
		tsn->ingress_time = tmv_to_nanoseconds(c->ingress_ts);
Packit 9c3e7e
		tsn->cumulativeScaledRateOffset =
Packit 9c3e7e
			(Integer32) (c->status.cumulativeScaledRateOffset +
Packit 9c3e7e
				      c->nrr * POW2_41 - POW2_41);
Packit 9c3e7e
		tsn->scaledLastGmPhaseChange = c->status.scaledLastGmPhaseChange;
Packit 9c3e7e
		tsn->gmTimeBaseIndicator = c->status.gmTimeBaseIndicator;
Packit 9c3e7e
		tsn->lastGmPhaseChange = c->status.lastGmPhaseChange;
Packit 9c3e7e
		if (cid_eq(&c->dad.pds.grandmasterIdentity, &c->dds.clockIdentity))
Packit 9c3e7e
			tsn->gmPresent = 0;
Packit 9c3e7e
		else
Packit 9c3e7e
			tsn->gmPresent = 1;
Packit 9c3e7e
		tsn->gmIdentity = c->dad.pds.grandmasterIdentity;
Packit 9c3e7e
		datalen = sizeof(*tsn);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_GRANDMASTER_SETTINGS_NP:
Packit 9c3e7e
		gsn = (struct grandmaster_settings_np *) tlv->data;
Packit 9c3e7e
		gsn->clockQuality = c->dds.clockQuality;
Packit 9c3e7e
		gsn->utc_offset = c->utc_offset;
Packit 9c3e7e
		gsn->time_flags = c->time_flags;
Packit 9c3e7e
		gsn->time_source = c->time_source;
Packit 9c3e7e
		datalen = sizeof(*gsn);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_SUBSCRIBE_EVENTS_NP:
Packit 9c3e7e
		if (p != c->uds_port) {
Packit 9c3e7e
			/* Only the UDS port allowed. */
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
		sen = (struct subscribe_events_np *)tlv->data;
Packit 9c3e7e
		clock_get_subscription(c, req, sen->bitmask, &sen->duration);
Packit 9c3e7e
		break;
Packit 9c3e7e
	default:
Packit 9c3e7e
		/* The caller should *not* respond to this message. */
Packit 9c3e7e
		tlv_extra_recycle(extra);
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (datalen % 2) {
Packit 9c3e7e
		tlv->data[datalen] = 0;
Packit 9c3e7e
		datalen++;
Packit 9c3e7e
	}
Packit 9c3e7e
	tlv->length = sizeof(tlv->id) + datalen;
Packit 9c3e7e
	rsp->header.messageLength += sizeof(*tlv) + datalen;
Packit 9c3e7e
	msg_tlv_attach(rsp, extra);
Packit 9c3e7e
Packit 9c3e7e
	/* The caller can respond to this message. */
Packit 9c3e7e
	return 1;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_management_get_response(struct clock *c, struct port *p,
Packit 9c3e7e
					 int id, struct ptp_message *req)
Packit 9c3e7e
{
Packit 9c3e7e
	struct PortIdentity pid = port_identity(p);
Packit 9c3e7e
	struct ptp_message *rsp;
Packit 9c3e7e
	int respond;
Packit 9c3e7e
Packit 9c3e7e
	rsp = port_management_reply(pid, p, req);
Packit 9c3e7e
	if (!rsp) {
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	respond = clock_management_fill_response(c, p, req, rsp, id);
Packit 9c3e7e
	if (respond)
Packit 9c3e7e
		port_prepare_and_send(p, rsp, TRANS_GENERAL);
Packit 9c3e7e
	msg_put(rsp);
Packit 9c3e7e
	return respond;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_management_set(struct clock *c, struct port *p,
Packit 9c3e7e
				int id, struct ptp_message *req, int *changed)
Packit 9c3e7e
{
Packit 9c3e7e
	int respond = 0;
Packit 9c3e7e
	struct management_tlv *tlv;
Packit 9c3e7e
	struct management_tlv_datum *mtd;
Packit 9c3e7e
	struct grandmaster_settings_np *gsn;
Packit 9c3e7e
	struct subscribe_events_np *sen;
Packit 9c3e7e
Packit 9c3e7e
	tlv = (struct management_tlv *) req->management.suffix;
Packit 9c3e7e
Packit 9c3e7e
	switch (id) {
Packit 9c3e7e
	case TLV_PRIORITY1:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		c->dds.priority1 = mtd->val;
Packit 9c3e7e
		*changed = 1;
Packit 9c3e7e
		respond = 1;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_PRIORITY2:
Packit 9c3e7e
		mtd = (struct management_tlv_datum *) tlv->data;
Packit 9c3e7e
		c->dds.priority2 = mtd->val;
Packit 9c3e7e
		*changed = 1;
Packit 9c3e7e
		respond = 1;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_GRANDMASTER_SETTINGS_NP:
Packit 9c3e7e
		gsn = (struct grandmaster_settings_np *) tlv->data;
Packit 9c3e7e
		c->dds.clockQuality = gsn->clockQuality;
Packit 9c3e7e
		c->utc_offset = gsn->utc_offset;
Packit 9c3e7e
		c->time_flags = gsn->time_flags;
Packit 9c3e7e
		c->time_source = gsn->time_source;
Packit 9c3e7e
		*changed = 1;
Packit 9c3e7e
		respond = 1;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TLV_SUBSCRIBE_EVENTS_NP:
Packit 9c3e7e
		sen = (struct subscribe_events_np *)tlv->data;
Packit 9c3e7e
		clock_update_subscription(c, req, sen->bitmask,
Packit 9c3e7e
					  sen->duration);
Packit 9c3e7e
		respond = 1;
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (respond && !clock_management_get_response(c, p, id, req))
Packit 9c3e7e
		pr_err("failed to send management set response");
Packit 9c3e7e
	return respond ? 1 : 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_stats_update(struct clock_stats *s,
Packit 9c3e7e
			       double offset, double freq)
Packit 9c3e7e
{
Packit 9c3e7e
	struct stats_result offset_stats, freq_stats, delay_stats;
Packit 9c3e7e
Packit 9c3e7e
	stats_add_value(s->offset, offset);
Packit 9c3e7e
	stats_add_value(s->freq, freq);
Packit 9c3e7e
Packit 9c3e7e
	if (stats_get_num_values(s->offset) < s->max_count)
Packit 9c3e7e
		return;
Packit 9c3e7e
Packit 9c3e7e
	stats_get_result(s->offset, &offset_stats);
Packit 9c3e7e
	stats_get_result(s->freq, &freq_stats);
Packit 9c3e7e
Packit 9c3e7e
	/* Path delay stats are updated separately, they may be empty. */
Packit 9c3e7e
	if (!stats_get_result(s->delay, &delay_stats)) {
Packit 9c3e7e
		pr_info("rms %4.0f max %4.0f "
Packit 9c3e7e
			"freq %+6.0f +/- %3.0f "
Packit 9c3e7e
			"delay %5.0f +/- %3.0f",
Packit 9c3e7e
			offset_stats.rms, offset_stats.max_abs,
Packit 9c3e7e
			freq_stats.mean, freq_stats.stddev,
Packit 9c3e7e
			delay_stats.mean, delay_stats.stddev);
Packit 9c3e7e
	} else {
Packit 9c3e7e
		pr_info("rms %4.0f max %4.0f "
Packit 9c3e7e
			"freq %+6.0f +/- %3.0f",
Packit 9c3e7e
			offset_stats.rms, offset_stats.max_abs,
Packit 9c3e7e
			freq_stats.mean, freq_stats.stddev);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	stats_reset(s->offset);
Packit 9c3e7e
	stats_reset(s->freq);
Packit 9c3e7e
	stats_reset(s->delay);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static enum servo_state clock_no_adjust(struct clock *c, tmv_t ingress,
Packit 9c3e7e
					tmv_t origin)
Packit 9c3e7e
{
Packit 9c3e7e
	double fui;
Packit 9c3e7e
	double ratio, freq;
Packit 9c3e7e
	struct freq_estimator *f = &c->fest;
Packit 9c3e7e
	enum servo_state state = SERVO_UNLOCKED;
Packit 9c3e7e
	/*
Packit 9c3e7e
	 * The ratio of the local clock freqency to the master clock
Packit 9c3e7e
	 * is estimated by:
Packit 9c3e7e
	 *
Packit 9c3e7e
	 *    (ingress_2 - ingress_1) / (origin_2 - origin_1)
Packit 9c3e7e
	 *
Packit 9c3e7e
	 * Both of the origin time estimates include the path delay,
Packit 9c3e7e
	 * but we assume that the path delay is in fact constant.
Packit 9c3e7e
	 * By leaving out the path delay altogther, we can avoid the
Packit 9c3e7e
	 * error caused by our imperfect path delay measurement.
Packit 9c3e7e
	 */
Packit 9c3e7e
	if (tmv_is_zero(f->ingress1)) {
Packit 9c3e7e
		f->ingress1 = ingress;
Packit 9c3e7e
		f->origin1 = origin;
Packit 9c3e7e
		return state;
Packit 9c3e7e
	}
Packit 9c3e7e
	f->count++;
Packit 9c3e7e
	if (f->count < f->max_count) {
Packit 9c3e7e
		return state;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (tmv_cmp(ingress, f->ingress1) == 0) {
Packit 9c3e7e
		pr_warning("bad timestamps in rate ratio calculation");
Packit 9c3e7e
		return state;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	ratio = tmv_dbl(tmv_sub(origin, f->origin1)) /
Packit 9c3e7e
		tmv_dbl(tmv_sub(ingress, f->ingress1));
Packit 9c3e7e
	freq = (1.0 - ratio) * 1e9;
Packit 9c3e7e
Packit 9c3e7e
	if (c->stats.max_count > 1) {
Packit 9c3e7e
		clock_stats_update(&c->stats, tmv_dbl(c->master_offset), freq);
Packit 9c3e7e
	} else {
Packit 9c3e7e
		pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
Packit 9c3e7e
			"path delay %9" PRId64,
Packit 9c3e7e
			tmv_to_nanoseconds(c->master_offset), state, freq,
Packit 9c3e7e
			tmv_to_nanoseconds(c->path_delay));
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	fui = 1.0 + (c->status.cumulativeScaledRateOffset + 0.0) / POW2_41;
Packit 9c3e7e
Packit 9c3e7e
	pr_debug("peer/local    %.9f", c->nrr);
Packit 9c3e7e
	pr_debug("fup_info      %.9f", fui);
Packit 9c3e7e
	pr_debug("product       %.9f", fui * c->nrr);
Packit 9c3e7e
	pr_debug("sum-1         %.9f", fui + c->nrr - 1.0);
Packit 9c3e7e
	pr_debug("master/local  %.9f", ratio);
Packit 9c3e7e
	pr_debug("diff         %+.9f", ratio - (fui + c->nrr - 1.0));
Packit 9c3e7e
Packit 9c3e7e
	f->ingress1 = ingress;
Packit 9c3e7e
	f->origin1 = origin;
Packit 9c3e7e
	f->count = 0;
Packit 9c3e7e
Packit 9c3e7e
	c->master_local_rr = ratio;
Packit 9c3e7e
Packit 9c3e7e
	return state;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_update_grandmaster(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct parentDS *pds = &c->dad.pds;
Packit 9c3e7e
	memset(&c->cur, 0, sizeof(c->cur));
Packit 9c3e7e
	memset(c->ptl, 0, sizeof(c->ptl));
Packit 9c3e7e
	pds->parentPortIdentity.clockIdentity   = c->dds.clockIdentity;
Packit 9c3e7e
	pds->parentPortIdentity.portNumber      = 0;
Packit 9c3e7e
	pds->grandmasterIdentity                = c->dds.clockIdentity;
Packit 9c3e7e
	pds->grandmasterClockQuality            = c->dds.clockQuality;
Packit 9c3e7e
	pds->grandmasterPriority1               = c->dds.priority1;
Packit 9c3e7e
	pds->grandmasterPriority2               = c->dds.priority2;
Packit 9c3e7e
	c->dad.path_length                      = 0;
Packit 9c3e7e
	c->tds.currentUtcOffset                 = c->utc_offset;
Packit 9c3e7e
	c->tds.flags                            = c->time_flags;
Packit 9c3e7e
	c->tds.timeSource                       = c->time_source;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_update_slave(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct parentDS *pds = &c->dad.pds;
Packit 9c3e7e
	struct ptp_message *msg        = TAILQ_FIRST(&c->best->messages);
Packit 9c3e7e
	c->cur.stepsRemoved            = 1 + c->best->dataset.stepsRemoved;
Packit 9c3e7e
	pds->parentPortIdentity        = c->best->dataset.sender;
Packit 9c3e7e
	pds->grandmasterIdentity       = msg->announce.grandmasterIdentity;
Packit 9c3e7e
	pds->grandmasterClockQuality   = msg->announce.grandmasterClockQuality;
Packit 9c3e7e
	pds->grandmasterPriority1      = msg->announce.grandmasterPriority1;
Packit 9c3e7e
	pds->grandmasterPriority2      = msg->announce.grandmasterPriority2;
Packit 9c3e7e
	c->tds.currentUtcOffset        = msg->announce.currentUtcOffset;
Packit 9c3e7e
	c->tds.flags                   = msg->header.flagField[1];
Packit 9c3e7e
	c->tds.timeSource              = msg->announce.timeSource;
Packit 9c3e7e
	if (!(c->tds.flags & PTP_TIMESCALE)) {
Packit 9c3e7e
		pr_warning("foreign master not using PTP timescale");
Packit 9c3e7e
	}
Packit 9c3e7e
	if (c->tds.currentUtcOffset < c->utc_offset) {
Packit 9c3e7e
		pr_warning("running in a temporal vortex");
Packit 9c3e7e
	}
Packit 9c3e7e
	if ((c->tds.flags & UTC_OFF_VALID && c->tds.flags & TIME_TRACEABLE) ||
Packit 9c3e7e
	    (c->tds.currentUtcOffset > c->utc_offset)) {
Packit 9c3e7e
		pr_info("updating UTC offset to %d", c->tds.currentUtcOffset);
Packit 9c3e7e
		c->utc_offset = c->tds.currentUtcOffset;
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_utc_correct(struct clock *c, tmv_t ingress)
Packit 9c3e7e
{
Packit 9c3e7e
	struct timespec offset;
Packit 9c3e7e
	int utc_offset, leap, clock_leap;
Packit 9c3e7e
	uint64_t ts;
Packit 9c3e7e
Packit 9c3e7e
	if (!c->utc_timescale)
Packit 9c3e7e
		return 0;
Packit 9c3e7e
Packit 9c3e7e
	utc_offset = c->utc_offset;
Packit 9c3e7e
Packit 9c3e7e
	if (c->tds.flags & LEAP_61) {
Packit 9c3e7e
		leap = 1;
Packit 9c3e7e
	} else if (c->tds.flags & LEAP_59) {
Packit 9c3e7e
		leap = -1;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		leap = 0;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Handle leap seconds. */
Packit 9c3e7e
	if ((leap || c->leap_set) && c->clkid == CLOCK_REALTIME) {
Packit 9c3e7e
		/* If the clock will be stepped, the time stamp has to be the
Packit 9c3e7e
		   target time. Ignore possible 1 second error in utc_offset. */
Packit 9c3e7e
		if (c->servo_state == SERVO_UNLOCKED) {
Packit 9c3e7e
			ts = tmv_to_nanoseconds(tmv_sub(ingress,
Packit 9c3e7e
							c->master_offset));
Packit 9c3e7e
			if (c->tds.flags & PTP_TIMESCALE)
Packit 9c3e7e
				ts -= utc_offset * NS_PER_SEC;
Packit 9c3e7e
		} else {
Packit 9c3e7e
			ts = tmv_to_nanoseconds(ingress);
Packit 9c3e7e
		}
Packit 9c3e7e
Packit 9c3e7e
		/* Suspend clock updates in the last second before midnight. */
Packit 9c3e7e
		if (is_utc_ambiguous(ts)) {
Packit 9c3e7e
			pr_info("clock update suspended due to leap second");
Packit 9c3e7e
			return -1;
Packit 9c3e7e
		}
Packit 9c3e7e
Packit 9c3e7e
		clock_leap = leap_second_status(ts, c->leap_set,
Packit 9c3e7e
						&leap, &utc_offset);
Packit 9c3e7e
		if (c->leap_set != clock_leap) {
Packit 9c3e7e
			if (c->kernel_leap)
Packit 9c3e7e
				sysclk_set_leap(clock_leap);
Packit 9c3e7e
			else
Packit 9c3e7e
				servo_leap(c->servo, clock_leap);
Packit 9c3e7e
			c->leap_set = clock_leap;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Update TAI-UTC offset of the system clock if valid and traceable. */
Packit 9c3e7e
	if (c->tds.flags & UTC_OFF_VALID && c->tds.flags & TIME_TRACEABLE &&
Packit 9c3e7e
	    c->utc_offset_set != utc_offset && c->clkid == CLOCK_REALTIME) {
Packit 9c3e7e
		sysclk_set_tai_offset(utc_offset);
Packit 9c3e7e
		c->utc_offset_set = utc_offset;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (!(c->tds.flags & PTP_TIMESCALE))
Packit 9c3e7e
		return 0;
Packit 9c3e7e
Packit 9c3e7e
	offset.tv_sec = utc_offset;
Packit 9c3e7e
	offset.tv_nsec = 0;
Packit 9c3e7e
	/* Local clock is UTC, but master is TAI. */
Packit 9c3e7e
	c->master_offset = tmv_add(c->master_offset, timespec_to_tmv(offset));
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int forwarding(struct clock *c, struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	enum port_state ps = port_state(p);
Packit 9c3e7e
	switch (ps) {
Packit 9c3e7e
	case PS_MASTER:
Packit 9c3e7e
	case PS_GRAND_MASTER:
Packit 9c3e7e
	case PS_SLAVE:
Packit 9c3e7e
	case PS_UNCALIBRATED:
Packit 9c3e7e
	case PS_PRE_MASTER:
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	default:
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (p == c->uds_port && ps != PS_FAULTY) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/* public methods */
Packit 9c3e7e
Packit 9c3e7e
UInteger8 clock_class(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->dds.clockQuality.clockClass;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct config *clock_config(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->config;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int (*clock_dscmp(struct clock *c))(struct dataset *a, struct dataset *b)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->dscmp;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct currentDS *clock_current_dataset(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return &c->cur;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_add_port(struct clock *c, int phc_index,
Packit 9c3e7e
			  enum timestamp_type timestamping,
Packit 9c3e7e
			  struct interface *iface)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *p, *piter, *lastp = NULL;
Packit 9c3e7e
Packit 9c3e7e
	if (clock_resize_pollfd(c, c->nports + 1)) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	p = port_open(phc_index, timestamping, ++c->last_port_number, iface, c);
Packit 9c3e7e
	if (!p) {
Packit 9c3e7e
		/* No need to shrink pollfd */
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	LIST_FOREACH(piter, &c->ports, list) {
Packit 9c3e7e
		lastp = piter;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (lastp) {
Packit 9c3e7e
		LIST_INSERT_AFTER(lastp, p, list);
Packit 9c3e7e
	} else {
Packit 9c3e7e
		LIST_INSERT_HEAD(&c->ports, p, list);
Packit 9c3e7e
	}
Packit 9c3e7e
	c->nports++;
Packit 9c3e7e
	clock_fda_changed(c);
Packit 9c3e7e
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_remove_port(struct clock *c, struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	/* Do not call clock_resize_pollfd, it's pointless to shrink
Packit 9c3e7e
	 * the allocated memory at this point, clock_destroy will free
Packit 9c3e7e
	 * it all anyway. This function is usable from other parts of
Packit 9c3e7e
	 * the code, but even then we don't mind if pollfd is larger
Packit 9c3e7e
	 * than necessary. */
Packit 9c3e7e
	LIST_REMOVE(p, list);
Packit 9c3e7e
	c->nports--;
Packit 9c3e7e
	clock_fda_changed(c);
Packit 9c3e7e
	port_close(p);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_required_modes(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	int required_modes = 0;
Packit 9c3e7e
Packit 9c3e7e
	switch (c->timestamping) {
Packit 9c3e7e
	case TS_SOFTWARE:
Packit 9c3e7e
		required_modes |= SOF_TIMESTAMPING_TX_SOFTWARE |
Packit 9c3e7e
			SOF_TIMESTAMPING_RX_SOFTWARE |
Packit 9c3e7e
			SOF_TIMESTAMPING_SOFTWARE;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TS_LEGACY_HW:
Packit 9c3e7e
		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
Packit 9c3e7e
			SOF_TIMESTAMPING_RX_HARDWARE |
Packit 9c3e7e
			SOF_TIMESTAMPING_SYS_HARDWARE;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case TS_HARDWARE:
Packit 9c3e7e
	case TS_ONESTEP:
Packit 9c3e7e
	case TS_P2P1STEP:
Packit 9c3e7e
		required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
Packit 9c3e7e
			SOF_TIMESTAMPING_RX_HARDWARE |
Packit 9c3e7e
			SOF_TIMESTAMPING_RAW_HARDWARE;
Packit 9c3e7e
		break;
Packit 9c3e7e
	default:
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	return required_modes;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/*
Packit 9c3e7e
 * If we do not have a slave or the rtnl query failed, then use our
Packit 9c3e7e
 * own interface name as the time stamping interface name.
Packit 9c3e7e
 */
Packit 9c3e7e
static void ensure_ts_label(struct interface *iface)
Packit 9c3e7e
{
Packit 9c3e7e
	if (iface->ts_label[0] == '\0')
Packit 9c3e7e
		strncpy(iface->ts_label, iface->name, MAX_IFNAME_SIZE);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct clock *clock_create(enum clock_type type, struct config *config,
Packit 9c3e7e
			   const char *phc_device)
Packit 9c3e7e
{
Packit 9c3e7e
	enum servo_type servo = config_get_int(config, NULL, "clock_servo");
Packit 9c3e7e
	enum timestamp_type timestamping;
Packit 9c3e7e
	int fadj = 0, max_adj = 0, sw_ts;
Packit 9c3e7e
	int phc_index, required_modes = 0;
Packit 9c3e7e
	struct clock *c = &the_clock;
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
	unsigned char oui[OUI_LEN];
Packit 9c3e7e
	char phc[32], *tmp;
Packit 9c3e7e
	struct interface *iface, *udsif = &c->uds_interface;
Packit 9c3e7e
	struct timespec ts;
Packit 9c3e7e
	int sfl;
Packit 9c3e7e
Packit 9c3e7e
	clock_gettime(CLOCK_REALTIME, &ts);
Packit 9c3e7e
	srandom(ts.tv_sec ^ ts.tv_nsec);
Packit 9c3e7e
Packit 9c3e7e
	if (c->nports) {
Packit 9c3e7e
		clock_destroy(c);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	switch (type) {
Packit 9c3e7e
	case CLOCK_TYPE_ORDINARY:
Packit 9c3e7e
	case CLOCK_TYPE_BOUNDARY:
Packit 9c3e7e
	case CLOCK_TYPE_P2P:
Packit 9c3e7e
	case CLOCK_TYPE_E2E:
Packit 9c3e7e
		c->type = type;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case CLOCK_TYPE_MANAGEMENT:
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Initialize the defaultDS. */
Packit 9c3e7e
	c->dds.clockQuality.clockClass =
Packit 9c3e7e
		config_get_int(config, NULL, "clockClass");
Packit 9c3e7e
	c->dds.clockQuality.clockAccuracy =
Packit 9c3e7e
		config_get_int(config, NULL, "clockAccuracy");
Packit 9c3e7e
	c->dds.clockQuality.offsetScaledLogVariance =
Packit 9c3e7e
		config_get_int(config, NULL, "offsetScaledLogVariance");
Packit 9c3e7e
Packit 9c3e7e
	c->desc.productDescription.max_symbols = 64;
Packit 9c3e7e
	c->desc.revisionData.max_symbols = 32;
Packit 9c3e7e
	c->desc.userDescription.max_symbols = 128;
Packit 9c3e7e
Packit 9c3e7e
	tmp = config_get_string(config, NULL, "productDescription");
Packit 9c3e7e
	if (count_char(tmp, ';') != 2 ||
Packit 9c3e7e
	    static_ptp_text_set(&c->desc.productDescription, tmp)) {
Packit 9c3e7e
		pr_err("invalid productDescription '%s'", tmp);
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	tmp = config_get_string(config, NULL, "revisionData");
Packit 9c3e7e
	if (count_char(tmp, ';') != 2 ||
Packit 9c3e7e
	    static_ptp_text_set(&c->desc.revisionData, tmp)) {
Packit 9c3e7e
		pr_err("invalid revisionData '%s'", tmp);
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	tmp = config_get_string(config, NULL, "userDescription");
Packit 9c3e7e
	if (static_ptp_text_set(&c->desc.userDescription, tmp)) {
Packit 9c3e7e
		pr_err("invalid userDescription '%s'", tmp);
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	tmp = config_get_string(config, NULL, "manufacturerIdentity");
Packit 9c3e7e
	if (OUI_LEN != sscanf(tmp, "%hhx:%hhx:%hhx", &oui[0], &oui[1], &oui[2])) {
Packit 9c3e7e
		pr_err("invalid manufacturerIdentity '%s'", tmp);
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	memcpy(c->desc.manufacturerIdentity, oui, OUI_LEN);
Packit 9c3e7e
Packit 9c3e7e
	c->dds.domainNumber = config_get_int(config, NULL, "domainNumber");
Packit 9c3e7e
Packit 9c3e7e
	if (config_get_int(config, NULL, "slaveOnly")) {
Packit 9c3e7e
		c->dds.flags |= DDS_SLAVE_ONLY;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (!config_get_int(config, NULL, "gmCapable") &&
Packit 9c3e7e
	    c->dds.flags & DDS_SLAVE_ONLY) {
Packit 9c3e7e
		pr_err("Cannot mix 1588 slaveOnly with 802.1AS !gmCapable");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (!config_get_int(config, NULL, "gmCapable") ||
Packit 9c3e7e
	    c->dds.flags & DDS_SLAVE_ONLY) {
Packit 9c3e7e
		c->dds.clockQuality.clockClass = 255;
Packit 9c3e7e
	}
Packit 9c3e7e
	c->default_dataset.localPriority =
Packit 9c3e7e
		config_get_int(config, NULL, "G.8275.defaultDS.localPriority");
Packit 9c3e7e
Packit 9c3e7e
	/* Harmonize the twoStepFlag with the time_stamping option. */
Packit 9c3e7e
	if (config_harmonize_onestep(config)) {
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (config_get_int(config, NULL, "twoStepFlag")) {
Packit 9c3e7e
		c->dds.flags |= DDS_TWO_STEP_FLAG;
Packit 9c3e7e
	}
Packit 9c3e7e
	timestamping = config_get_int(config, NULL, "time_stamping");
Packit 9c3e7e
	if (timestamping == TS_SOFTWARE) {
Packit 9c3e7e
		sw_ts = 1;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		sw_ts = 0;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c->dds.priority1 = config_get_int(config, NULL, "priority1");
Packit 9c3e7e
	c->dds.priority2 = config_get_int(config, NULL, "priority2");
Packit 9c3e7e
Packit 9c3e7e
	/* Check the time stamping mode on each interface. */
Packit 9c3e7e
	c->timestamping = timestamping;
Packit 9c3e7e
	required_modes = clock_required_modes(c);
Packit 9c3e7e
	STAILQ_FOREACH(iface, &config->interfaces, list) {
Packit 9c3e7e
		rtnl_get_ts_device(iface->name, iface->ts_label);
Packit 9c3e7e
		ensure_ts_label(iface);
Packit 9c3e7e
		sk_get_ts_info(iface->ts_label, &iface->ts_info);
Packit 9c3e7e
		if (iface->ts_info.valid &&
Packit 9c3e7e
		    ((iface->ts_info.so_timestamping & required_modes) != required_modes)) {
Packit 9c3e7e
			pr_err("interface '%s' does not support "
Packit 9c3e7e
			       "requested timestamping mode", iface->name);
Packit 9c3e7e
			return NULL;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	iface = STAILQ_FIRST(&config->interfaces);
Packit 9c3e7e
Packit 9c3e7e
	/* determine PHC Clock index */
Packit 9c3e7e
	if (config_get_int(config, NULL, "free_running")) {
Packit 9c3e7e
		phc_index = -1;
Packit 9c3e7e
	} else if (timestamping == TS_SOFTWARE || timestamping == TS_LEGACY_HW) {
Packit 9c3e7e
		phc_index = -1;
Packit 9c3e7e
	} else if (phc_device) {
Packit 9c3e7e
		if (1 != sscanf(phc_device, "/dev/ptp%d", &phc_index)) {
Packit 9c3e7e
			pr_err("bad ptp device string");
Packit 9c3e7e
			return NULL;
Packit 9c3e7e
		}
Packit 9c3e7e
	} else if (iface->ts_info.valid) {
Packit 9c3e7e
		phc_index = iface->ts_info.phc_index;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		pr_err("PTP device not specified and automatic determination"
Packit 9c3e7e
		       " is not supported. Please specify PTP device.");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (phc_index >= 0) {
Packit 9c3e7e
		pr_info("selected /dev/ptp%d as PTP clock", phc_index);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (generate_clock_identity(&c->dds.clockIdentity, iface->name)) {
Packit 9c3e7e
		pr_err("failed to generate a clock identity");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Configure the UDS. */
Packit 9c3e7e
	snprintf(udsif->name, sizeof(udsif->name), "%s",
Packit 9c3e7e
		 config_get_string(config, NULL, "uds_address"));
Packit 9c3e7e
	if (config_set_section_int(config, udsif->name,
Packit 9c3e7e
				   "announceReceiptTimeout", 0)) {
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (config_set_section_int(config, udsif->name,
Packit 9c3e7e
				    "delay_mechanism", DM_AUTO)) {
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (config_set_section_int(config, udsif->name,
Packit 9c3e7e
				    "network_transport", TRANS_UDS)) {
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (config_set_section_int(config, udsif->name, "delay_filter_length", 1)) {
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c->config = config;
Packit 9c3e7e
	c->free_running = config_get_int(config, NULL, "free_running");
Packit 9c3e7e
	c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval");
Packit 9c3e7e
	c->grand_master_capable = config_get_int(config, NULL, "gmCapable");
Packit 9c3e7e
	c->kernel_leap = config_get_int(config, NULL, "kernel_leap");
Packit 9c3e7e
	c->utc_offset = config_get_int(config, NULL, "utc_offset");
Packit 9c3e7e
	c->time_source = config_get_int(config, NULL, "timeSource");
Packit 9c3e7e
Packit 9c3e7e
	if (c->free_running) {
Packit 9c3e7e
		c->clkid = CLOCK_INVALID;
Packit 9c3e7e
		if (timestamping == TS_SOFTWARE || timestamping == TS_LEGACY_HW) {
Packit 9c3e7e
			c->utc_timescale = 1;
Packit 9c3e7e
		}
Packit 9c3e7e
	} else if (phc_index >= 0) {
Packit 9c3e7e
		snprintf(phc, sizeof(phc), "/dev/ptp%d", phc_index);
Packit 9c3e7e
		c->clkid = phc_open(phc);
Packit 9c3e7e
		if (c->clkid == CLOCK_INVALID) {
Packit 9c3e7e
			pr_err("Failed to open %s: %m", phc);
Packit 9c3e7e
			return NULL;
Packit 9c3e7e
		}
Packit 9c3e7e
		max_adj = phc_max_adj(c->clkid);
Packit 9c3e7e
		if (!max_adj) {
Packit 9c3e7e
			pr_err("clock is not adjustable");
Packit 9c3e7e
			return NULL;
Packit 9c3e7e
		}
Packit 9c3e7e
		clockadj_init(c->clkid);
Packit 9c3e7e
	} else {
Packit 9c3e7e
		c->clkid = CLOCK_REALTIME;
Packit 9c3e7e
		c->utc_timescale = 1;
Packit 9c3e7e
		clockadj_init(c->clkid);
Packit 9c3e7e
		max_adj = sysclk_max_freq();
Packit 9c3e7e
		sysclk_set_leap(0);
Packit 9c3e7e
	}
Packit 9c3e7e
	c->utc_offset_set = 0;
Packit 9c3e7e
	c->leap_set = 0;
Packit 9c3e7e
	c->time_flags = c->utc_timescale ? 0 : PTP_TIMESCALE;
Packit 9c3e7e
Packit 9c3e7e
	if (c->clkid != CLOCK_INVALID) {
Packit 9c3e7e
		fadj = (int) clockadj_get_freq(c->clkid);
Packit 9c3e7e
		/* Due to a bug in older kernels, the reading may silently fail
Packit 9c3e7e
		   and return 0. Set the frequency back to make sure fadj is
Packit 9c3e7e
		   the actual frequency of the clock. */
Packit 9c3e7e
		clockadj_set_freq(c->clkid, fadj);
Packit 9c3e7e
	}
Packit 9c3e7e
	c->servo = servo_create(c->config, servo, -fadj, max_adj, sw_ts);
Packit 9c3e7e
	if (!c->servo) {
Packit 9c3e7e
		pr_err("Failed to create clock servo");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	c->servo_state = SERVO_UNLOCKED;
Packit 9c3e7e
	c->servo_type = servo;
Packit 9c3e7e
	if (config_get_int(config, NULL, "dataset_comparison") == DS_CMP_G8275) {
Packit 9c3e7e
		c->dscmp = telecom_dscmp;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		c->dscmp = dscmp;
Packit 9c3e7e
	}
Packit 9c3e7e
	c->tsproc = tsproc_create(config_get_int(config, NULL, "tsproc_mode"),
Packit 9c3e7e
				  config_get_int(config, NULL, "delay_filter"),
Packit 9c3e7e
				  config_get_int(config, NULL, "delay_filter_length"));
Packit 9c3e7e
	if (!c->tsproc) {
Packit 9c3e7e
		pr_err("Failed to create time stamp processor");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	c->initial_delay = dbl_tmv(config_get_int(config, NULL, "initial_delay"));
Packit 9c3e7e
	c->master_local_rr = 1.0;
Packit 9c3e7e
	c->nrr = 1.0;
Packit 9c3e7e
	c->stats_interval = config_get_int(config, NULL, "summary_interval");
Packit 9c3e7e
	c->stats.offset = stats_create();
Packit 9c3e7e
	c->stats.freq = stats_create();
Packit 9c3e7e
	c->stats.delay = stats_create();
Packit 9c3e7e
	if (!c->stats.offset || !c->stats.freq || !c->stats.delay) {
Packit 9c3e7e
		pr_err("failed to create stats");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	sfl = config_get_int(config, NULL, "sanity_freq_limit");
Packit 9c3e7e
	if (sfl) {
Packit 9c3e7e
		c->sanity_check = clockcheck_create(sfl);
Packit 9c3e7e
		if (!c->sanity_check) {
Packit 9c3e7e
			pr_err("Failed to create clock sanity check");
Packit 9c3e7e
			return NULL;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Initialize the parentDS. */
Packit 9c3e7e
	clock_update_grandmaster(c);
Packit 9c3e7e
	c->dad.pds.parentStats                           = 0;
Packit 9c3e7e
	c->dad.pds.observedParentOffsetScaledLogVariance = 0xffff;
Packit 9c3e7e
	c->dad.pds.observedParentClockPhaseChangeRate    = 0x7fffffff;
Packit 9c3e7e
	c->dad.ptl = c->ptl;
Packit 9c3e7e
Packit 9c3e7e
	clock_sync_interval(c, 0);
Packit 9c3e7e
Packit 9c3e7e
	LIST_INIT(&c->subscribers);
Packit 9c3e7e
	LIST_INIT(&c->ports);
Packit 9c3e7e
	c->last_port_number = 0;
Packit 9c3e7e
Packit 9c3e7e
	if (clock_resize_pollfd(c, 0)) {
Packit 9c3e7e
		pr_err("failed to allocate pollfd");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Create the UDS interface. */
Packit 9c3e7e
	c->uds_port = port_open(phc_index, timestamping, 0, udsif, c);
Packit 9c3e7e
	if (!c->uds_port) {
Packit 9c3e7e
		pr_err("failed to open the UDS port");
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	clock_fda_changed(c);
Packit 9c3e7e
Packit 9c3e7e
	/* Create the ports. */
Packit 9c3e7e
	STAILQ_FOREACH(iface, &config->interfaces, list) {
Packit 9c3e7e
		if (clock_add_port(c, phc_index, timestamping, iface)) {
Packit 9c3e7e
			pr_err("failed to open port %s", iface->name);
Packit 9c3e7e
			return NULL;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c->dds.numberPorts = c->nports;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(p, &c->ports, list) {
Packit 9c3e7e
		port_dispatch(p, EV_INITIALIZE, 0);
Packit 9c3e7e
	}
Packit 9c3e7e
	port_dispatch(c->uds_port, EV_INITIALIZE, 0);
Packit 9c3e7e
Packit 9c3e7e
	return c;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct dataset *clock_best_foreign(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->best ? &c->best->dataset : NULL;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct port *clock_best_port(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->best ? c->best->port : NULL;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct dataset *clock_default_ds(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct dataset *out = &c->default_dataset;
Packit 9c3e7e
	struct defaultDS *in = &c->dds;
Packit 9c3e7e
Packit 9c3e7e
	out->priority1              = in->priority1;
Packit 9c3e7e
	out->identity               = in->clockIdentity;
Packit 9c3e7e
	out->quality                = in->clockQuality;
Packit 9c3e7e
	out->priority2              = in->priority2;
Packit 9c3e7e
	out->stepsRemoved           = 0;
Packit 9c3e7e
	out->sender.clockIdentity   = in->clockIdentity;
Packit 9c3e7e
	out->sender.portNumber      = 0;
Packit 9c3e7e
	out->receiver.clockIdentity = in->clockIdentity;
Packit 9c3e7e
	out->receiver.portNumber    = 0;
Packit 9c3e7e
Packit 9c3e7e
	return out;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
UInteger8 clock_domain_number(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->dds.domainNumber;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct port *clock_first_port(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return LIST_FIRST(&c->ports);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_follow_up_info(struct clock *c, struct follow_up_info_tlv *f)
Packit 9c3e7e
{
Packit 9c3e7e
	c->status.cumulativeScaledRateOffset = f->cumulativeScaledRateOffset;
Packit 9c3e7e
	c->status.scaledLastGmPhaseChange = f->scaledLastGmPhaseChange;
Packit 9c3e7e
	c->status.gmTimeBaseIndicator = f->gmTimeBaseIndicator;
Packit 9c3e7e
	memcpy(&c->status.lastGmPhaseChange, &f->lastGmPhaseChange,
Packit 9c3e7e
	       sizeof(c->status.lastGmPhaseChange));
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_free_running(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->free_running ? 1 : 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_gm_capable(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->grand_master_capable;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct ClockIdentity clock_identity(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->dds.clockIdentity;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_resize_pollfd(struct clock *c, int new_nports)
Packit 9c3e7e
{
Packit 9c3e7e
	struct pollfd *new_pollfd;
Packit 9c3e7e
Packit 9c3e7e
	/* Need to allocate one whole extra block of fds for UDS. */
Packit 9c3e7e
	new_pollfd = realloc(c->pollfd,
Packit 9c3e7e
			     (new_nports + 1) * N_CLOCK_PFD *
Packit 9c3e7e
			     sizeof(struct pollfd));
Packit 9c3e7e
	if (!new_pollfd) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	c->pollfd = new_pollfd;
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_fill_pollfd(struct pollfd *dest, struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	struct fdarray *fda;
Packit 9c3e7e
	int i;
Packit 9c3e7e
Packit 9c3e7e
	fda = port_fda(p);
Packit 9c3e7e
	for (i = 0; i < N_POLLFD; i++) {
Packit 9c3e7e
		dest[i].fd = fda->fd[i];
Packit 9c3e7e
		dest[i].events = POLLIN|POLLPRI;
Packit 9c3e7e
	}
Packit 9c3e7e
	dest[i].fd = port_fault_fd(p);
Packit 9c3e7e
	dest[i].events = POLLIN|POLLPRI;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_check_pollfd(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
	struct pollfd *dest = c->pollfd;
Packit 9c3e7e
Packit 9c3e7e
	if (c->pollfd_valid) {
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	LIST_FOREACH(p, &c->ports, list) {
Packit 9c3e7e
		clock_fill_pollfd(dest, p);
Packit 9c3e7e
		dest += N_CLOCK_PFD;
Packit 9c3e7e
	}
Packit 9c3e7e
	clock_fill_pollfd(dest, c->uds_port);
Packit 9c3e7e
	c->pollfd_valid = 1;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_fda_changed(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	c->pollfd_valid = 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int clock_do_forward_mgmt(struct clock *c,
Packit 9c3e7e
				 struct port *in, struct port *out,
Packit 9c3e7e
				 struct ptp_message *msg, int *pre_sent)
Packit 9c3e7e
{
Packit 9c3e7e
	if (in == out || !forwarding(c, out))
Packit 9c3e7e
		return 0;
Packit 9c3e7e
Packit 9c3e7e
	/* Don't forward any requests to the UDS port. */
Packit 9c3e7e
	if (out == c->uds_port) {
Packit 9c3e7e
		switch (management_action(msg)) {
Packit 9c3e7e
		case GET:
Packit 9c3e7e
		case SET:
Packit 9c3e7e
		case COMMAND:
Packit 9c3e7e
			return 0;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (!*pre_sent) {
Packit 9c3e7e
		/* delay calling msg_pre_send until
Packit 9c3e7e
		 * actually forwarding */
Packit 9c3e7e
		msg_pre_send(msg);
Packit 9c3e7e
		*pre_sent = 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	return port_forward(out, msg);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void clock_forward_mgmt_msg(struct clock *c, struct port *p, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *piter;
Packit 9c3e7e
	int pdulen = 0, msg_ready = 0;
Packit 9c3e7e
Packit 9c3e7e
	if (forwarding(c, p) && msg->management.boundaryHops) {
Packit 9c3e7e
		pdulen = msg->header.messageLength;
Packit 9c3e7e
		msg->management.boundaryHops--;
Packit 9c3e7e
		LIST_FOREACH(piter, &c->ports, list) {
Packit 9c3e7e
			if (clock_do_forward_mgmt(c, p, piter, msg, &msg_ready))
Packit 9c3e7e
				pr_err("port %d: management forward failed",
Packit 9c3e7e
				       port_number(piter));
Packit 9c3e7e
		}
Packit 9c3e7e
		if (clock_do_forward_mgmt(c, p, c->uds_port, msg, &msg_ready))
Packit 9c3e7e
			pr_err("uds port: management forward failed");
Packit 9c3e7e
		if (msg_ready) {
Packit 9c3e7e
			msg_post_recv(msg, pdulen);
Packit 9c3e7e
			msg->management.boundaryHops++;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
tmv_t clock_ingress_time(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->ingress_ts;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	int changed = 0, res, answers;
Packit 9c3e7e
	struct port *piter;
Packit 9c3e7e
	struct management_tlv *mgt;
Packit 9c3e7e
	struct ClockIdentity *tcid, wildcard = {
Packit 9c3e7e
		{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
Packit 9c3e7e
	};
Packit 9c3e7e
Packit 9c3e7e
	/* Forward this message out all eligible ports. */
Packit 9c3e7e
	clock_forward_mgmt_msg(c, p, msg);
Packit 9c3e7e
Packit 9c3e7e
	/* Apply this message to the local clock and ports. */
Packit 9c3e7e
	tcid = &msg->management.targetPortIdentity.clockIdentity;
Packit 9c3e7e
	if (!cid_eq(tcid, &wildcard) && !cid_eq(tcid, &c->dds.clockIdentity)) {
Packit 9c3e7e
		return changed;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (msg_tlv_count(msg) != 1) {
Packit 9c3e7e
		return changed;
Packit 9c3e7e
	}
Packit 9c3e7e
	mgt = (struct management_tlv *) msg->management.suffix;
Packit 9c3e7e
Packit 9c3e7e
	/*
Packit 9c3e7e
	  The correct length according to the management ID is checked
Packit 9c3e7e
	  in tlv.c, but management TLVs with empty bodies are also
Packit 9c3e7e
	  received successfully to support GETs and CMDs. At this
Packit 9c3e7e
	  point the TLV either has the correct length or length 2.
Packit 9c3e7e
	*/
Packit 9c3e7e
	switch (management_action(msg)) {
Packit 9c3e7e
	case GET:
Packit 9c3e7e
		if (clock_management_get_response(c, p, mgt->id, msg))
Packit 9c3e7e
			return changed;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case SET:
Packit 9c3e7e
		if (mgt->length == 2 && mgt->id != TLV_NULL_MANAGEMENT) {
Packit 9c3e7e
			clock_management_send_error(p, msg, TLV_WRONG_LENGTH);
Packit 9c3e7e
			return changed;
Packit 9c3e7e
		}
Packit 9c3e7e
		if (p != c->uds_port) {
Packit 9c3e7e
			/* Sorry, only allowed on the UDS port. */
Packit 9c3e7e
			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
Packit 9c3e7e
			return changed;
Packit 9c3e7e
		}
Packit 9c3e7e
		if (clock_management_set(c, p, mgt->id, msg, &changed))
Packit 9c3e7e
			return changed;
Packit 9c3e7e
		break;
Packit 9c3e7e
	case COMMAND:
Packit 9c3e7e
		break;
Packit 9c3e7e
	default:
Packit 9c3e7e
		return changed;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	switch (mgt->id) {
Packit 9c3e7e
	case TLV_PORT_PROPERTIES_NP:
Packit 9c3e7e
		if (p != c->uds_port) {
Packit 9c3e7e
			/* Only the UDS port allowed. */
Packit 9c3e7e
			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
Packit 9c3e7e
			return 0;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	switch (mgt->id) {
Packit 9c3e7e
	case TLV_USER_DESCRIPTION:
Packit 9c3e7e
	case TLV_SAVE_IN_NON_VOLATILE_STORAGE:
Packit 9c3e7e
	case TLV_RESET_NON_VOLATILE_STORAGE:
Packit 9c3e7e
	case TLV_INITIALIZE:
Packit 9c3e7e
	case TLV_FAULT_LOG:
Packit 9c3e7e
	case TLV_FAULT_LOG_RESET:
Packit 9c3e7e
	case TLV_DEFAULT_DATA_SET:
Packit 9c3e7e
	case TLV_CURRENT_DATA_SET:
Packit 9c3e7e
	case TLV_PARENT_DATA_SET:
Packit 9c3e7e
	case TLV_TIME_PROPERTIES_DATA_SET:
Packit 9c3e7e
	case TLV_PRIORITY1:
Packit 9c3e7e
	case TLV_PRIORITY2:
Packit 9c3e7e
	case TLV_DOMAIN:
Packit 9c3e7e
	case TLV_SLAVE_ONLY:
Packit 9c3e7e
	case TLV_TIME:
Packit 9c3e7e
	case TLV_CLOCK_ACCURACY:
Packit 9c3e7e
	case TLV_UTC_PROPERTIES:
Packit 9c3e7e
	case TLV_TRACEABILITY_PROPERTIES:
Packit 9c3e7e
	case TLV_TIMESCALE_PROPERTIES:
Packit 9c3e7e
	case TLV_PATH_TRACE_LIST:
Packit 9c3e7e
	case TLV_PATH_TRACE_ENABLE:
Packit 9c3e7e
	case TLV_GRANDMASTER_CLUSTER_TABLE:
Packit 9c3e7e
	case TLV_ACCEPTABLE_MASTER_TABLE:
Packit 9c3e7e
	case TLV_ACCEPTABLE_MASTER_MAX_TABLE_SIZE:
Packit 9c3e7e
	case TLV_ALTERNATE_TIME_OFFSET_ENABLE:
Packit 9c3e7e
	case TLV_ALTERNATE_TIME_OFFSET_NAME:
Packit 9c3e7e
	case TLV_ALTERNATE_TIME_OFFSET_MAX_KEY:
Packit 9c3e7e
	case TLV_ALTERNATE_TIME_OFFSET_PROPERTIES:
Packit 9c3e7e
	case TLV_TRANSPARENT_CLOCK_DEFAULT_DATA_SET:
Packit 9c3e7e
	case TLV_PRIMARY_DOMAIN:
Packit 9c3e7e
	case TLV_TIME_STATUS_NP:
Packit 9c3e7e
	case TLV_GRANDMASTER_SETTINGS_NP:
Packit 9c3e7e
	case TLV_SUBSCRIBE_EVENTS_NP:
Packit 9c3e7e
		clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
Packit 9c3e7e
		break;
Packit 9c3e7e
	default:
Packit 9c3e7e
		answers = 0;
Packit 9c3e7e
		LIST_FOREACH(piter, &c->ports, list) {
Packit 9c3e7e
			res = port_manage(piter, p, msg);
Packit 9c3e7e
			if (res < 0)
Packit 9c3e7e
				return changed;
Packit 9c3e7e
			if (res > 0)
Packit 9c3e7e
				answers++;
Packit 9c3e7e
		}
Packit 9c3e7e
		if (!answers) {
Packit 9c3e7e
			/* IEEE 1588 Interpretation #21 suggests to use
Packit 9c3e7e
			 * TLV_WRONG_VALUE for ports that do not exist */
Packit 9c3e7e
			clock_management_send_error(p, msg, TLV_WRONG_VALUE);
Packit 9c3e7e
		}
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
	return changed;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_notify_event(struct clock *c, enum notification event)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *uds = c->uds_port;
Packit 9c3e7e
	struct PortIdentity pid = port_identity(uds);
Packit 9c3e7e
	struct ptp_message *msg;
Packit 9c3e7e
	int id;
Packit 9c3e7e
Packit 9c3e7e
	switch (event) {
Packit 9c3e7e
	/* set id */
Packit 9c3e7e
	default:
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	/* targetPortIdentity and sequenceId will be filled by
Packit 9c3e7e
	 * clock_send_notification */
Packit 9c3e7e
	msg = port_management_notify(pid, uds);
Packit 9c3e7e
	if (!msg)
Packit 9c3e7e
		return;
Packit 9c3e7e
	if (!clock_management_fill_response(c, NULL, NULL, msg, id))
Packit 9c3e7e
		goto err;
Packit 9c3e7e
	if (msg_pre_send(msg))
Packit 9c3e7e
		goto err;
Packit 9c3e7e
	clock_send_notification(c, msg, event);
Packit 9c3e7e
err:
Packit 9c3e7e
	msg_put(msg);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct parent_ds *clock_parent_ds(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return &c->dad;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct PortIdentity clock_parent_identity(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->dad.pds.parentPortIdentity;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_set_sde(struct clock *c, int sde)
Packit 9c3e7e
{
Packit 9c3e7e
	c->sde = sde;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_poll(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	int cnt, i;
Packit 9c3e7e
	enum fsm_event event;
Packit 9c3e7e
	struct pollfd *cur;
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
Packit 9c3e7e
	clock_check_pollfd(c);
Packit 9c3e7e
	cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1);
Packit 9c3e7e
	if (cnt < 0) {
Packit 9c3e7e
		if (EINTR == errno) {
Packit 9c3e7e
			return 0;
Packit 9c3e7e
		} else {
Packit 9c3e7e
			pr_emerg("poll failed");
Packit 9c3e7e
			return -1;
Packit 9c3e7e
		}
Packit 9c3e7e
	} else if (!cnt) {
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	cur = c->pollfd;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(p, &c->ports, list) {
Packit 9c3e7e
		/* Let the ports handle their events. */
Packit 9c3e7e
		for (i = 0; i < N_POLLFD; i++) {
Packit 9c3e7e
			if (cur[i].revents & (POLLIN|POLLPRI)) {
Packit 9c3e7e
				event = port_event(p, i);
Packit 9c3e7e
				if (EV_STATE_DECISION_EVENT == event) {
Packit 9c3e7e
					c->sde = 1;
Packit 9c3e7e
				}
Packit 9c3e7e
				if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event) {
Packit 9c3e7e
					c->sde = 1;
Packit 9c3e7e
				}
Packit 9c3e7e
				port_dispatch(p, event, 0);
Packit 9c3e7e
				/* Clear any fault after a little while. */
Packit 9c3e7e
				if (PS_FAULTY == port_state(p)) {
Packit 9c3e7e
					clock_fault_timeout(p, 1);
Packit 9c3e7e
					break;
Packit 9c3e7e
				}
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
Packit 9c3e7e
		/*
Packit 9c3e7e
		 * When the fault timer expires we clear the fault,
Packit 9c3e7e
		 * but only if the link is up.
Packit 9c3e7e
		 */
Packit 9c3e7e
		if (cur[N_POLLFD].revents & (POLLIN|POLLPRI)) {
Packit 9c3e7e
			clock_fault_timeout(p, 0);
Packit 9c3e7e
			if (port_link_status_get(p)) {
Packit 9c3e7e
				port_dispatch(p, EV_FAULT_CLEARED, 0);
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
Packit 9c3e7e
		cur += N_CLOCK_PFD;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Check the UDS port. */
Packit 9c3e7e
	for (i = 0; i < N_POLLFD; i++) {
Packit 9c3e7e
		if (cur[i].revents & (POLLIN|POLLPRI)) {
Packit 9c3e7e
			event = port_event(c->uds_port, i);
Packit 9c3e7e
			if (EV_STATE_DECISION_EVENT == event) {
Packit 9c3e7e
				c->sde = 1;
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (c->sde) {
Packit 9c3e7e
		handle_state_decision_event(c);
Packit 9c3e7e
		c->sde = 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	clock_prune_subscriptions(c);
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_path_delay(struct clock *c, tmv_t req, tmv_t rx)
Packit 9c3e7e
{
Packit 9c3e7e
	tsproc_up_ts(c->tsproc, req, rx);
Packit 9c3e7e
Packit 9c3e7e
	if (tsproc_update_delay(c->tsproc, &c->path_delay))
Packit 9c3e7e
		return;
Packit 9c3e7e
Packit 9c3e7e
	c->cur.meanPathDelay = tmv_to_TimeInterval(c->path_delay);
Packit 9c3e7e
Packit 9c3e7e
	if (c->stats.delay)
Packit 9c3e7e
		stats_add_value(c->stats.delay, tmv_dbl(c->path_delay));
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_peer_delay(struct clock *c, tmv_t ppd, tmv_t req, tmv_t rx,
Packit 9c3e7e
		      double nrr)
Packit 9c3e7e
{
Packit 9c3e7e
	c->path_delay = ppd;
Packit 9c3e7e
	c->nrr = nrr;
Packit 9c3e7e
Packit 9c3e7e
	tsproc_set_delay(c->tsproc, ppd);
Packit 9c3e7e
	tsproc_up_ts(c->tsproc, req, rx);
Packit 9c3e7e
Packit 9c3e7e
	if (c->stats.delay)
Packit 9c3e7e
		stats_add_value(c->stats.delay, tmv_dbl(ppd));
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_slave_only(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->dds.flags & DDS_SLAVE_ONLY;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
UInteger16 clock_steps_removed(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->cur.stepsRemoved;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int clock_switch_phc(struct clock *c, int phc_index)
Packit 9c3e7e
{
Packit 9c3e7e
	struct servo *servo;
Packit 9c3e7e
	int fadj, max_adj;
Packit 9c3e7e
	clockid_t clkid;
Packit 9c3e7e
	char phc[32];
Packit 9c3e7e
Packit 9c3e7e
	snprintf(phc, sizeof(phc), "/dev/ptp%d", phc_index);
Packit 9c3e7e
	clkid = phc_open(phc);
Packit 9c3e7e
	if (clkid == CLOCK_INVALID) {
Packit 9c3e7e
		pr_err("Switching PHC, failed to open %s: %m", phc);
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	max_adj = phc_max_adj(clkid);
Packit 9c3e7e
	if (!max_adj) {
Packit 9c3e7e
		pr_err("Switching PHC, clock is not adjustable");
Packit 9c3e7e
		phc_close(clkid);
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	fadj = (int) clockadj_get_freq(clkid);
Packit 9c3e7e
	clockadj_set_freq(clkid, fadj);
Packit 9c3e7e
	servo = servo_create(c->config, c->servo_type, -fadj, max_adj, 0);
Packit 9c3e7e
	if (!servo) {
Packit 9c3e7e
		pr_err("Switching PHC, failed to create clock servo");
Packit 9c3e7e
		phc_close(clkid);
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	phc_close(c->clkid);
Packit 9c3e7e
	servo_destroy(c->servo);
Packit 9c3e7e
	c->clkid = clkid;
Packit 9c3e7e
	c->servo = servo;
Packit 9c3e7e
	c->servo_state = SERVO_UNLOCKED;
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin)
Packit 9c3e7e
{
Packit 9c3e7e
	double adj, weight;
Packit 9c3e7e
	enum servo_state state = SERVO_UNLOCKED;
Packit 9c3e7e
Packit 9c3e7e
	c->ingress_ts = ingress;
Packit 9c3e7e
Packit 9c3e7e
	tsproc_down_ts(c->tsproc, origin, ingress);
Packit 9c3e7e
Packit 9c3e7e
	if (tsproc_update_offset(c->tsproc, &c->master_offset, &weight)) {
Packit 9c3e7e
		if (c->free_running) {
Packit 9c3e7e
			return clock_no_adjust(c, ingress, origin);
Packit 9c3e7e
		} else {
Packit 9c3e7e
			return state;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (clock_utc_correct(c, ingress)) {
Packit 9c3e7e
		return c->servo_state;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c->cur.offsetFromMaster = tmv_to_TimeInterval(c->master_offset);
Packit 9c3e7e
Packit 9c3e7e
	if (c->free_running) {
Packit 9c3e7e
		return clock_no_adjust(c, ingress, origin);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	adj = servo_sample(c->servo, tmv_to_nanoseconds(c->master_offset),
Packit 9c3e7e
			   tmv_to_nanoseconds(ingress), weight, &state);
Packit 9c3e7e
	c->servo_state = state;
Packit 9c3e7e
Packit 9c3e7e
	if (c->stats.max_count > 1) {
Packit 9c3e7e
		clock_stats_update(&c->stats, tmv_dbl(c->master_offset), adj);
Packit 9c3e7e
	} else {
Packit 9c3e7e
		pr_info("master offset %10" PRId64 " s%d freq %+7.0f "
Packit 9c3e7e
			"path delay %9" PRId64,
Packit 9c3e7e
			tmv_to_nanoseconds(c->master_offset), state, adj,
Packit 9c3e7e
			tmv_to_nanoseconds(c->path_delay));
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	tsproc_set_clock_rate_ratio(c->tsproc, clock_rate_ratio(c));
Packit 9c3e7e
Packit 9c3e7e
	switch (state) {
Packit 9c3e7e
	case SERVO_UNLOCKED:
Packit 9c3e7e
		break;
Packit 9c3e7e
	case SERVO_JUMP:
Packit 9c3e7e
		clockadj_set_freq(c->clkid, -adj);
Packit 9c3e7e
		clockadj_step(c->clkid, -tmv_to_nanoseconds(c->master_offset));
Packit 9c3e7e
		c->ingress_ts = tmv_zero();
Packit 9c3e7e
		if (c->sanity_check) {
Packit 9c3e7e
			clockcheck_set_freq(c->sanity_check, -adj);
Packit 9c3e7e
			clockcheck_step(c->sanity_check,
Packit 9c3e7e
					-tmv_to_nanoseconds(c->master_offset));
Packit 9c3e7e
		}
Packit 9c3e7e
		tsproc_reset(c->tsproc, 0);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case SERVO_LOCKED:
Packit 9c3e7e
		clockadj_set_freq(c->clkid, -adj);
Packit 9c3e7e
		if (c->clkid == CLOCK_REALTIME) {
Packit 9c3e7e
			sysclk_set_sync();
Packit 9c3e7e
		}
Packit 9c3e7e
		if (c->sanity_check) {
Packit 9c3e7e
			clockcheck_set_freq(c->sanity_check, -adj);
Packit 9c3e7e
		}
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
	return state;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_sync_interval(struct clock *c, int n)
Packit 9c3e7e
{
Packit 9c3e7e
	int shift;
Packit 9c3e7e
Packit 9c3e7e
	shift = c->freq_est_interval - n;
Packit 9c3e7e
	if (shift < 0)
Packit 9c3e7e
		shift = 0;
Packit 9c3e7e
	else if (shift >= sizeof(int) * 8) {
Packit 9c3e7e
		shift = sizeof(int) * 8 - 1;
Packit 9c3e7e
		pr_warning("freq_est_interval is too long");
Packit 9c3e7e
	}
Packit 9c3e7e
	c->fest.max_count = (1 << shift);
Packit 9c3e7e
Packit 9c3e7e
	shift = c->stats_interval - n;
Packit 9c3e7e
	if (shift < 0)
Packit 9c3e7e
		shift = 0;
Packit 9c3e7e
	else if (shift >= sizeof(int) * 8) {
Packit 9c3e7e
		shift = sizeof(int) * 8 - 1;
Packit 9c3e7e
		pr_warning("summary_interval is too long");
Packit 9c3e7e
	}
Packit 9c3e7e
	c->stats.max_count = (1 << shift);
Packit 9c3e7e
Packit 9c3e7e
	servo_sync_interval(c->servo, n < 0 ? 1.0 / (1 << -n) : 1 << n);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct timePropertiesDS *clock_time_properties(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return &c->tds;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_update_time_properties(struct clock *c, struct timePropertiesDS tds)
Packit 9c3e7e
{
Packit 9c3e7e
	c->tds = tds;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void handle_state_decision_event(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	struct foreign_clock *best = NULL, *fc;
Packit 9c3e7e
	struct ClockIdentity best_id;
Packit 9c3e7e
	struct port *piter;
Packit 9c3e7e
	int fresh_best = 0;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(piter, &c->ports, list) {
Packit 9c3e7e
		fc = port_compute_best(piter);
Packit 9c3e7e
		if (!fc)
Packit 9c3e7e
			continue;
Packit 9c3e7e
		if (!best || c->dscmp(&fc->dataset, &best->dataset) > 0)
Packit 9c3e7e
			best = fc;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (best) {
Packit 9c3e7e
		best_id = best->dataset.identity;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		best_id = c->dds.clockIdentity;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (cid_eq(&best_id, &c->dds.clockIdentity)) {
Packit 9c3e7e
		pr_notice("selected local clock %s as best master",
Packit 9c3e7e
			  cid2str(&best_id));
Packit 9c3e7e
	} else {
Packit 9c3e7e
		pr_notice("selected best master clock %s",
Packit 9c3e7e
			  cid2str(&best_id));
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (!cid_eq(&best_id, &c->best_id)) {
Packit 9c3e7e
		clock_freq_est_reset(c);
Packit 9c3e7e
		tsproc_reset(c->tsproc, 1);
Packit 9c3e7e
		if (!tmv_is_zero(c->initial_delay))
Packit 9c3e7e
			tsproc_set_delay(c->tsproc, c->initial_delay);
Packit 9c3e7e
		c->ingress_ts = tmv_zero();
Packit 9c3e7e
		c->path_delay = c->initial_delay;
Packit 9c3e7e
		c->nrr = 1.0;
Packit 9c3e7e
		fresh_best = 1;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c->best = best;
Packit 9c3e7e
	c->best_id = best_id;
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(piter, &c->ports, list) {
Packit 9c3e7e
		enum port_state ps;
Packit 9c3e7e
		enum fsm_event event;
Packit 9c3e7e
		ps = bmc_state_decision(c, piter, c->dscmp);
Packit 9c3e7e
		switch (ps) {
Packit 9c3e7e
		case PS_LISTENING:
Packit 9c3e7e
			event = EV_NONE;
Packit 9c3e7e
			break;
Packit 9c3e7e
		case PS_GRAND_MASTER:
Packit 9c3e7e
			pr_notice("assuming the grand master role");
Packit 9c3e7e
			clock_update_grandmaster(c);
Packit 9c3e7e
			event = EV_RS_GRAND_MASTER;
Packit 9c3e7e
			break;
Packit 9c3e7e
		case PS_MASTER:
Packit 9c3e7e
			event = EV_RS_MASTER;
Packit 9c3e7e
			break;
Packit 9c3e7e
		case PS_PASSIVE:
Packit 9c3e7e
			event = EV_RS_PASSIVE;
Packit 9c3e7e
			break;
Packit 9c3e7e
		case PS_SLAVE:
Packit 9c3e7e
			clock_update_slave(c);
Packit 9c3e7e
			event = EV_RS_SLAVE;
Packit 9c3e7e
			break;
Packit 9c3e7e
		default:
Packit 9c3e7e
			event = EV_FAULT_DETECTED;
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
		port_dispatch(piter, event, fresh_best);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct clock_description *clock_description(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return &c->desc;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
enum clock_type clock_type(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	return c->type;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void clock_check_ts(struct clock *c, uint64_t ts)
Packit 9c3e7e
{
Packit 9c3e7e
	if (c->sanity_check && clockcheck_sample(c->sanity_check, ts)) {
Packit 9c3e7e
		servo_reset(c->servo);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
double clock_rate_ratio(struct clock *c)
Packit 9c3e7e
{
Packit 9c3e7e
	if (c->free_running) {
Packit 9c3e7e
		return c->master_local_rr;
Packit 9c3e7e
	}
Packit 9c3e7e
	return servo_rate_ratio(c->servo);
Packit 9c3e7e
}