Commit 45b06a25 authored by Jukka Rissanen's avatar Jukka Rissanen
Browse files

net: gptp: Initial core IEEE 802.1AS support



Core IEEE 802.1AS-2011 (gPTP) support and application interface.

Signed-off-by: default avatarJukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: default avatarJulien Chevrier <julien.chevrier@intel.com>
parent e69c0589
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -108,6 +108,12 @@ Hostname Configuration Library
.. doxygengroup:: net_hostname
   :project: Zephyr

generic Precision Time Protocol (gPTP)
**************************************

.. doxygengroup:: gptp
   :project: Zephyr

Network technologies
********************

+51 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ struct net_eth_addr {
#define NET_ETH_PTYPE_IP		0x0800
#define NET_ETH_PTYPE_IPV6		0x86dd
#define NET_ETH_PTYPE_VLAN		0x8100
#define NET_ETH_PTYPE_PTP		0x88f7

#define NET_ETH_MINIMAL_FRAME_SIZE	60

@@ -188,6 +189,14 @@ struct ethernet_context {
		struct net_if *iface;
	} carrier_mgmt;

#if defined(CONFIG_NET_GPTP)
	/** The gPTP port number for this network device. We need to store the
	 * port number here so that we do not need to fetch it for every
	 * incoming gPTP packet.
	 */
	int port;
#endif

#if defined(CONFIG_NET_VLAN)
	/** Flag that tells whether how many VLAN tags are enabled for this
	 * context. The same information can be dug from the vlan array but
@@ -259,6 +268,22 @@ static inline bool net_eth_is_addr_multicast(struct net_eth_addr *addr)
	return false;
}

static inline bool net_eth_is_addr_lldp_multicast(struct net_eth_addr *addr)
{
#if defined(CONFIG_NET_GPTP)
	if (addr->addr[0] == 0x01 &&
	    addr->addr[1] == 0x80 &&
	    addr->addr[2] == 0xc2 &&
	    addr->addr[3] == 0x00 &&
	    addr->addr[4] == 0x00 &&
	    addr->addr[5] == 0x0e) {
		return true;
	}
#endif

	return false;
}

const struct net_eth_addr *net_eth_broadcast_addr(void);

/**
@@ -424,6 +449,32 @@ void net_eth_carrier_off(struct net_if *iface);
 */
struct device *net_eth_get_ptp_clock(struct net_if *iface);

#if defined(CONFIG_NET_GPTP)
/**
 * @brief Return gPTP port number attached to this interface.
 *
 * @param iface Network interface
 *
 * @return Port number, no such port if < 0
 */
int net_eth_get_ptp_port(struct net_if *iface);

/**
 * @brief Set gPTP port number attached to this interface.
 *
 * @param iface Network interface
 * @param port Port number to set
 */
void net_eth_set_ptp_port(struct net_if *iface, int port);
#else
static inline int net_eth_get_ptp_port(struct net_if *iface)
{
	ARG_UNUSED(iface);

	return -ENODEV;
}
#endif /* CONFIG_NET_GPTP */

#ifdef __cplusplus
}
#endif

include/net/gptp.h

0 → 100644
+296 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief Public functions for the Precision Time Protocol Stack.
 *
 */

#ifndef __GPTP_H
#define __GPTP_H

/**
 * @brief generic Precision Time Protocol (gPTP) support
 * @defgroup gptp gPTP support
 * @ingroup networking
 * @{
 */

#include <net/net_core.h>
#include <net/ptp_time.h>

