port: Provide a common method for updating the port state.

When computing the next port state based on a FSM event, much of the logic
will stay the same for OC, BC, and TC nodes.

- handling a fault ASAP
- INITIALIZING state handling
- showing the transition in the log
- sending notifications

This patch moves this common code into a global port method, making it
available to future TC implementations.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
master
Richard Cochran 2017-08-06 20:43:30 +02:00
parent c170405822
commit 866da1044c
2 changed files with 54 additions and 37 deletions

82
port.c
View File

@ -2382,55 +2382,23 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff)
static void bc_dispatch(struct port *p, enum fsm_event event, int mdiff)
{
enum port_state next;
if (clock_slave_only(p->clock)) {
if (event == EV_RS_MASTER || event == EV_RS_GRAND_MASTER) {
port_slave_priority_warning(p);
}
}
next = p->state_machine(p->state, event, mdiff);
if (PS_FAULTY == next) {
struct fault_interval i;
fault_interval(p, last_fault_type(p), &i);
if (clear_fault_asap(&i)) {
pr_notice("port %hu: clearing fault immediately", portnum(p));
next = p->state_machine(next, EV_FAULT_CLEARED, 0);
}
}
if (PS_INITIALIZING == next) {
/*
* This is a special case. Since we initialize the
* port immediately, we can skip right to listening
* state if all goes well.
*/
if (port_is_enabled(p)) {
port_disable(p);
}
if (port_initialize(p)) {
event = EV_FAULT_DETECTED;
} else {
event = EV_INIT_COMPLETE;
}
next = p->state_machine(next, event, 0);
}
if (next == p->state)
if (!port_state_update(p, event, mdiff)) {
return;
port_show_transition(p, next, event);
}
if (p->delayMechanism == DM_P2P) {
port_p2p_transition(p, next);
port_p2p_transition(p, p->state);
} else {
port_e2e_transition(p, next);
port_e2e_transition(p, p->state);
}
p->state = next;
port_notify_event(p, NOTIFY_PORT_STATE);
if (p->jbod && next == PS_UNCALIBRATED) {
if (p->jbod && p->state == PS_UNCALIBRATED) {
if (clock_switch_phc(p->clock, p->phc_index)) {
p->last_fault_type = FT_SWITCH_PHC;
port_dispatch(p, EV_FAULT_DETECTED, 0);
@ -2987,3 +2955,43 @@ enum port_state port_state(struct port *port)
{
return port->state;
}
int port_state_update(struct port *p, enum fsm_event event, int mdiff)
{
enum port_state next = p->state_machine(p->state, event, mdiff);
if (PS_FAULTY == next) {
struct fault_interval i;
fault_interval(p, last_fault_type(p), &i);
if (clear_fault_asap(&i)) {
pr_notice("port %hu: clearing fault immediately", portnum(p));
next = p->state_machine(next, EV_FAULT_CLEARED, 0);
}
}
if (PS_INITIALIZING == next) {
/*
* This is a special case. Since we initialize the
* port immediately, we can skip right to listening
* state if all goes well.
*/
if (port_is_enabled(p)) {
port_disable(p);
}
if (port_initialize(p)) {
event = EV_FAULT_DETECTED;
} else {
event = EV_INIT_COMPLETE;
}
next = p->state_machine(next, event, 0);
}
if (next != p->state) {
port_show_transition(p, next, event);
p->state = next;
port_notify_event(p, NOTIFY_PORT_STATE);
return 1;
}
return 0;
}

9
port.h
View File

@ -212,6 +212,15 @@ struct port *port_open(int phc_index,
*/
enum port_state port_state(struct port *port);
/**
* Update a port's current state based on a given event.
* @param p A pointer previously obtained via port_open().
* @param event One of the @a fsm_event codes.
* @param mdiff Whether a new master has been selected.
* @return One (1) if the port state has changed, zero otherwise.
*/
int port_state_update(struct port *p, enum fsm_event event, int mdiff);
/**
* Return array of file descriptors for this port. The fault fd is not
* included.