wrs-startup.c 7.16 KB
Newer Older
1
/*
2 3 4 5
 * Copyright (C) 2011 CERN (www.cern.ch)
 * Author: Alessandro Rubini
 *
 * Released to the public domain
6 7 8 9 10 11 12 13 14 15
 */

/*
 * This is the startup thing for hosted environments. It
 * defines main and then calls the main loop.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
16
#include <time.h>
17 18 19 20
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
21
#include <sys/timex.h>
22
#include <signal.h>
23

24 25
#include <minipc.h>
#include <hal_exports.h>
26 27

#include <ppsi/ppsi.h>
28
#include <ppsi-wrs.h>
29
#include <libwr/shmem.h>
30

31 32
#  define WRSW_HAL_RETRIES 1000

33 34
#define WRSW_HAL_TIMEOUT 2000000 /* us */

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
static struct wr_operations wrs_wr_operations = {
	.locking_enable = wrs_locking_enable,
	.locking_poll = wrs_locking_poll,
	.locking_disable = wrs_locking_disable,
	.enable_ptracker = wrs_enable_ptracker,

	.adjust_in_progress = wrs_adjust_in_progress,
	.adjust_counters = wrs_adjust_counters,
	.adjust_phase = wrs_adjust_phase,

	.read_calib_data = wrs_read_calibration_data,
	.calib_disable = wrs_calibrating_disable,
	.calib_enable = wrs_calibrating_enable,
	.calib_poll = wrs_calibrating_poll,
	.calib_pattern_enable = wrs_calibration_pattern_enable,
	.calib_pattern_disable = wrs_calibration_pattern_disable,
51 52

	.enable_timing_output = wrs_enable_timing_output,
53
};
54

55
struct minipc_ch *hal_ch;
56
struct minipc_ch *ppsi_ch;
57 58
struct hal_port_state *hal_ports;
int hal_nports;
59
struct wrs_shm_head *ppsi_head;
60 61 62 63
/*
 * we need to call calloc, to reset all stuff that used to be static,
 * but we'd better have a simple prototype, compatilble with wrs_shm_alloc()
 */
64
static void *local_malloc(struct wrs_shm_head *headptr, size_t size)
65 66 67 68 69 70 71 72
{
	void *retval = malloc(size);

	if (retval)
		memset(retval, 0, size);
	return retval;
}