#ifdef __cplusplus
extern "C" {
#endif

#define GPTP_CLOCK_ACCURACY_UNKNOWN        0xFE

#define GPTP_OFFSET_SCALED_LOG_VAR_UNKNOWN 0x436A

#define GPTP_PRIORITY1_NON_GM_CAPABLE      255
#define GPTP_PRIORITY2_DEFAULT             248

/**
 * @brief Scaled Nanoseconds.
 */
struct gptp_scaled_ns {
	/** High half. */
	s32_t high;

	/** Low half. */
	s64_t low;
} __packed;

/**
 * @brief UScaled Nanoseconds.
 */
struct gptp_uscaled_ns {
	/** High half. */
	u32_t high;

	/** Low half. */
	u64_t low;
} __packed;

#if defined(CONFIG_NEWLIB_LIBC)
#include <math.h>

#define GPTP_POW2(exp) pow(2, exp)
#else

static inline double _gptp_pow2(int exp)
{
	double res;

	if (exp >= 0) {
		res = 1 << exp;
	} else {
		res = 1.0;

		while (exp++) {
			res /= 2;
		}
	}

	return res;
}

#define GPTP_POW2(exp) _gptp_pow2(exp)
#endif

/* Message types. Event messages have BIT(3) set to 0, and general messages
 * have that bit set to 1. IEEE 802.1AS chapter 10.5.2.2.2
 */
#define GPTP_SYNC_MESSAGE                0x00
#define GPTP_DELAY_REQ_MESSAGE           0x01
#define GPTP_PATH_DELAY_REQ_MESSAGE      0x02
#define GPTP_PATH_DELAY_RESP_MESSAGE     0x03
#define GPTP_FOLLOWUP_MESSAGE            0x08
#define GPTP_DELAY_RESP_MESSAGE          0x09
#define GPTP_PATH_DELAY_FOLLOWUP_MESSAGE 0x0a
#define GPTP_ANNOUNCE_MESSAGE            0x0b
#define GPTP_SIGNALING_MESSAGE           0x0c
#define GPTP_MANAGEMENT_MESSAGE          0x0d

#define GPTP_IS_EVENT_MSG(msg_type)      (!((msg_type) & BIT(3)))

#define GPTP_CLOCK_ID_LEN                8

/**
 * @brief Port Identity.
 */
struct gptp_port_identity {
	/** Clock identity of the port. */
	u8_t clk_id[GPTP_CLOCK_ID_LEN];

	/** Number of the port. */
	u16_t port_number;
} __packed;

struct gptp_flags {
	union {
		/** Byte access. */
		u8_t octets[2];

		/** Whole field access. */
		u16_t all;
	};
} __packed;

struct gptp_hdr {
	/** Type of the message. */
	u8_t message_type:4;

	/** Transport specific, always 1. */
	u8_t transport_specific:4;

	/** Version of the PTP, always 2. */
	u8_t ptp_version:4;

	/** Reserved field. */
	u8_t reserved0:4;

	/** Total length of the message from the header to the last TLV. */
	u16_t message_length;

	/** Domain number, always 0. */
	u8_t domain_number;

	/** Reserved field. */
	u8_t reserved1;

	/** Message flags. */
	struct gptp_flags flags;

	/** Correction Field. The content depends of the message type. */
	s64_t correction_field;

	/** Reserved field. */
	u32_t reserved2;

	/** Port Identity of the sender. */
	struct gptp_port_identity port_id;

	/** Sequence Id. */
	u16_t sequence_id;

	/** Control value. Sync: 0, Follow-up: 2, Others: 5. */
	u8_t control;

	/** Message Interval in Log2 for Sync and Announce messages. */
	s8_t log_msg_interval;
} __packed;

/*
 * TODO: k_uptime_get need to be replaced by the MAC ptp_clock.
 * The ptp_clock access infrastructure is not ready yet
 * so use it for the time being.
 * k_uptime time precision is in ms.
 */
#define GPTP_GET_CURRENT_TIME_NANOSECOND() (k_uptime_get() * 1000000)
#define GPTP_GET_CURRENT_TIME_USCALED_NS(uscaled_ns_ptr)		\
	do {								\
		(uscaled_ns_ptr)->low =					\
			GPTP_GET_CURRENT_TIME_NANOSECOND() << 16;	\
		(uscaled_ns_ptr)->high = 0;				\
	} while (0)

/**
 * @typedef gptp_phase_dis_callback_t
 * @brief Define callback that is called after a phase discontinuity has been
 *        sent by the grandmaster.
 * @param "u8_t *gm_identity" A pointer to first element of a
 *        ClockIdentity array. The size of the array is GPTP_CLOCK_ID_LEN.
 * @param "u16_t *gm_time_base" A pointer to the value of timeBaseIndicator
 *        of the current grandmaster.
 * @param "struct scaled_ns *last_gm_ph_change" A pointer to the value of
 *        lastGmPhaseChange received from grandmaster.
 * @param "double *last_gm_freq_change" A pointer to the value of
 *        lastGmFreqChange received from the grandmaster.
 */
typedef void (*gptp_phase_dis_callback_t)(
	u8_t *gm_identity,
	u16_t *time_base,
	struct gptp_scaled_ns *last_gm_ph_change,
	double *last_gm_freq_change);

/**
 * @brief Phase discontinuity callback structure.
 *
 * Stores the phase discontinuity callback information. Caller must make sure
 * that the variable pointed by this is valid during the lifetime of
 * registration. Typically this means that the variable cannot be
 * allocated from stack.
 */
struct gptp_phase_dis_cb {
	/** Node information for the slist. */
	sys_snode_t node;

	/** Phase discontinuity callback. */
	gptp_phase_dis_callback_t cb;
};

/**
 * @brief Register a phase discontinuity callback.
 *
 * @param phase_dis Caller specified handler for the callback.
 * @param cb Callback to register.
 */
void gptp_register_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis,
				gptp_phase_dis_callback_t cb);

