wrc_main.c 7.92 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * This work is part of the White Rabbit project
 *
 * Copyright (C) 2011,2012 CERN (www.cern.ch)
 * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
 * Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
 *
 * Released according to the GNU GPL, version 2 or any later version.
 */
10 11 12
#include <stdio.h>
#include <inttypes.h>

13 14
#include <stdarg.h>

15
#include <wrc.h>
16
#include <w1.h>
17
#include <temperature.h>
18
#include "syscon.h"
19 20 21 22
#include "uart.h"
#include "endpoint.h"
#include "minic.h"
#include "pps_gen.h"
23
#include "ptpd_netif.h"
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
24
#include "i2c.h"
25
#include "storage.h"
26
#include "softpll_ng.h"
27
#include "onewire.h"
28
#include "pps_gen.h"
29
#include "shell.h"
Wesley W. Terpstra's avatar
Wesley W. Terpstra committed
30
#include "lib/ipv4.h"
31
#include "rxts_calibrator.h"
32
#include "flash.h"
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
33

34
#include "wrc_ptp.h"
35
#include "system_checks.h"
36

37 38 39 40
#ifndef CONFIG_DEFAULT_PRINT_TASK_TIME_THRESHOLD
#define CONFIG_DEFAULT_PRINT_TASK_TIME_THRESHOLD 0
#endif

41
int wrc_ui_mode = UI_SHELL_MODE;
42
int wrc_ui_refperiod = TICS_PER_SECOND; /* 1 sec */
43
int wrc_phase_tracking = 1;
44
char wrc_hw_name[HW_NAME_LENGTH];
45

46
uint32_t cal_phase_transition[wr_num_ports];
47

48 49
int wrc_vlan_number = CONFIG_VLAN_NR;

50
static uint32_t prev_nanos_for_profile;
51
static uint32_t prev_ticks_for_profile;
52
uint32_t print_task_time_threshold = CONFIG_DEFAULT_PRINT_TASK_TIME_THRESHOLD;
53
uint8_t mac_addr[wr_num_ports][6];
54

55
static void wrc_initialize(void)
56
{
57
	int port;
58
	sdb_find_devices();
59
	uart_init_hw();
60

61
	pp_printf("WR Core: starting up...\n");
62

63
	timer_init(1);
64
	get_hw_name(wrc_hw_name);
65
#ifdef CONFIG_SDB_STORAGE
66
	storage_read_hdl_cfg();
67
#endif
68
	wrpc_w1_init();
69 70
	wrpc_w1_bus.detail = ONEWIRE_PORT;
	w1_scan_bus(&wrpc_w1_bus);
71

72 73
	/*initialize flash*/
	flash_init();
74 75
	/*initialize I2C bus*/
	mi2c_init(WRPC_FMC_I2C);
76 77
	/*init storage (Flash / W1 EEPROM / I2C EEPROM*/
	storage_init(WRPC_FMC_I2C, FMC_EEPROM_ADR);
78

79
	if (get_persistent_mac(ONEWIRE_PORT, mac_addr[0]) == -1) {
80
		pp_printf("Unable to determine MAC address\n");
81 82 83 84 85 86 87 88
		for (port=0; port<wr_num_ports;port++) {
			mac_addr[0][0] = 0x22+port; //fallback MAC if get_persistent_mac fails
			mac_addr[0][1] = 0x33;
			mac_addr[0][2] = 0x44;
			mac_addr[0][3] = 0x55;
			mac_addr[0][4] = 0x66;
			mac_addr[0][5] = 0x77;
		}
89
	} else {
90 91 92 93 94 95 96 97
		for (port=0; port<wr_num_ports;port++) {
			mac_addr[port][0]=mac_addr[0][0]+port;
			mac_addr[port][1]=mac_addr[0][1];
			mac_addr[port][2]=mac_addr[0][2];
			mac_addr[port][3]=mac_addr[0][3];
			mac_addr[port][4]=mac_addr[0][4];
			mac_addr[port][5]=mac_addr[0][5];
		}
98
	}
99

100
	net_rst();
101

102 103 104
	//Duplicate the configuration for both ports.
	for (port=0; port<wr_num_ports;port++)
	{	
105 106 107
		pp_printf("PORT %d Local MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", port,
			mac_addr[port][0], mac_addr[port][1], mac_addr[port][2], mac_addr[port][3],
			mac_addr[port][4], mac_addr[port][5]);
108 109 110 111 112 113 114
		ep_init(mac_addr[port], port);
		/* Sleep for 1s to make sure WRS v4.2 always realizes that
		 * the link is down */
		timer_delay_ms(200);
		ep_enable(1, 1, port);
		minic_init(port);
	}
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
115

116
	shw_pps_gen_init();
117
	wrc_ptp_init();
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
118
	/* try reading t24 phase transition from EEPROM */
119
	for (port=0; port<wr_num_ports;port++){
120
		cal_phase_transition[port] = 5800; // default
121
	}
122

123
	spll_very_init();
124 125
	usleep_init();
	shell_init();
126

127 128 129
	wrc_ui_mode = UI_SHELL_MODE;
	_endram = ENDRAM_MAGIC;

130
	wrc_ptp_set_mode(WRC_MODE_MASTER, 0);
131
	
132
	shw_pps_gen_get_time(NULL, &prev_nanos_for_profile);
133 134
	/* get tics */
	prev_ticks_for_profile = timer_get_tics();
135
}
136