73 74 75 76
int main(int argc, char **argv)
{
	struct pp_globals *ppg;
	struct pp_instance *ppi;
77
	struct wr_dsport *wrp;
78
	unsigned long seed;
79
	struct timex t;
80
	int i, hal_retries;
81
	struct wrs_shm_head *hal_head;
82
	struct hal_shmem_header *h;
83 84
	void *(*alloc_fn)(struct wrs_shm_head *headptr, size_t size);
	alloc_fn = local_malloc;
85 86 87

	setbuf(stdout, NULL);

88 89 90
	pp_printf("PPSi. Commit %s, built on " __DATE__ "\n",
		PPSI_VERSION);

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
	/* check if there is another instance of PPSi already running */
	ppsi_head = wrs_shm_get(wrs_shm_ptp, "", WRS_SHM_READ);
	if (!ppsi_head) {
		pp_printf("Unable to open shm for PPSi! Unable to check if "
			  "there is another PPSi instance running. Error: %s\n",
			  strerror(errno));
		exit(1);
	}

	/* check if pid is 0 (shm not filled) or process with provided
	 * pid does not exist (probably crashed) */
	if ((ppsi_head->pid != 0) && (kill(ppsi_head->pid, 0) == 0)) {
		wrs_shm_put(ppsi_head);
		pp_printf("Fatal: There is another PPSi instance running. "
			  "Exit...\n\n");
		exit(1);
	}

109 110
	/* try connecting to HAL multiple times in case it's still not ready */
	hal_retries = WRSW_HAL_RETRIES;
111
	while (hal_retries) { /* may be never, if built without WR extension */
112 113
		hal_ch = minipc_client_create(WRSW_HAL_SERVER_ADDR,
					      MINIPC_FLAG_VERBOSE);
114
		if (hal_ch)
115
			break;
116
		hal_retries--;
117 118 119
		usleep(WRSW_HAL_TIMEOUT);
	}

120
	if (!hal_ch) {
121 122
		pp_printf("ppsi: could not connect to HAL RPC");
		exit(1);
123
	}
124

125 126 127 128 129 130 131 132 133 134 135 136 137
	/* If we connected, we also know "for sure" shmem is there */
	hal_head = wrs_shm_get(wrs_shm_hal,"", WRS_SHM_READ);
	if (!hal_head || !hal_head->data_off) {
		pp_printf("ppsi: Can't connect with HAL "
			  "shared memory\n");
		exit(1);
	}
	if (hal_head->version != HAL_SHMEM_VERSION) {
		pp_printf("ppsi: unknown HAL's shm version %i "
			  "(known is %i)\n", hal_head->version,
			  HAL_SHMEM_VERSION);
		exit(1);
	}
138

139 140
	h = (void *)hal_head + hal_head->data_off;
	hal_nports = h->nports;
141

142
	hal_ports = wrs_shm_follow(hal_head, h->ports);
143

144 145 146 147 148
	if (!hal_ports) {
		pp_printf("ppsi: unable to follow hal_ports pointer "
			  "in HAL's shmem\n");
		exit(1);
	}
149

150 151 152 153 154 155 156
	/* And create your own channel, until we move to shmem too */
	ppsi_ch = minipc_server_create("ptpd", 0);
	if (!ppsi_ch) { /* FIXME should we retry ? */
		pp_printf("ppsi: could not create minipc server");
		exit(1);
	}
	wrs_init_ipcserver(ppsi_ch);
157

158 159 160 161 162 163
	ppsi_head = wrs_shm_get(wrs_shm_ptp, "ppsi",
				WRS_SHM_WRITE | WRS_SHM_LOCKED);
	if (!ppsi_head) {
		fprintf(stderr, "Fatal: could not create shmem: %s\n",
			strerror(errno));
		exit(1);
164
	}
165 166
	alloc_fn = wrs_shm_alloc;
	ppsi_head->version = WRS_PPSI_SHMEM_VERSION;
167

168 169 170 171 172 173 174
	ppg = alloc_fn(ppsi_head, sizeof(*ppg));
	ppg->defaultDS = alloc_fn(ppsi_head, sizeof(*ppg->defaultDS));
	ppg->currentDS = alloc_fn(ppsi_head, sizeof(*ppg->currentDS));
	ppg->parentDS =  alloc_fn(ppsi_head, sizeof(*ppg->parentDS));
	ppg->timePropertiesDS = alloc_fn(ppsi_head,
					 sizeof(*ppg->timePropertiesDS));
	ppg->servo = alloc_fn(ppsi_head, sizeof(*ppg->servo));
175
	ppg->rt_opts = &__pp_default_rt_opts;
176

177
	ppg->max_links = PP_MAX_LINKS;
178
	ppg->global_ext_data = alloc_fn(ppsi_head,
179
					sizeof(struct wr_servo_state));
180
	/* NOTE: arch_data is not in shmem */
181 182 183
	ppg->arch_data = malloc( sizeof(struct unix_arch_data));
	ppg->pp_instances = alloc_fn(ppsi_head,
				     ppg->max_links * sizeof(*ppi));
184

185 186 187 188
	if ((!ppg->arch_data) || (!ppg->pp_instances)) {
		fprintf(stderr, "ppsi: out of memory\n");
		exit(1);
	}
189

190 191 192 193 194 195 196 197 198
	/* Set offset here, so config parsing can override it */
	if (adjtimex(&t) >= 0) {
		int *p;
		/*
		 * Our WRS kernel has tai support, but our compiler does not.
		 * We are 32-bit only, and we know for sure that tai is
		 * exactly after stbcnt. It's a bad hack, but it works
		 */
		p = (int *)(&t.stbcnt) + 1;
199
		ppg->timePropertiesDS->currentUtcOffset = *p;
200 201
	}

202 203
	if (pp_parse_cmdline(ppg, argc, argv) != 0)
		return -1;
204

205
	/* If no item has been parsed, provide a default file or string */
206
	if (ppg->cfg.cfg_items == 0)
207
		pp_config_file(ppg, 0, PP_DEFAULT_CONFIGFILE);
208
	if (ppg->cfg.cfg_items == 0) {
209 210 211 212 213
		/* Default configuration for WR switch is all ports */
		char s[128];
		int i;

		for (i = 0; i < 18; i++) {
214 215
			sprintf(s, "port %i; iface wri%i; proto raw;"
				"extension whiterabbit; role auto", i + 1, i + 1);
216 217 218
			pp_config_string(ppg, s);
		}
	}
219
	for (i = 0; i < ppg->nlinks; i++) {
220
		ppi = INST(ppg, i);
221 222
		ppi->ch[PP_NP_EVT].fd = -1;
		ppi->ch[PP_NP_GEN].fd = -1;
223

224
		ppi->glbs = ppg;
225
		ppi->vlans_array_len = CONFIG_VLAN_ARRAY_SIZE;
226
		ppi->iface_name = ppi->cfg.iface_name;
227
		ppi->port_name = ppi->cfg.port_name;
228
		ppi->mech = ppi->cfg.mech;
229
		ppi->portDS = calloc(1, sizeof(*ppi->portDS));
230 231 232 233 234 235 236
		if (ppi->portDS)
			ppi->portDS->ext_dsport =
				calloc(1, sizeof(struct wr_dsport));
		if (!ppi->portDS || !ppi->portDS->ext_dsport) {
			fprintf(stderr, "ppsi: out of memory\n");
			exit(1);
		}
237 238
		wrp = WR_DSPOR(ppi); /* just allocated above */
		wrp->ops = &wrs_wr_operations;
239 240 241 242 243

		/* The following default names depend on TIME= at build time */
		ppi->n_ops = &DEFAULT_NET_OPS;
		ppi->t_ops = &DEFAULT_TIME_OPS;

244 245 246 247 248 249 250
		ppi->__tx_buffer = malloc(PP_MAX_FRAME_LENGTH);
		ppi->__rx_buffer = malloc(PP_MAX_FRAME_LENGTH);

		if (!ppi->__tx_buffer || !ppi->__rx_buffer) {
			fprintf(stderr, "ppsi: out of memory\n");
			exit(1);
		}
251 252
	}

253
	pp_init_globals(ppg, &__pp_default_rt_opts);
254

255 256 257 258 259
	seed = time(NULL);
	if (getenv("PPSI_DROP_SEED"))
		seed = atoi(getenv("PPSI_DROP_SEED"));
	ppsi_drop_init(ppg, seed);

260
	/* release lock from wrs_shm_get */
261
	wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
262

263
	wrs_main_loop(ppg);
264 265
	return 0; /* never reached */
}