Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <logging/log.h>
LOG_MODULE_DECLARE(net_gptp, CONFIG_NET_GPTP_LOG_LEVEL);

#include <drivers/ptp_clock.h>
#include <net/gptp.h>

#include "gptp_messages.h"
#include "gptp_data_set.h"

#include "net_private.h"

static sys_slist_t phase_dis_callbacks;

void gptp_register_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis,
				gptp_phase_dis_callback_t cb)
{
	sys_slist_find_and_remove(&phase_dis_callbacks, &phase_dis->node);
	sys_slist_prepend(&phase_dis_callbacks, &phase_dis->node);

	phase_dis->cb = cb;
}

void gptp_unregister_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis)
{
	sys_slist_find_and_remove(&phase_dis_callbacks, &phase_dis->node);
}

void gptp_call_phase_dis_cb(void)
{
	struct gptp_global_ds *global_ds;
	sys_snode_t *sn, *sns;
	uint8_t *gm_id;

	global_ds = GPTP_GLOBAL_DS();
	gm_id = &global_ds->gm_priority.root_system_id.grand_master_id[0];

	SYS_SLIST_FOR_EACH_NODE_SAFE(&phase_dis_callbacks, sn, sns) {
		struct gptp_phase_dis_cb *phase_dis =
			CONTAINER_OF(sn, struct gptp_phase_dis_cb, node);

		phase_dis->cb(gm_id,
			      &global_ds->gm_time_base_indicator,
			      &global_ds->clk_src_last_gm_phase_change,
			      &global_ds->clk_src_last_gm_freq_change);
	}
}

int gptp_event_capture(struct net_ptp_time *slave_time, bool *gm_present)
{
	int port, key;
	const struct device *clk;

	key = irq_lock();
	*gm_present =  GPTP_GLOBAL_DS()->gm_present;

	for (port = GPTP_PORT_START; port <= GPTP_PORT_END; port++) {
		/* Get first available clock, or slave clock if GM present. */
		if (!*gm_present || (GPTP_GLOBAL_DS()->selected_role[port] ==
				     GPTP_PORT_SLAVE)) {
			clk = net_eth_get_ptp_clock(GPTP_PORT_IFACE(port));
			if (clk) {
				ptp_clock_get(clk, slave_time);
				irq_unlock(key);
				return 0;
			}
		}
	}

	irq_unlock(key);
	return -EAGAIN;
}

char *gptp_sprint_clock_id(const uint8_t *clk_id, char *output, size_t output_len)
{
	return net_sprint_ll_addr_buf(clk_id, 8, output, output_len);
}

void gptp_clk_src_time_invoke(struct gptp_clk_src_time_invoke_params *arg)
{
	struct gptp_clk_master_sync_rcv_state *state;

	state = &GPTP_STATE()->clk_master_sync_receive;

	memcpy(&state->rcvd_clk_src_req, arg,
	       sizeof(struct gptp_clk_src_time_invoke_params));

	state->rcvd_clock_source_req = true;
}