main-loop.c 3.75 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
 * This is the main loop for the wr-switch architecture. It's amost
 * the same as the unix main loop, but we must serve RPC calls too
11 12 13 14
 */
#include <stdlib.h>
#include <errno.h>
#include <sys/select.h>
15
#include <netinet/if_ether.h>
16 17

#include <ppsi/ppsi.h>
18
#include <ppsi-wrs.h>
19 20
#include <wr-api.h>
#include <hal_exports.h>
21
#include <common-fun.h>
22 23 24 25 26 27 28 29 30

/* Call pp_state_machine for each instance. To be called periodically,
 * when no packets are incoming */
static int run_all_state_machines(struct pp_globals *ppg)
{
	int j;
	int delay_ms = 0, delay_ms_j;

	for (j = 0; j < ppg->nlinks; j++) {
31
		struct pp_instance *ppi = INST(ppg, j);
32
		int old_lu = WR_DSPOR(ppi)->linkUP;
33
		struct hal_port_state *p;
34

35 36
		/* FIXME: we should save this pointer in the ppi itself */
		p = pp_wrs_lookup_port(ppi->iface_name);
37 38 39 40 41
		if (!p) {
			fprintf(stderr, "ppsi: can't find %s in shmem\n",
				ppi->iface_name);
			continue;
		}
42

43 44 45
		WR_DSPOR(ppi)->linkUP =
			(p->state != HAL_PORT_STATE_LINK_DOWN &&
			 p->state != HAL_PORT_STATE_DISABLED);
46 47 48 49 50 51 52 53 54 55 56 57 58

		if (old_lu != WR_DSPOR(ppi)->linkUP) {

			pp_diag(ppi, fsm, 1, "iface %s went %s\n",
				ppi->iface_name, WR_DSPOR(ppi)->linkUP ? "up":"down");

			if (WR_DSPOR(ppi)->linkUP) {
				ppi->state = PPS_INITIALIZING;
			}
			else {
				ppi->n_ops->exit(ppi);
				ppi->frgn_rec_num = 0;
				ppi->frgn_rec_best = -1;
59
				if (ppg->ebest_idx == ppi->port_idx)
60
					wr_servo_reset(ppi);
61 62 63 64 65 66 67 68
			}
		}

		/* Do not call state machine if link is down */
		if (WR_DSPOR(ppi)->linkUP)
			delay_ms_j = pp_state_machine(ppi, NULL, 0);
		else
			delay_ms_j = PP_DEFAULT_NEXT_DELAY_MS;
69 70

		/* delay_ms is the least delay_ms among all instances */
71
		if (j == 0)
72
			delay_ms = delay_ms_j;
73 74
		if (delay_ms_j < delay_ms)
			delay_ms = delay_ms_j;
75 76 77 78 79
	}

	return delay_ms;
}

80
void wrs_main_loop(struct pp_globals *ppg)
81 82 83 84 85 86 87 88
{
	struct pp_instance *ppi;
	int delay_ms;
	int j;

	/* Initialize each link's state machine */
	for (j = 0; j < ppg->nlinks; j++) {

89
		ppi = INST(ppg, j);
90 91 92 93 94 95

		/*
		* The main loop here is based on select. While we are not
		* doing anything else but the protocol, this allows extra stuff
		* to fit.
		*/
96
		ppi->is_new_state = 1;
97 98 99 100 101 102 103
	}

	delay_ms = run_all_state_machines(ppg);

	while (1) {
		int i;

104 105
		minipc_server_action(ppsi_ch, 10 /* ms */);

106 107 108 109 110
		/*
		 * If Ebest was changed in previous loop, run best
		 * master clock before checking for new packets, which
		 * would affect port state again
		 */
111 112 113
		if (ppg->ebest_updated) {
			for (j = 0; j < ppg->nlinks; j++) {
				int new_state;
114
				struct pp_instance *ppi = INST(ppg, j);
115 116 117
				new_state = bmc(ppi);
				if (new_state != ppi->state) {
					ppi->state = new_state;
118
					ppi->is_new_state = 1;
119 120 121 122 123
				}
			}
			ppg->ebest_updated = 0;
		}

124
		i = wrs_net_ops.check_packet(ppg, delay_ms);
125 126 127 128 129 130 131 132 133

		if (i < 0)
			continue;

		if (i == 0) {
			delay_ms = run_all_state_machines(ppg);
			continue;
		}

134
		/* If delay_ms is -1, the above ops.check_packet will continue
135 136 137 138 139 140
		 * consuming the previous timeout (see its implementation).
		 * This ensures that every state machine is called at least once
		 * every delay_ms */
		delay_ms = -1;

		for (j = 0; j < ppg->nlinks; j++) {
141
			int tmp_d;
142
			ppi = INST(ppg, j);
143

144 145
			if ((ppi->ch[PP_NP_GEN].pkt_present) ||
			    (ppi->ch[PP_NP_EVT].pkt_present)) {
146

147
				i = __recv_and_count(ppi, ppi->rx_frame,
148 149 150
						PP_MAX_FRAME_LENGTH - 4,
						&ppi->last_rcv_time);

151
				if (i == -2) {
152
					continue; /* dropped or not for us */
153 154 155 156 157 158 159
				}
				if (i == -1) {
					pp_diag(ppi, frames, 1,
						"Receive Error %i: %s\n",
						errno, strerror(errno));
					continue;
				}
160

161
				tmp_d = pp_state_machine(ppi, ppi->rx_ptp,
162
					i - ppi->rx_offset);
163 164 165

				if ((delay_ms == -1) || (tmp_d < delay_ms))
					delay_ms = tmp_d;
166 167 168 169
			}
		}
	}
}