137 138 139 140 141
DEFINE_WRC_TASK0(idle) = {
	.name = "idle",
	.init = wrc_initialize,
};

142
uint8_t link_status[wr_num_ports];
143

144
static int wrc_check_link(void)
145
{
146 147
	static int prev_state[wr_num_ports];
	static uint8_t first_run=0;
148
	int state[wr_num_ports];
149
	int rv = 0;
150
	int port;
151 152 153 154

	if (first_run==0)
	{
		for(port=0; port<wr_num_ports; port++) {
155 156
			sfp_match(port);
			calib_t24p(WRC_MODE_MASTER, &cal_phase_transition[port],port);
157
			prev_state[port] = -1;
158 159 160 161 162 163 164 165 166 167
			state[port] = ep_link_up(NULL, port);
			if (state[port])
			{
				wrc_ptp_start(port);
				link_status[port] = LINK_UP;
				if (port==0) gpio_out(GPIO_LED_LINK, 1);
			} else {
				link_status[port] = LINK_DOWN;
				if (port==0) gpio_out(GPIO_LED_LINK, 0);
			}
168 169 170 171 172 173 174 175 176 177
		}
		first_run++;
	} else {
		for(port=0; port<wr_num_ports; port++) {
			state[port] = ep_link_up(NULL, port);

			if (!prev_state[port] && state[port]) {
				wrc_verbose("Port 0 Link up.\n");
				if (port==0) gpio_out(GPIO_LED_LINK, 1);
				sfp_match(port);
178
				calib_t24p(WRC_MODE_MASTER, &cal_phase_transition[port],port);
179 180 181 182 183 184 185 186
				wrc_ptp_start(port);
				link_status[port] = LINK_WENT_UP;
				rv = 1;
			} else if (prev_state[port] && !state[port]) {
				wrc_verbose("Port %d Link down.\n",port);
				if (port==0) gpio_out(GPIO_LED_LINK, 0);
				link_status[port] = LINK_WENT_DOWN;
				wrc_ptp_stop(port);
187
				minic_init(port);
188
				rv = 1;
189 190
			} else {
				link_status[port] = (state[port] ? LINK_UP : LINK_DOWN);
191
			}
192

193 194 195
			prev_state[port] = state[port];
		}	
	}
196
	return rv;
197
}
198 199 200 201
DEFINE_WRC_TASK(link) = {
	.name = "check-link",
	.job = wrc_check_link,
};
202

203
static int ui_update(void)
204
{
205
	int ret;
206

207
	if (wrc_ui_mode == UI_GUI_MODE) {
208
		ret = wrc_mon_gui();
209
		if (uart_read_byte() == 27 || wrc_ui_refperiod == 0) {
210 211
			shell_init();
			wrc_ui_mode = UI_SHELL_MODE;
212
		}
213
	} else {
214
		ret = shell_interactive();
215
	}
216
	return ret;
217
}
218

