ppsi.h 12 KB
Newer Older
1
/*
2 3 4 5
 * Copyright (C) 2011 CERN (www.cern.ch)
 * Author: Aurelio Colosimo
 *
 * Released according to the GNU LGPL, version 2.1 or any later version.
6
 */
7

Alessandro Rubini's avatar
Alessandro Rubini committed
8 9
#ifndef __PPSI_PPSI_H__
#define __PPSI_PPSI_H__
10
#include <generated/autoconf.h>
11 12 13

#include <stdint.h>
#include <stdarg.h>
Alessandro Rubini's avatar
Alessandro Rubini committed
14 15 16
#include <ppsi/lib.h>
#include <ppsi/ieee1588_types.h>
#include <ppsi/constants.h>
17
#include <ppsi/jiffies.h>
Aurelio Colosimo's avatar
Aurelio Colosimo committed
18

19 20 21
#include <ppsi/pp-instance.h>
#include <ppsi/diag-macros.h>

22 23
#include <arch/arch.h> /* ntohs and so on -- and wr-api.h for wr archs */

24 25 26 27
/* At this point in time, we need ARRAY_SIZE to conditionally build vlan code */
#undef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

28 29 30 31 32
/* 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)));
33 34
extern int pp_sprintf(char *s, const char *fmt, ...)
	__attribute__((format(printf,2,3)));
35 36 37
extern int pp_vsprintf(char *buf, const char *, va_list)
	__attribute__ ((format (printf, 2, 0)));

38 39 40 41 42 43 44 45 46
/* This structure is never defined, it seems */
struct pp_vlanhdr {
	uint8_t h_dest[6];
	uint8_t h_source[6];
	uint16_t h_tpid;
	uint16_t h_tci;
	uint16_t h_proto;
};

47

48
/* We use data sets a lot, so have these helpers */
49
static inline struct pp_globals *GLBS(struct pp_instance *ppi)
50
{
51
	return ppi->glbs;
52
}
53

54 55 56 57 58 59
static inline struct pp_instance *INST(struct pp_globals *ppg,
							int n_instance)
{
	return ppg->pp_instances + n_instance;
}

60 61 62 63 64
static inline struct pp_runtime_opts *GOPTS(struct pp_globals *ppg)
{
	return ppg->rt_opts;
}

65
static inline struct pp_runtime_opts *OPTS(struct pp_instance *ppi)
66
{
67
	return GOPTS(GLBS(ppi));
68 69
}

70 71 72 73 74
static inline struct DSDefault *GDSDEF(struct pp_globals *ppg)
{
	return ppg->defaultDS;
}

75 76
static inline struct DSDefault *DSDEF(struct pp_instance *ppi)
{
77
	return GDSDEF(GLBS(ppi));
78 79
}

80 81
static inline struct DSCurrent *DSCUR(struct pp_instance *ppi)
{
82
	return GLBS(ppi)->currentDS;
83 84
}

85 86
static inline struct DSParent *DSPAR(struct pp_instance *ppi)
{
87
	return GLBS(ppi)->parentDS;
88 89
}

90 91 92 93 94
static inline struct DSPort *DSPOR(struct pp_instance *ppi)
{
	return ppi->portDS;
}

95 96
static inline struct DSTimeProperties *DSPRO(struct pp_instance *ppi)
{
97
	return GLBS(ppi)->timePropertiesDS;
98
}
99

100
/* We used to have a "netpath" structure. Keep this until we merge pdelay */
101 102 103
static struct pp_instance *NP(struct pp_instance *ppi)
	__attribute__((deprecated));

104
static inline struct pp_instance *NP(struct pp_instance *ppi)
105
{
106
	return ppi;
107
}
108

109 110
static inline struct pp_servo *SRV(struct pp_instance *ppi)
{
111
	return GLBS(ppi)->servo;
112
}
113

114 115
extern void pp_prepare_pointers(struct pp_instance *ppi);

116 117
/*
 * Each extension should fill this structure that is used to augment
118
 * the standard states and avoid code duplications. Please remember
119 120 121 122 123 124
 * 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 {
125 126
	int (*init)(struct pp_instance *ppg, unsigned char *pkt, int plen);
	int (*open)(struct pp_globals *ppi, struct pp_runtime_opts *rt_opts);
127
	int (*close)(struct pp_globals *ppg);
128
	int (*listening)(struct pp_instance *ppi, unsigned char *pkt, int plen);
129 130
	int (*master_msg)(struct pp_instance *ppi, unsigned char *pkt,
			  int plen, int msgtype);
131
	int (*new_slave)(struct pp_instance *ppi, unsigned char *pkt, int plen);
132
	int (*handle_resp)(struct pp_instance *ppi);
133
	void (*s1)(struct pp_instance *ppi, MsgHeader *hdr, MsgAnnounce *ann);
134 135 136 137
	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);
138 139
	int (*pack_announce)(struct pp_instance *ppi);
	void (*unpack_announce)(void *buf, MsgAnnounce *ann);
140 141 142 143 144
};

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


145 146
/*
 * Network methods are encapsulated in a structure, so each arch only needs
147
 * to provide that structure. This simplifies management overall.
148 149 150 151 152 153
 */
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);
154
	/* chtype here is PP_NP_GEN or PP_NP_EVT -- use_pdelay must be 0 */
