ppsi.h 10.4 KB
Newer Older
1
/*
2
 * Aurelio Colosimo for CERN, 2011 -- GNU LGPL v2.1 or later
3
 */
4

Alessandro Rubini's avatar
Alessandro Rubini committed
5 6
#ifndef __PPSI_PPSI_H__
#define __PPSI_PPSI_H__
7 8 9 10

#include <stdint.h>
#include <stdarg.h>
#include <arch/arch.h> /* ntohs and so on */
Alessandro Rubini's avatar
Alessandro Rubini committed
11 12 13
#include <ppsi/lib.h>
#include <ppsi/ieee1588_types.h>
#include <ppsi/constants.h>
14
#include <ppsi/jiffies.h>
Aurelio Colosimo's avatar
Aurelio Colosimo committed
15

16 17 18
#include <ppsi/pp-instance.h>
#include <ppsi/diag-macros.h>

19 20 21 22 23
/* We can't include pp-printf.h when building freestading, so have it here */
extern int pp_printf(const char *fmt, ...)
	__attribute__((format(printf, 1, 2)));
extern int pp_vprintf(const char *fmt, va_list args)
	__attribute__((format(printf, 1, 0)));
24 25
extern int pp_sprintf(char *s, const char *fmt, ...)
	__attribute__((format(printf,2,3)));
26 27 28
extern int pp_vsprintf(char *buf, const char *, va_list)
	__attribute__ ((format (printf, 2, 0)));

29

30
/* We use data sets a lot, so have these helpers */
31
static inline struct pp_globals *GLBS(struct pp_instance *ppi)
32
{
33
	return ppi->glbs;
34
}
35

36 37 38 39 40
static inline struct pp_runtime_opts *GOPTS(struct pp_globals *ppg)
{
	return ppg->rt_opts;
}

41
static inline struct pp_runtime_opts *OPTS(struct pp_instance *ppi)
42
{
43
	return GOPTS(GLBS(ppi));
44 45
}

46 47 48 49 50
static inline struct DSDefault *GDSDEF(struct pp_globals *ppg)
{
	return ppg->defaultDS;
}

51 52
static inline struct DSDefault *DSDEF(struct pp_instance *ppi)
{
53
	return GDSDEF(GLBS(ppi));
54 55
}

56 57
static inline struct DSCurrent *DSCUR(struct pp_instance *ppi)
{
58
	return GLBS(ppi)->currentDS;
59 60
}

61 62
static inline struct DSParent *DSPAR(struct pp_instance *ppi)
{
63
	return GLBS(ppi)->parentDS;
64 65
}

66 67 68 69 70
static inline struct DSPort *DSPOR(struct pp_instance *ppi)
{
	return ppi->portDS;
}

71 72
static inline struct DSTimeProperties *DSPRO(struct pp_instance *ppi)
{
73
	return GLBS(ppi)->timePropertiesDS;
74
}
75

76 77
static inline struct pp_net_path *NP(struct pp_instance *ppi)
{
78
	return &ppi->np;
79
}
80

81 82
static inline struct pp_servo *SRV(struct pp_instance *ppi)
{
83
	return GLBS(ppi)->servo;
84
}
85

86

87 88 89 90 91 92 93 94 95 96 97
/* Sometimes (e.g., raw ethernet frames), we need to consider an offset */
static inline void *pp_get_header(struct pp_instance *ppi, void *ptp_payload)
{
	return ptp_payload - NP(ppi)->ptp_offset;
}

static inline void *pp_get_payload(struct pp_instance *ppi, void *frame_ptr)
{
	return frame_ptr + NP(ppi)->ptp_offset;
}

98 99
extern void pp_prepare_pointers(struct pp_instance *ppi);

100

101 102
/*
 * Each extension should fill this structure that is used to augment
103
 * the standard states and avoid code duplications. Please remember
104 105 106 107 108 109
 * that proto-standard functions are picked as a fall-back when non
 * extension-specific code is provided. The set of hooks here is designed
 * based on what White Rabbit does. If you add more please remember to
 * allow NULL pointers.
 */
struct pp_ext_hooks {
110 111
	int (*init)(struct pp_instance *ppg, unsigned char *pkt, int plen);
	int (*open)(struct pp_globals *ppi, struct pp_runtime_opts *rt_opts);
112
	int (*close)(struct pp_globals *ppg);
113
	int (*listening)(struct pp_instance *ppi, unsigned char *pkt, int plen);
114 115
	int (*master_msg)(struct pp_instance *ppi, unsigned char *pkt,
			  int plen, int msgtype);
116 117
	int (*new_slave)(struct pp_instance *ppi, unsigned char *pkt, int plen);
	int (*update_delay)(struct pp_instance *ppi);
118
	void (*s1)(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann);
119 120 121 122
	int (*execute_slave)(struct pp_instance *ppi);
	void (*handle_announce)(struct pp_instance *ppi);
	int (*handle_followup)(struct pp_instance *ppi, TimeInternal *orig,
			       TimeInternal *correction_field);
123 124
	int (*pack_announce)(struct pp_instance *ppi);
	void (*unpack_announce)(void *buf, MsgAnnounce *ann);
125 126 127 128 129
};