/**
 * @brief Unregister a phase discontinuity callback.
 *
 * @param phase_dis Caller specified handler for the callback.
 */
void gptp_unregister_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis);

/**
 * @brief Call a phase discontinuity callback function.
 */
void gptp_call_phase_dis_cb(void);

/**
 * @brief Get gPTP time.
 *
 * @param slave_time A pointer to structure where timestamp will be saved.
 * @param gm_present A pointer to a boolean where status of the
 *        presence of a grand master will be saved.
 *
 * @return Error code. 0 if no error.
 */
int gptp_event_capture(struct net_ptp_time *slave_time, bool *gm_present);

/**
 * @brief Utility function to print clock id to a user supplied buffer.
 *
 * @param clk_id Clock id
 * @param output Output buffer
 * @param output_len Output buffer len
 *
 * @return Pointer to output buffer
 */
char *gptp_sprint_clock_id(const u8_t *clk_id, char *output,
			   size_t output_len);

/**
 * @typedef gptp_port_cb_t
 * @brief Callback used while iterating over gPTP ports
 *
 * @param port Port number
 * @param iface Pointer to network interface
 * @param user_data A valid pointer to user data or NULL
 */
typedef void (*gptp_port_cb_t)(int port, struct net_if *iface,
			       void *user_data);

/**
 * @brief Go through all the gPTP ports and call callback for each of them.
 *
 * @param cb User-supplied callback function to call
 * @param user_data User specified data
 */
void gptp_foreach_port(gptp_port_cb_t cb, void *user_data);

/**
 * @brief Get gPTP domain.
 * @details This contains all the configuration / status of the gPTP domain.
 *
 * @return Pointer to domain or NULL if not found.
 */
struct gptp_domain *gptp_get_domain(void);

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

#endif /* __GPTP_H */
+2 −0
Original line number Diff line number Diff line
@@ -62,8 +62,10 @@ enum net_sock_type {

#define ntohs(x) sys_be16_to_cpu(x)
#define ntohl(x) sys_be32_to_cpu(x)
#define ntohll(x) sys_be64_to_cpu(x)
#define htons(x) sys_cpu_to_be16(x)
#define htonl(x) sys_cpu_to_be32(x)
#define htonll(x) sys_cpu_to_be64(x)

/** IPv6 address structure */
struct in6_addr {
+4 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <net/net_core.h>
#include <net/dns_resolve.h>
#include <net/tcp.h>
#include <net/gptp.h>

#include "net_private.h"
#include "net_shell.h"
@@ -130,6 +131,9 @@ static void processing_data(struct net_pkt *pkt, bool is_loopback)
/* Things to setup after we are able to RX and TX */
static void net_post_init(void)
{
#if defined(CONFIG_NET_GPTP)
	net_gptp_init();
#endif
}

static void init_rx_queues(void)
Loading