155 156
	int (*send)(struct pp_instance *ppi, void *pkt, int len,
		    TimeInternal *t, int chtype, int use_pdelay_addr);
157
	int (*check_packet)(struct pp_globals *ppg, int delay_ms);
158 159
};

160 161 162
/* This is the struct pp_network_operations to be provided by time- dir */
extern struct pp_network_operations DEFAULT_NET_OPS;

163 164 165
/* These can be liked and used as fallback by a different timing engine */
extern struct pp_network_operations unix_net_ops;

166

167 168 169 170
/*
 * Time operations, like network operations above, are encapsulated.
 * They may live in their own time-<name> subdirectory.
 *
171
 * If "set" receives a NULL time value, it should update the TAI offset.
172 173
 */
struct pp_time_operations {
174 175
	int (*get)(struct pp_instance *ppi, TimeInternal *t);
	int (*set)(struct pp_instance *ppi, TimeInternal *t);
176 177
	/* freq_ppb is parts per billion */
	int (*adjust)(struct pp_instance *ppi, long offset_ns, long freq_ppb);
178
	int (*adjust_offset)(struct pp_instance *ppi, long offset_ns);
179
	int (*adjust_freq)(struct pp_instance *ppi, long freq_ppb);
180
	int (*init_servo)(struct pp_instance *ppi);
181 182
	/* calc_timeout cannot return zero */
	unsigned long (*calc_timeout)(struct pp_instance *ppi, int millisec);
183 184
};

185 186 187
/* This is the struct pp_time_operations to be provided by time- dir */
extern struct pp_time_operations DEFAULT_TIME_OPS;

188 189 190 191
/* These can be liked and used as fallback by a different timing engine */
extern struct pp_time_operations unix_time_ops;


192 193
/* FIXME this define is no more used; check whether it should be
 * introduced again */
194 195
#define  PP_ADJ_NS_MAX		(500*1000)

196 197
/* FIXME Restored to value of ptpd. What does this stand for, exactly? */
#define  PP_ADJ_FREQ_MAX	512000
198

199 200 201 202
/*
 * 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.
203 204
 * So we don't need struct operations, as it is one function only,
 * which is folded into the "pp_time_operations" above.
205 206 207 208 209
 */

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

213 214
extern void pp_timeout_rand(struct pp_instance *ppi, int index, int logval);

215 216 217 218 219
static inline void pp_timeout_clr(struct pp_instance *ppi, int index)
{
	ppi->timeouts[index] = 0;
}

220 221
extern void pp_timeout_log(struct pp_instance *ppi, int index);

222 223
static inline int pp_timeout(struct pp_instance *ppi, int index)
{
224
	int ret = ppi->timeouts[index] &&
225
		time_after_eq(ppi->t_ops->calc_timeout(ppi, 0),
226
			      ppi->timeouts[index]);
227

228
	if (ret)
229 230
		pp_timeout_log(ppi, index);
	return ret;
231 232
}

233 234 235 236 237 238 239 240
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;
}
241

242 243 244 245 246 247 248 249
/* 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;

250
	ret = ppi->timeouts[index] - ppi->t_ops->calc_timeout(ppi, 0);
251 252 253
	return ret <= 0 ? 0 : ret;
}

254 255 256 257 258 259 260 261
/* 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);
}
262 263


264
/* The channel for an instance must be created and possibly destroyed. */
265
extern int pp_init_globals(struct pp_globals *ppg, struct pp_runtime_opts *opts);
266
extern int pp_close_globals(struct pp_globals *ppg);
267

268
extern int pp_parse_cmdline(struct pp_globals *ppg, int argc, char **argv);
269

270 271 272 273 274 275
/* platform independent timespec-like data structure */
struct pp_cfg_time {
	long tv_sec;
	long tv_nsec;
};

276 277 278 279 280 281
/* Data structure used to pass just a single argument to configuration
 * functions. Any future new type for any new configuration function can be just
 * added inside here, without redefining cfg_handler prototype */
union pp_cfg_arg {
	int i;
	char *s;
282
	struct pp_cfg_time ts;
283 284
};