extern struct pp_ext_hooks pp_hooks; /* The one for the extension we build */


130 131 132 133 134 135 136 137 138
/*
 * Network methods are encapsulated in a structure, so each arch only needs
 * to provide that structure. This should simplify management overall.
 */
struct pp_network_operations {
	int (*init)(struct pp_instance *ppi);
	int (*exit)(struct pp_instance *ppi);
	int (*recv)(struct pp_instance *ppi, void *pkt, int len,
		    TimeInternal *t);
139
	/* chtype here is PP_NP_GEN or PP_NP_EVT -- use_pdelay must be 0 */
140 141 142 143
	int (*send)(struct pp_instance *ppi, void *pkt, int len,
		    TimeInternal *t, int chtype, int use_pdelay_addr);
};

144 145 146
/* These can be liked and used as fallback by a different timing engine */
extern struct pp_network_operations unix_net_ops;

147

148 149 150 151 152 153 154
/*
 * Time operations, like network operations above, are encapsulated.
 * They may live in their own time-<name> subdirectory.
 *
 * Maybe this structure will need updating, to pass ppi as well
 */
struct pp_time_operations {
155 156
	int (*get)(struct pp_instance *ppi, TimeInternal *t);
	int (*set)(struct pp_instance *ppi, TimeInternal *t);
157
	/* freq_ppm is "scaled-ppm" like the argument of adjtimex(2) */
158
	int (*adjust)(struct pp_instance *ppi, long offset_ns, long freq_ppm);
159 160
	int (*adjust_offset)(struct pp_instance *ppi, long offset_ns);
	int (*adjust_freq)(struct pp_instance *ppi, long freq_ppm);
161 162
	/* calc_timeout cannot return zero */
	unsigned long (*calc_timeout)(struct pp_instance *ppi, int millisec);
163 164
};

165 166 167 168
/* These can be liked and used as fallback by a different timing engine */
extern struct pp_time_operations unix_time_ops;


169 170
/* FIXME this define is no more used; check whether it should be
 * introduced again */
171 172
#define  PP_ADJ_NS_MAX		(500*1000)

173 174
/* FIXME Restored to value of ptpd. What does this stand for, exactly? */
#define  PP_ADJ_FREQ_MAX	512000
175

176 177 178 179
/*
 * Timeouts. I renamed from "timer" to "timeout" to avoid
 * misread/miswrite with the time operations above. A timeout, actually,
 * is just a number that must be compared with the current counter.
180 181
 * So we don't need struct operations, as it is one function only,
 * which is folded into the "pp_time_operations" above.
182 183 184 185 186
 */

static inline void pp_timeout_set(struct pp_instance *ppi, int index,
				  int millisec)
{
187
	ppi->timeouts[index] = ppi->t_ops->calc_timeout(ppi, millisec);
188 189
}

190 191
extern void pp_timeout_rand(struct pp_instance *ppi, int index, int logval);

192 193 194 195 196
static inline void pp_timeout_clr(struct pp_instance *ppi, int index)
{
	ppi->timeouts[index] = 0;
}

197 198
extern void pp_timeout_log(struct pp_instance *ppi, int index);

199 200
static inline int pp_timeout(struct pp_instance *ppi, int index)
{
201
	int ret = ppi->timeouts[index] &&
202
		time_after_eq(ppi->t_ops->calc_timeout(ppi, 0),
203
			      ppi->timeouts[index]);
204

205
	if (ret)
206 207
		pp_timeout_log(ppi, index);
	return ret;
208 209
}

210 211 212 213 214 215 216 217
static inline int pp_timeout_z(struct pp_instance *ppi, int index)
{
	int ret = pp_timeout(ppi, index);

	if (ret)
		pp_timeout_clr(ppi, index);
	return ret;
}
218

219 220 221 222 223 224 225 226
/* how many ms to wait for the timeout to happen, for ppi->next_delay */
static inline int pp_ms_to_timeout(struct pp_instance *ppi, int index)
{
	signed long ret;

	if (!ppi->timeouts[index]) /* not pending, nothing to wait for */
		return 0;

227
	ret = ppi->timeouts[index] - ppi->t_ops->calc_timeout(ppi, 0);
228 229 230
	return ret <= 0 ? 0 : ret;
}