219 220
/* initialize functions to be called after reset in check_reset function */
void init_hw_after_reset(void)
221
{
222 223
	/* Ok, now init the devices so we can printf and delay */
	sdb_find_devices();
224
	uart_init_hw();
225 226 227
	timer_init(1);
}

228 229 230
/* count uptime, in seconds, for remote polling */
static uint32_t uptime_lastj;
static void init_uptime(void)
231
{
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	uptime_lastj = timer_get_tics();
}
static int update_uptime(void)
{
	extern uint32_t uptime_sec;
	uint32_t j;
	static uint32_t fraction = 0;

	j = timer_get_tics();
	fraction += j - uptime_lastj;
	uptime_lastj = j;
	if (fraction > TICS_PER_SECOND) {
		fraction -= TICS_PER_SECOND;
		uptime_sec++;
		return 1;
	}
	return 0;
}
250 251 252 253
DEFINE_WRC_TASK(uptime) = {
	.name = "uptime",
	.init = init_uptime,
	.job = update_uptime,
254 255
};

256 257 258 259 260 261 262 263 264 265 266 267 268
DEFINE_WRC_TASK(ptp) = {
	.name = "ptp",
	.job = wrc_ptp_update,
};
DEFINE_WRC_TASK(shell) = {
	.name = "shell+gui",
	.init = shell_boot_script,
	.job = ui_update,
};
DEFINE_WRC_TASK(spll) = {
	.name = "spll-bh",
	.job = spll_update,
};
269

270 271 272 273 274 275 276 277
static void task_time_normalize(struct wrc_task *t)
{
	if (t->nanos > 1000 * 1000 * 1000) {
		t->nanos -= 1000 * 1000 * 1000;
		t->seconds++;
	}
}

278 279 280 281 282
/* Account the time to either this task or task 0 */
static void account_task(struct wrc_task *t, int done_sth)
{
	uint32_t nanos;
	signed int delta;
283 284
	uint32_t ticks;
	signed int delta_ticks;
285 286

	if (!done_sth)
287
		t = __task_begin; /* task 0 is special */
288
	shw_pps_gen_get_time(NULL, &nanos);
289 290 291
	/* get monotonic number of ticks */
	ticks = timer_get_tics();

292 293 294 295 296
	delta = nanos - prev_nanos_for_profile;
	if (delta < 0)
		delta += 1000 * 1000 * 1000;

	t->nanos += delta;
297
	task_time_normalize(t);
298
	prev_nanos_for_profile = nanos;
299 300 301 302 303 304 305 306

	delta_ticks = ticks - prev_ticks_for_profile;
	if (delta_ticks < 0)
		delta_ticks += TICS_PER_SECOND;

	if (t->max_run_ticks < delta_ticks) {/* update max_run_ticks */
		if (print_task_time_threshold) {
			/* Print only if threshold is set */
307 308
			pp_printf("New max run time for a task %s, old %ld, "
				  "new %d\n",
309
				  t->name, t->max_run_ticks, delta_ticks);
310
		}
311
		t->max_run_ticks = delta_ticks;
312
	}
313 314 315 316 317
	if (print_task_time_threshold
            && delta_ticks > print_task_time_threshold)
		pp_printf("task %s, run for %d ms\n", t->name, delta_ticks);

	prev_ticks_for_profile = ticks;
318
}
319

320
/* Run a task with profiling */
321 322
static void wrc_run_task(struct wrc_task *t)
{
323 324 325 326 327 328 329 330 331 332
	int done_sth = 0;

	if (!t->job) /* idle task, just count iterations */
		t->nrun++;
	else if (!t->enable || *t->enable) {
		/* either enabled or without a check variable */
		done_sth = t->job();
		t->nrun += done_sth;
	}
	account_task(t, done_sth);
333
}
334

335
int main(void) __attribute__ ((weak));
336 337
int main(void)
{
338
	struct wrc_task *t;
339

340
	check_reset();
341

342
	/* initialization of individual tasks */
343 344 345
	for_each_task(t)
		if (t->init)
			t->init();
346

347
	for (;;) {
348 349
		for_each_task(t)
			wrc_run_task(t);
350

351
		/* better safe than sorry */
352
		check_stack();
353
	}
354
}