285 286 287
/*
 * Configuration: we are structure-based, and a typedef simplifies things
 */
288 289
typedef int (*cfg_handler)(int lineno, struct pp_globals *ppg,
				union pp_cfg_arg *arg);
290 291 292 293 294 295 296 297 298 299

struct pp_argname {
	char *name;
	int value;
};
enum pp_argtype {
	ARG_NONE,
	ARG_INT,
	ARG_STR,
	ARG_NAMES,
300
	ARG_TIME,
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
};
struct pp_argline {
	cfg_handler f;
	char *keyword;	/* Each line starts with a keyword */
	enum pp_argtype t;
	struct pp_argname *args;
};

/* Both the architecture and the extension can provide config arguments */
extern struct pp_argline pp_arch_arglines[];
extern struct pp_argline pp_ext_arglines[];

/* Note: config_string modifies the string it receives */
extern int pp_config_string(struct pp_globals *ppg, char *s);
extern int pp_config_file(struct pp_globals *ppg, int force, char *fname);
316

317 318
#define PPSI_PROTO_RAW		0
#define PPSI_PROTO_UDP		1
319
#define PPSI_PROTO_VLAN		2	/* Actually: vlan over raw eth */
320 321 322 323 324 325 326 327 328

#define PPSI_ROLE_AUTO		0
#define PPSI_ROLE_MASTER	1
#define PPSI_ROLE_SLAVE		2

#define PPSI_EXT_NONE		0
#define PPSI_EXT_WR		1


329
/* Servo */
330 331 332
extern void pp_servo_init(struct pp_instance *ppi);
extern void pp_servo_got_sync(struct pp_instance *ppi); /* got t1 and t2 */
extern void pp_servo_got_resp(struct pp_instance *ppi); /* got all t1..t4 */
333

334

335 336
/* bmc.c */
extern void m1(struct pp_instance *ppi);
337
extern int bmc(struct pp_instance *ppi);
338 339

/* msg.c */
340
extern void msg_pack_header(struct pp_instance *ppi, void *buf);
341
extern int __attribute__((warn_unused_result))
342
	msg_unpack_header(struct pp_instance *ppi, void *buf, int plen);
343 344 345 346 347 348
extern void msg_unpack_sync(void *buf, MsgSync *sync);
extern void msg_unpack_announce(void *buf, MsgAnnounce *ann);
extern void msg_unpack_follow_up(void *buf, MsgFollowUp *flwup);
extern void msg_unpack_delay_req(void *buf, MsgDelayReq *delay_req);
extern void msg_unpack_delay_resp(void *buf, MsgDelayResp *resp);

349 350 351 352 353
/* each of them returns 0 if ok, -1 in case of error in send, 1 if stamp err */
#define PP_SEND_OK		0
#define PP_SEND_ERROR		-1
#define PP_SEND_NO_STAMP	1

354
extern int msg_issue_announce(struct pp_instance *ppi);
355
extern int msg_issue_sync_followup(struct pp_instance *ppi);
356 357
extern int msg_issue_delay_req(struct pp_instance *ppi);
extern int msg_issue_delay_resp(struct pp_instance *ppi, TimeInternal *time);
358

359 360

/* Functions for timestamp handling (internal to protocol format conversion*/
361
/* FIXME: add prefix in function name? */
362
extern void cField_to_TimeInternal(TimeInternal *internal, Integer64 bigint);
363 364
extern int from_TimeInternal(TimeInternal *internal, Timestamp *external);
extern int to_TimeInternal(TimeInternal *internal, Timestamp *external);
365 366
extern void add_TimeInternal(TimeInternal *r, TimeInternal *x, TimeInternal *y);
extern void sub_TimeInternal(TimeInternal *r, TimeInternal *x, TimeInternal *y);
367
extern void div2_TimeInternal(TimeInternal *r);
368

369 370 371 372
/*
 * The state machine itself is an array of these structures.
 */

373 374 375
/* Use a typedef, to avoid long prototypes */
typedef int pp_action(struct pp_instance *ppi, uint8_t *packet, int plen);

376 377
struct pp_state_table_item {
	int state;
378
	char *name;
379
	pp_action *f1;
380 381 382 383 384 385
};

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

/* Standard state-machine functions */
extern pp_action pp_initializing, pp_faulty, pp_disabled, pp_listening,
386 387
		 pp_pre_master, pp_master, pp_passive, pp_uncalibrated,
		 pp_slave;
388 389 390 391

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

392 393 394 395 396
/* Frame-drop support -- rx before tx, alphabetically */
extern void ppsi_drop_init(struct pp_globals *ppg, unsigned long seed);
extern int ppsi_drop_rx(void);
extern int ppsi_drop_tx(void);

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