231 232 233 234 235 236 237 238
/* called several times, only sets a timeout, so inline it here */
static inline void pp_timeout_restart_annrec(struct pp_instance *ppi)
{
	/* This timeout is a number of the announce interval lapses */
	pp_timeout_set(ppi, PP_TO_ANN_RECEIPT,
		       ((DSPOR(ppi)->announceReceiptTimeout) <<
			DSPOR(ppi)->logAnnounceInterval) * 1000);
}
239 240


241
/* The channel for an instance must be created and possibly destroyed. */
242
extern int pp_open_globals(struct pp_globals *ppg);
243

244
extern int pp_close_globals(struct pp_globals *ppg);
245

246
extern int pp_parse_cmdline(struct pp_globals *ppg, int argc, char **argv);
247

248 249
extern int pp_parse_conf(struct pp_globals *ppg, char *conf, int len);

250
/* Servo */
251
extern void pp_init_clock(struct pp_instance *ppi);
252 253
extern void pp_update_delay(struct pp_instance *ppi,
			    TimeInternal *correction_field);
254 255
extern void pp_update_offset(struct pp_instance *ppi,
			     TimeInternal *correctionField);
256 257
extern void pp_update_clock(struct pp_instance *ppi);

258

259 260
/* bmc.c */
extern void m1(struct pp_instance *ppi);
261
extern void s1(struct pp_instance *ppi, MsgHeader *header, MsgAnnounce *ann);
262
extern int bmc(struct pp_instance *ppi);
263 264

/* msg.c */
265
extern void msg_pack_header(struct pp_instance *ppi, void *buf);
266
extern int __attribute__((warn_unused_result))
267
	msg_unpack_header(struct pp_instance *ppi, void *buf, int plen);
268
void *msg_copy_header(MsgHeader *dest, MsgHeader *src);
269
extern void msg_pack_sync(struct pp_instance *ppi, Timestamp *orig_tstamp);
270
extern void msg_unpack_sync(void *buf, MsgSync *sync);
271
extern int msg_pack_announce(struct pp_instance *ppi);
272
extern void msg_unpack_announce(void *buf, MsgAnnounce *ann);
273
extern void msg_pack_follow_up(struct pp_instance *ppi,
274
			       Timestamp *prec_orig_tstamp);
275
extern void msg_unpack_follow_up(void *buf, MsgFollowUp *flwup);
276
extern void msg_pack_delay_req(struct pp_instance *ppi,
277
			       Timestamp *orig_tstamp);
278
extern void msg_unpack_delay_req(void *buf, MsgDelayReq *delay_req);
279
extern void msg_pack_delay_resp(struct pp_instance *ppi,
280
				MsgHeader *hdr, Timestamp *rcv_tstamp);
281 282
extern void msg_unpack_delay_resp(void *buf, MsgDelayResp *resp);

283 284 285 286 287 288
/* each of them returns 0 if no error and -1 in case of error in send */
extern int msg_issue_announce(struct pp_instance *ppi);
extern int msg_issue_sync(struct pp_instance *ppi);
extern int msg_issue_followup(struct pp_instance *ppi, TimeInternal *time);
extern int msg_issue_delay_req(struct pp_instance *ppi);
extern int msg_issue_delay_resp(struct pp_instance *ppi, TimeInternal *time);
289

290 291

/* Functions for timestamp handling (internal to protocol format conversion*/
292
/* FIXME: add prefix in function name? */
293
extern void cField_to_TimeInternal(TimeInternal *internal, Integer64 bigint);
294 295
extern int from_TimeInternal(TimeInternal *internal, Timestamp *external);
extern int to_TimeInternal(TimeInternal *internal, Timestamp *external);
296 297
extern void add_TimeInternal(TimeInternal *r, TimeInternal *x, TimeInternal *y);
extern void sub_TimeInternal(TimeInternal *r, TimeInternal *x, TimeInternal *y);
298
extern void display_TimeInternal(const char *label, TimeInternal *t);
299
extern void div2_TimeInternal(TimeInternal *r);
300

301 302 303 304 305 306
/*
 * The state machine itself is an array of these structures.
 */

struct pp_state_table_item {
	int state;
307
	char *name;
308 309 310 311 312
	int (*f1)(struct pp_instance *ppi, uint8_t *packet, int plen);
};

extern struct pp_state_table_item pp_state_table[]; /* 0-terminated */

313

314

315
/* Use a typedef, to avoid long prototypes */
316 317 318 319
typedef int pp_action(struct pp_instance *ppi, uint8_t *packet, int plen);

/* Standard state-machine functions */
extern pp_action pp_initializing, pp_faulty, pp_disabled, pp_listening,
320 321
		 pp_pre_master, pp_master, pp_passive, pp_uncalibrated,
		 pp_slave;
322 323 324 325

/* The engine */
extern int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen);

Alessandro Rubini's avatar
Alessandro Rubini committed
326
#endif /* __PPSI_PPSI_H__ */