Commit cc873eac authored by Jean-Claude BAU's avatar Jean-Claude BAU

HAL review

New implementation of HAL using sub state machines. The objective is to
facilitate the integration of the new feature "Low Phase Drift
Calibration" which needs two new state machines.
The HAL state machine is available by opening the hal.html file
parent 328b9f52
......@@ -6,12 +6,12 @@
#include <string.h>
/* Port state machine states */
#define HAL_PORT_STATE_DISABLED 0
#define HAL_PORT_STATE_LINK_DOWN 1
#define HAL_PORT_STATE_UP 2
#define HAL_PORT_STATE_CALIBRATION 3
#define HAL_PORT_STATE_LOCKING 4
#define HAL_PORT_STATE_RESET 5
typedef enum {
HAL_PORT_STATE_INIT=0,
HAL_PORT_STATE_DISABLED,
HAL_PORT_STATE_LINK_DOWN,
HAL_PORT_STATE_LINK_UP,
} halPortState_t;
/* Read temperature from SFPs */
#define READ_SFP_DIAG_ENABLE 1
......@@ -59,33 +59,36 @@ typedef struct hal_port_calibration {
struct shw_sfp_caldata sfp;
struct shw_sfp_header sfp_header_raw;
struct shw_sfp_dom sfp_dom_raw;
int sfpPresent;
} hal_port_calibration_t;
/* Internal port state structure */
struct hal_port_state {
/* non-zero: allocated */
int in_use;
/* linux i/f name */
char name[16];
typedef struct {
int state;
int nextState;
} halPortFsmState_t;
/* MAC addr */
uint8_t hw_addr[6];
typedef struct {
int isSupported; /* Set if Low Phase Drift Calibration is supported */
halPortFsmState_t txSetupStates;
halPortFsmState_t rxSetupStates;
}halPortLPDC_t; /* data for Low phase drift calibration */
/* ioctl() hw index */
int hw_index;
/* file descriptor for ioctls() */
int fd;
/* Internal port state structure */
struct hal_port_state {
int in_use; /* non-zero: allocated */
char name[16]; /* linux i/f name */
uint8_t hw_addr[6]; /* MAC addr */
int hw_index; /* ioctl() hw index : 0..n */
int fd; /* file descriptor for ioctls() */
int hw_addr_auto;
/* port FSM state (HAL_PORT_STATE_xxxx) */
int state;
halPortFsmState_t portStates;
/* fiber type, used to get alpha for SFP frequency */
int fiber_index;
/* 1: PLL is locked to this port */
int locked;
int fiber_index;/* fiber type, used to get alpha for SFP frequency */
int locked; /* 1: PLL is locked to this port */
/* calibration data */
hal_port_calibration_t calib;
......@@ -94,11 +97,10 @@ struct hal_port_state {
uint32_t phase_val;
int phase_val_valid;
int tx_cal_pending, rx_cal_pending;
/* locking FSM state */
int lock_state;
/*reference lock period in picoseconds*/
uint32_t clock_period;
int lock_state; /* locking FSM state */
uint32_t clock_period; /*reference lock period in picoseconds*/
/* approximate DMTD phase value (on slave port) at which RX timestamp
* (T2) counter transistion occurs (picoseconds) */
......@@ -108,8 +110,7 @@ struct hal_port_state {
* counter transistion occurs (picoseconds) */
uint32_t t4_phase_transition;
/* Endpoint's base address */
uint32_t ep_base;
uint32_t ep_base;/* Endpoint's base address */
/* whether SFP has diagnostic Monitoring capability */
int has_sfp_diag;
......@@ -122,6 +123,16 @@ struct hal_port_state {
int synchronized; // <>0 if port is synchronized
int portInfoUpdated; // Set to 1 when updated
/* Events to process */
int evt_reset; /* Set if a reset is requested */
int evt_lock; /* Set if the ptracker must be activated*/
int evt_linkUp; /* Set if link is up ( driver call */
/* Low phase drift calibration data */
halPortLPDC_t lpdc;
/* Pll FSM */
halPortFsmState_t pllStates;
};
struct hal_temp_sensors {
......@@ -132,8 +143,7 @@ struct hal_temp_sensors {
};
/* This is the overall structure stored in shared memory */
#define HAL_SHMEM_VERSION 12 /* Version 12, added monitor to
struct hal_port_state */
#define HAL_SHMEM_VERSION 13 /* Version 13, HAL code review */
struct hal_shmem_header {
int nports;
......@@ -143,10 +153,14 @@ struct hal_shmem_header {
int read_sfp_diag;
};
static inline int state_up(int state)
static inline int get_port_state(struct hal_port_state *ps)
{
return ps->portStates.state;
}
static inline int state_up(struct hal_port_state *ps)
{
return (state != HAL_PORT_STATE_LINK_DOWN
&& state != HAL_PORT_STATE_DISABLED);
return get_port_state(ps) == HAL_PORT_STATE_LINK_UP;
}
static inline struct hal_port_state *hal_lookup_port(
......
Subproject commit 135c480e387345315ed3d205342629fea45a1ca3
Subproject commit 5285a9abcd9b2c30c914129e05831e0eeccac0fc
......@@ -98,8 +98,8 @@ time_t wrsPortStatusTable_data_fill(unsigned int *n_rows)
* values defined as WRS_PORT_STATUS_LINK_*
*/
wrsPortStatusTable_array[i].wrsPortStatusLink =
1 + state_up(port_state->state);
if (port_state->state == HAL_PORT_STATE_DISABLED) {
1 + state_up(&port_state);
if (get_port_state(port_state) == HAL_PORT_STATE_DISABLED) {
wrsPortStatusTable_array[i].wrsPortStatusSfpError =
WRS_PORT_STATUS_SFP_ERROR_PORT_DOWN;
/* if port is disabled don't fill
......
......@@ -666,7 +666,7 @@ void show_ports(int hal_alive, int ppsi_alive)
if (mode == SHOW_GUI) {
/* check if link is up */
if (state_up(port_state->state))
if (state_up(port_state))
term_cprintf(C_GREEN, " %-5s", if_name);
else
term_cprintf(C_RED, "*%-5s", if_name);
......@@ -816,7 +816,7 @@ void show_ports(int hal_alive, int ppsi_alive)
}
term_cprintf(C_WHITE, "\n");
} else if (mode & WEB_INTERFACE) {
printf("%s ", state_up(port_state->state)
printf("%s ", state_up(port_state)
? "up" : "down");
printf("%s ", port_state->locked
? "Locked" : "NoLock");
......@@ -825,7 +825,7 @@ void show_ports(int hal_alive, int ppsi_alive)
? "Calibrated" : "Uncalibrated");
} else if (print_port) {
printf("port:%s ", if_name);
printf("lnk:%d ", state_up(port_state->state));
printf("lnk:%d ", state_up(port_state));
printf("lock:%d ", port_state->locked);
print_port = 0;
}
......
......@@ -401,7 +401,11 @@ struct dump_info hal_port_info [] = {
DUMP_FIELD(int, hw_index),
DUMP_FIELD(int, fd),
DUMP_FIELD(int, hw_addr_auto),
DUMP_FIELD(int, state),
DUMP_FIELD(int, portStates.state),
DUMP_FIELD(int, pllStates.state),
DUMP_FIELD(int, lpdc.isSupported),
DUMP_FIELD(int, lpdc.txSetupStates.state),
DUMP_FIELD(int, lpdc.rxSetupStates.state),
DUMP_FIELD(int, fiber_index),
DUMP_FIELD(int, locked),
/* these fields are defined as uint32_t but we prefer %i to %x */
......
......@@ -2,7 +2,9 @@
# We are now Kconfig-based
-include ../../.config
OBJS = hal_exports.o hal_main.o hal_ports.o hal_timing.o
OBJS = hal_exports.o hal_main.o hal_ports.o hal_timing.o \
hal_port_gen_fsm.o hal_port_fsm.o hal_port_fsm_tx.o hal_port_fsm_rx.o hal_port_fsm_pll.o\
hal_port_leds.o hal_timer.o
BINARY = wrsw_hal
......
......@@ -77,7 +77,7 @@ int halexp_lock_cmd(const char *port_name, int command, int priority)
* both the PLLs and the PPS Generator. */
int halexp_pps_cmd(int cmd, hexp_pps_params_t * params)
{
int busy,ret;
int ret;
pr_debug("halexp_pps_cmd: cmd=%d\n", cmd);
switch (cmd) {
......@@ -142,9 +142,7 @@ int halexp_pps_cmd(int cmd, hexp_pps_params_t * params)
return shw_pps_gen_enable_output(params->pps_valid);
case HEXP_PPSG_CMD_SET_TIMING_MODE:
ret=shw_pps_set_timing_mode(params->timing_mode);
hal_update_timing_mode();
return ret;
return hal_set_timing_mode(params->timing_mode);
case HEXP_PPSG_CMD_GET_TIMING_MODE:{
ret=hal_get_timing_mode();
......
......@@ -22,11 +22,38 @@
#include <libwr/timeout.h>
#include "wrsw_hal.h"
#include "hal_timer.h"
#include <rt_ipc.h>
#define MAX_CLEANUP_CALLBACKS 16
#define UPDATE_FAN_PERIOD 500
#define UPDATE_ALL_PERIOD 100
typedef enum {
TMO_UPDATE_ALL=0,
TMO_UPDATE_FAN,
TMO_COUNT
}main_tmo_id_t;
static void cb_timer_update_fan(int timerId);
static void cb_timer_update_all(int timerId);
/* Polling timeouts (RT Subsystem & SFP detection) */
static timer_parameter_t _timerParameters[] = {
{
.id=TMO_UPDATE_ALL,
.tmoMs=100, // 100ms
.repeat=1,
.cb=cb_timer_update_all
},
{
.id=TMO_UPDATE_FAN,
.tmoMs=500, // 500ms
.repeat=1,
.cb=cb_timer_update_fan
},
};
#define MAIN_TIMER_COUNT (sizeof(_timerParameters)/sizeof(timer_parameter_t))
static int daemon_mode = 0;
static hal_cleanup_callback_t cleanup_cb[MAX_CLEANUP_CALLBACKS];
......@@ -223,11 +250,25 @@ static void hal_parse_cmdline(int argc, char *argv[])
}
}
static void cb_timer_update_fan(int timerId) {
struct hal_temp_sensors temp_sensors; /* local copy of temperatures */
/* Update fans and get temperatures values. Don't write
* temperatures directly to the shmem to reduce the
* critical section of shmem */
shw_update_fans(&temp_sensors);
wrs_shm_write(hal_shmem_hdr, WRS_SHM_WRITE_BEGIN);
memcpy(&hal_shmem->temp, &temp_sensors,
sizeof(temp_sensors));
wrs_shm_write(hal_shmem_hdr, WRS_SHM_WRITE_END);
}
static void cb_timer_update_all(int timerId) {
hal_port_update_all();
}
int main(int argc, char *argv[])
{
struct hal_temp_sensors temp_sensors; /* local copy of temperatures */
static timeout_t update_fan_tmo;
static timeout_t update_all_tmo;
wrs_msg_init(argc, argv, LOG_DAEMON);
......@@ -246,8 +287,7 @@ int main(int argc, char *argv[])
if (hal_init())
exit(1);
libwr_tmo_init(&update_fan_tmo, UPDATE_FAN_PERIOD, 1);
libwr_tmo_init(&update_all_tmo, UPDATE_ALL_PERIOD, 1);
timerInit(_timerParameters,MAIN_TIMER_COUNT);
/*
* Main loop update - polls for WRIPC requests and rolls the port
......@@ -263,19 +303,8 @@ int main(int argc, char *argv[])
for (;;) {
hal_update_wripc(25 /* max ms delay */);
if (libwr_tmo_expired(&update_all_tmo))
hal_port_update_all();
if (libwr_tmo_expired(&update_fan_tmo)) {
/* Update fans and get temperatures values. Don't write
* temperatures directly to the shmem to reduce the
* critical section of shmem */
shw_update_fans(&temp_sensors);
wrs_shm_write(hal_shmem_hdr, WRS_SHM_WRITE_BEGIN);
memcpy(&hal_shmem->temp, &temp_sensors,
sizeof(temp_sensors));
wrs_shm_write(hal_shmem_hdr, WRS_SHM_WRITE_END);
}
// Check main timers and call callback if timeout expires
timerScan(_timerParameters,MAIN_TIMER_COUNT);
}
hal_shutdown();
......
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/if.h>
#include <rt_ipc.h>
#include <hal_exports.h>
#include <libwr/hal_shmem.h>
#include <libwr/switch_hw.h>
#include "hal_ports.h"
#include "hal_port_leds.h"
#include "hal_port_gen_fsm.h"
#include "hal_port_fsmP.h"
#include "hal_port_fsm_rx.h"
#include "hal_port_fsm_tx.h"
#include "hal_port_fsm_pll.h"
#include "wrsw_hal.h"
/**
* State machine
* States :
* - HAL_PORT_STATE_INIT:
* Inital state
* - HAL_PORT_STATE_DISABLED:
* The port is disabled and waiting for a SFP insertion
* - HAL_PORT_STATE_LINK_DOWN:
* A Sfp is inserted but the port is waiting for being up
* - HAL_PORT_STATE_LINK_UP:
* The port is UP and operational
* Events :
* - timer : triggered regularly to execute background work
* - sfpInserted: A Sfp has been inserted
* - sfpRemoved : A Sfp has been removed
* - linkUp : A link up has been detected (driver ioctl)
* - Link down : Port is going down
* - reset : Reset of the port is requested
*
*/
/* external prototypes */
static int _builPortEvents(void * vpfg);
static int _hal_port_state_init(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_state_disabled(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_state_link_down(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_state_link_up(void *vpfg, int eventMsk, int isNewState);
static void _init_port(struct hal_port_state * ps);
static void _reset_port(struct hal_port_state * ps);
static void _unlock_port( struct hal_port_state * ps);
static int _get_port_link_state(struct hal_port_state * ps,int *linkUp);
static halPortStateTable_t _fsmStateTable[] =
{
{ .state=HAL_PORT_STATE_INIT,
.stateName="INIT",
FSM_SET_FCT_NAME(_hal_port_state_init)
},
{ .state=HAL_PORT_STATE_DISABLED,
.stateName="DISABLED",
FSM_SET_FCT_NAME(_hal_port_state_disabled)
},
{ .state=HAL_PORT_STATE_LINK_DOWN,
.stateName="LINK_DOWN",
FSM_SET_FCT_NAME(_hal_port_state_link_down)
},
{ .state=HAL_PORT_STATE_LINK_UP,
.stateName="LINK_UP",
FSM_SET_FCT_NAME(_hal_port_state_link_up)
},
{.state=1}
};
static halPortEventTable_t _fsmEvtTable[] = {
{
.evtMask = HAL_PORT_EVENT_TIMER,
.evtName="TIMER"
},
{
.evtMask =HAL_PORT_EVENT_SFP_INSERTED,
.evtName = "SFP_INS"
},
{
.evtMask =HAL_PORT_EVENT_SFP_REMOVED,
.evtName = "SFP_REM"
},
{
.evtMask =HAL_PORT_EVENT_LINK_UP,
.evtName = "LINK_UP"
},
{ .evtMask =HAL_PORT_EVENT_LINK_DOWN,
.evtName = "LINK_DOWN"
},
{ .evtMask =HAL_PORT_EVENT_RESET,
.evtName = "REET"
},
{ .evtMask = -1 } };
static halPortFsmGen_t _portFsm = {
.fsm_name="PortFsm",
.fctBuilEvents=_builPortEvents,
.pt=_fsmStateTable,
.pe=_fsmEvtTable
};
/* INIT state
*
* if entering in state then
* init port
* init TX SETUP FSM
* fi
* run TX SETUP FSM
* if final state reached (TX SETUP FSM) then state = DISABLED
*
*/
static int _hal_port_state_init(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
if ( isNewState ) {
_init_port(ps);
/* Init the tx state machine */
hal_port_tx_setup_init_fsm(ps);
}
/* if final state reached for tx setup state machine
* then we can go to DISABLED state
*/
if (hal_port_tx_setup_state_fsm(ps)==1 )
_fireState(vpfg,HAL_PORT_STATE_DISABLED);
return 0;
}
/*
* DISABLED state
*
* if entering in state then reset port
* if SFP inserted the state=LINK_DOWN
*/
static int _hal_port_state_disabled(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
if ( isNewState ) {
_reset_port(ps);
}
if ( _isHalEventSfpInserted(eventMsk) )
_fireState(vpfg,HAL_PORT_STATE_LINK_DOWN);
return 0;
}
/* LINK_DOWN state
*
* if SFP removed event then state= DISABLED
* if entering in state then
* reset port
* init RX_SETUP FSM
* fi
* run RX_SETUP FSM
* if final state (RX_SETUP FSM ) reached then state=LINK_UP
*/
static int _hal_port_state_link_down(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
// High priority event received
if ( _isHalEventSfpRemoved(eventMsk) ) {
_fireState(vpfg,HAL_PORT_STATE_DISABLED);
return 0;
}
if ( isNewState ) {
_reset_port(ps);
/* Init the rx state machine */
hal_port_rx_setup_init_fsm(ps);
}
/* if final state reached for tx setup state machine then
* we can go LINK_UP state
*/
if (hal_port_rx_setup_state_fsm(ps)==1 ) {
_fireState(vpfg,HAL_PORT_STATE_LINK_UP);
return 0;
}
return 0;
}
/* LINK_UP state :
*
* if SFP removed event then state= DISABLED
* if reset or link down events then state= LINK_DOWN
* if entering in state then inititialize PLL FSM
* Run PLL FSM
* Update Leds
*/
static int _hal_port_state_link_up(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
if ( _isHalEventSfpRemoved(eventMsk) ) {
_unlock_port(ps);
_fireState(vpfg,HAL_PORT_STATE_DISABLED);
return 0;
}
if ( _isHalEventReset(eventMsk) || _isHalEventLinkDown(eventMsk)) {
_unlock_port(ps);
_fireState(vpfg,HAL_PORT_STATE_LINK_DOWN);
return 0;
}
if ( isNewState ) {
// Init PLL FSM
hal_port_pll_init_fsm(ps);
}
// Run PLL state machine
hal_port_pll_state_fsm(ps);
// Update leds
{
// Update synced led
int ledValue= ps->synchronized
&& (ps->portInfoUpdated--) > -50 // 50 * 100ms (FSM call rate) = 5seconds
? 1 : 0;
led_set_synched(ps->hw_index, ledValue);
// Update link led
if (ps->portMode == PORT_MODE_SLAVE)
ledValue=SFP_LED_WRMODE_SLAVE;
else if (ps->portMode == PORT_MODE_MASTER)
ledValue=SFP_LED_WRMODE_MASTER;
else
ledValue=SFP_LED_WRMODE_OTHER;
led_set_wrmode(ps->hw_index,ledValue);
}
return 0;
}
/*
* Build all events
*/
static int _builPortEvents(void * vpfg) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
int portEventMask=HAL_PORT_EVENT_TIMER;
if ( ps->evt_linkUp != -1 ) {
portEventMask |= ps->evt_linkUp ?
HAL_PORT_EVENT_LINK_UP : HAL_PORT_EVENT_LINK_DOWN;
}
if ( ps->evt_reset ) {
portEventMask |= HAL_PORT_EVENT_RESET;
ps->evt_reset=0;
}
portEventMask |= ps->calib.sfpPresent ?
HAL_PORT_EVENT_SFP_INSERTED : HAL_PORT_EVENT_SFP_REMOVED;
return portEventMask;
}
/* Init the FSM on all ports. Called one time at startup */
void hal_port_state_fsm_init( struct hal_port_state * ps ) {
int portIndex;
for (portIndex = 0; portIndex < HAL_MAX_PORTS; portIndex++) {
if ( ps->in_use)
_portFsm.ps=ps;
_portFsm.st=&ps->portStates;
ps->portStates.state=-1;
_fireState(&_portFsm,HAL_PORT_STATE_INIT);
ps++; /* Next port */
}
}
/* Call FSM for on all ports */
void hal_port_state_fsm( struct hal_port_state * ps ) {
int portIndex;
hal_port_poll_rts_state(); // Update rts state on all ports
/* Call state machine for all ports */
for (portIndex = 0; portIndex < HAL_MAX_PORTS; portIndex++) {
if ( ps->in_use) {
_portFsm.ps=ps;
_portFsm.st=&ps->portStates;
/* Update evt_linkUp */
if ( _get_port_link_state(ps,&ps->evt_linkUp)==-1 ) {
// IOTCL error : We put -1 in the link state. It will be considered as invalid
ps->evt_linkUp=-1;
}
hal_port_generic_fsm(&_portFsm);
}
ps++; /* Next port */
}
}
/* Reset port
* Called when entering in states DISABLED and LINK_DOWN and when the port is initialized the first time
*/
static void _reset_port(struct hal_port_state * ps)
{
// Disable ptracker : Needed if we were in state LINK_UP with a timing mode set to BC
rts_enable_ptracker(ps->hw_index, 0);
// Clear data
ps->calib.rx_calibrated =
ps->calib.tx_calibrated =
ps->locked = 0;
ps->lock_state =
ps->tx_cal_pending =
ps->rx_cal_pending = 0;
ps->portMode= PORT_MODE_OTHER;
ps->synchronized=ps->portInfoUpdated=0;
ps->locked=0;
ps->calib.phy_tx_min = ps->calib.phy_rx_min = 0; // No longer used
ps->calib.delta_tx_board = 0; /* never set */
ps->calib.delta_rx_board = 0; /* never set */
ps->tx_cal_pending = 0;
ps->rx_cal_pending = 0;
/* Set link/wrmode LEDs to other. Master/slave
* color is set in the different place */
led_set_wrmode(ps->hw_index,SFP_LED_WRMODE_OTHER);
/* turn off synced LED */
led_set_synched(ps->hw_index, 0);
}
/* Port initialization */
static void _init_port(struct hal_port_state * ps)
{
_reset_port(ps);
ps->t2_phase_transition = DEFAULT_T2_PHASE_TRANS;
ps->t4_phase_transition = DEFAULT_T4_PHASE_TRANS;
ps->clock_period = REF_CLOCK_PERIOD_PS;
}
/* Action done when leaving states locking/up */
static void _unlock_port( struct hal_port_state * ps)
{
if ( hal_get_timing_mode()==HAL_TIMING_MODE_BC ) {
hal_set_timing_mode(HAL_TIMING_MODE_FREE_MASTER);
}
// Disable tracker
rts_enable_ptracker(ps->hw_index, 0);
ps->locked=0;
}
/* Checks if the link is up on inteface (if_name). Returns non-zero if yes. */
static int _get_port_link_state(struct hal_port_state * ps,int *linkUp)
{
struct ifreq ifr;
strncpy(ifr.ifr_name, ps->name, sizeof(ifr.ifr_name));
if (ioctl(halPorts.hal_port_fd, SIOCGIFFLAGS, &ifr) < 0 ) {
pr_error("%s: IOCTL error detected : Cannot check link up on %s",__func__,ps->name);
return -1;
}
*linkUp=(ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING);
return 0;
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_H
#define HAL_PORT_FSM_H
/* Prototypes */
void fsm_state_machine( struct hal_port_state * ps );
void hal_port_state_fsm( struct hal_port_state * ps );
void hal_port_state_fsm_init( struct hal_port_state * ps );
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSMP_H
#define HAL_PORT_FSMP_H
#include "hal_port_fsm.h"
typedef enum
{
HAL_PORT_EVENT_TIMER=(1<<0),
HAL_PORT_EVENT_SFP_INSERTED=(1<<1),
HAL_PORT_EVENT_SFP_REMOVED=(1<<3),
HAL_PORT_EVENT_LINK_UP=(1<<4),
HAL_PORT_EVENT_LINK_DOWN=(1<<5),
HAL_PORT_EVENT_RESET=(1<<6)
}halPortEventMask_t ;
static __inline__ int _isHalEventInitialized(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_TIMER;
}
static __inline__ int _isHalEventSfpInserted(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_SFP_INSERTED;
}
static __inline__ int _isHalEventSfpRemoved(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_SFP_REMOVED;
}
static __inline__ int _isHalEventLinkUp(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_LINK_UP;
}
static __inline__ int _isHalEventLinkDown(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_LINK_DOWN;
}
static __inline__ int _isHalEventReset(halPortEventMask_t eventMsk) {
return eventMsk & HAL_PORT_EVENT_RESET;
}
#endif
#include <hal_exports.h>
#include <libwr/hal_shmem.h>
#include "hal_ports.h"
#include "hal_port_fsm_pllP.h"
/**
* State machine
* States :
* - HAL_PORT_PLL_STATE_UNLOCKED: Inital state
* - HAL_PORT_PLL_STATE_LOCKING : Waiting PLL locking
* - HAL_PORT_PLL_STATE_LOCKED : Final state. Pll locked
* Events :
* - HAL_PORT_PLL_EVENT_TIMER : Use to do background stuff
* - HAL_PORT_PLL_EVENT_LOCK : Lock is requested (timing mode=BC)
* - HAL_PORT_PLL_EVENT_LOCKED : Port is locked
* - HAL_PORT_PLL_EVENT_UNLOCK : Pll is unlocked
* - HAL_PORT_PLL_EVENT_DISABLED : PLL lock is not requested
*
*
*/
/* external prototypes */
static int _buildEvents(void * vpfg);
static int _hal_port_pll_state_unlocked(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_pll_state_locked(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_pll_state_locking(void *vpfg, int eventMsk, int isNewState);
static int _check_pll_lock(struct hal_port_state *ps);
static halPortStateTable_t _fsmStateTable[] =
{
{
.state=HAL_PORT_PLL_STATE_UNLOCKED,
.stateName="UNLOCKED",
FSM_SET_FCT_NAME(_hal_port_pll_state_unlocked)
},
{
.state=HAL_PORT_PLL_STATE_LOCKING,
.stateName="LOCKING",
FSM_SET_FCT_NAME(_hal_port_pll_state_locking)
},
{
.state=HAL_PORT_PLL_STATE_LOCKED,
.stateName="LOCKED",
FSM_SET_FCT_NAME(_hal_port_pll_state_locked)
},
{.state=1}
};
static halPortEventTable_t _fsmEvtTable[] = {
{
.evtMask = HAL_PORT_PLL_EVENT_TIMER,
.evtName="TIMER"
},
{
.evtMask = HAL_PORT_PLL_EVENT_LOCK,
.evtName="LOCK"
},
{
.evtMask = HAL_PORT_PLL_EVENT_UNLOCKED,
.evtName="UNLOCKED"
},
{
.evtMask = HAL_PORT_PLL_EVENT_LOCKED,
.evtName="LOCKED"
},
{
.evtMask = HAL_PORT_PLL_EVENT_DISABLE,
.evtName="DISABLE"
},
{ .evtMask = -1 } };
static halPortFsmGen_t _portFsm = {
.fsm_name="PortFsmPll",
.fctBuilEvents=_buildEvents,
.pt=_fsmStateTable,
.pe=_fsmEvtTable
};
/* UNLOCKED state
*
* if locked event then
* state=LOCKED (should not happen )
* else
* if lock event then
* lock channel
* state=LOCKING
* fi
* fi
*
*/
static int _hal_port_pll_state_unlocked(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
if ( _isHalPllEventLocked(eventMsk) ) {
_fireState(vpfg,HAL_PORT_PLL_STATE_LOCKED);
return 0;
}
if ( _isHalPllEventLock(eventMsk) ) {
if ( rts_lock_channel(ps->hw_index, 0)>=0 ) {
_fireState(vpfg,HAL_PORT_PLL_STATE_LOCKING);
return 0;
}
}
return 0;
}
/*
* LOCKING state
*
* if locked event then state=LOCKED
* else if unlock event then state=UNLOCKED
*/
static int _hal_port_pll_state_locking(void *vpfg, int eventMsk, int isNewState) {
if ( _isHalPllEventLocked(eventMsk) ) {
_fireState(vpfg,HAL_PORT_PLL_STATE_LOCKED);
return 0;
}
if ( _isHalPllEventDisable(eventMsk) ) {
_fireState(vpfg,HAL_PORT_PLL_STATE_UNLOCKED);
return 0;
}
return 0;
}
/*
* LOCKED state
*
* if unlock event then
* state = LOCKING
* else if disabled event then state=UNLOCK
* else return final state machine reached
* fi
*/
static int _hal_port_pll_state_locked(void *vpfg, int eventMsk, int isNewState) {
if ( _isHalPllEventUnlock(eventMsk) ) {
_fireState(vpfg,HAL_PORT_PLL_STATE_LOCKING);
return 0;
}
if ( _isHalPllEventDisable(eventMsk) ) {
_fireState(vpfg,HAL_PORT_PLL_STATE_UNLOCKED);
return 0;
}
return 1; /* final state */
}
/*
* Build FSM events
*
* Lock & Locked events are generated only if the timing mode is BC
*/
static int _buildEvents(void * vpfg) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
int portEventMask=HAL_PORT_PLL_EVENT_TIMER;
int tm;
tm= hal_get_timing_mode();
ps->locked=0;
if ( tm == HAL_TIMING_MODE_BC) {
int locked=_check_pll_lock(ps);
if ( locked >=0 ) {
ps->locked = locked;
portEventMask|= locked ?
HAL_PORT_PLL_EVENT_LOCKED : HAL_PORT_PLL_EVENT_UNLOCKED;
}
if ( ps->evt_lock )
portEventMask |= HAL_PORT_PLL_EVENT_LOCK;
} else {
portEventMask |= HAL_PORT_PLL_EVENT_DISABLE;
}
ps->evt_lock=0;// Clear event
return portEventMask;
}
/* Init PLL FSM */
void hal_port_pll_init_fsm(struct hal_port_state * ps ) {
_portFsm.ps=ps;
_portFsm.st=&ps->pllStates;
ps->pllStates.state=-1;
_fireState(&_portFsm,HAL_PORT_PLL_STATE_UNLOCKED);
}
/* FSM state machine for TX setup on a given port
* Returned value:
* 1: when final state has been reached
* 0: when final state has not been reached
* -1: error detected
*/
int hal_port_pll_state_fsm( struct hal_port_state * ps ) {
_portFsm.ps=ps;
_portFsm.st=&ps->pllStates;
return hal_port_generic_fsm(&_portFsm);
}
extern struct rts_pll_state hal_port_rts_state;
extern int hal_port_rts_state_valid;
/* Returns 1 if the port is locked, 0 if unlocked, -1 in case of error */
static int _check_pll_lock(struct hal_port_state *ps)
{
struct rts_pll_state *hs = getRtsStatePtr();
if (!ps)
return -1;
if (!isRtsStateValid())
return -1;
if (hs->delock_count > 0)
return -1;
return ( hs->mode==RTS_MODE_BC &&
hs->current_ref == ps->hw_index &&
(hs->flags & RTS_DMTD_LOCKED) &&
(hs->flags & RTS_REF_LOCKED));
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_PLL_H
#define HAL_PORT_FSM_PLL_H
/* prototypes */
void hal_port_pll_init_fsm(struct hal_port_state * ps );
int hal_port_pll_state_fsm( struct hal_port_state * ps );
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_PLLP_H
#define HAL_PORT_FSM_PLLP_H
#include <libwr/wrs-msg.h>
#include "hal_port_gen_fsm.h"
#include "hal_port_fsm_pll.h"
typedef enum {
HAL_PORT_PLL_STATE_UNLOCKED=0,
HAL_PORT_PLL_STATE_LOCKING,
HAL_PORT_PLL_STATE_LOCKED
} halPortPllState_t;
typedef enum
{
HAL_PORT_PLL_EVENT_TIMER=(1<<0),
HAL_PORT_PLL_EVENT_UNLOCKED=(1<<1),
HAL_PORT_PLL_EVENT_LOCK=(1<<2),
HAL_PORT_PLL_EVENT_LOCKED=(1<<3),
HAL_PORT_PLL_EVENT_DISABLE=(1<<4),
}halPortPllEventMask_t ;
static __inline__ int _isHalPllEventLock(halPortPllEventMask_t eventMsk) {
return eventMsk & HAL_PORT_PLL_EVENT_LOCK;
}
static __inline__ int _isHalPllEventLocked(halPortPllEventMask_t eventMsk) {
return eventMsk & HAL_PORT_PLL_EVENT_LOCKED;
}
static __inline__ int _isHalPllEventUnlock(halPortPllEventMask_t eventMsk) {
return eventMsk & HAL_PORT_PLL_EVENT_UNLOCKED;
}
static __inline__ int _isHalPllEventDisable(halPortPllEventMask_t eventMsk) {
return eventMsk & HAL_PORT_PLL_EVENT_DISABLE;
}
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdint.h>
#include <libwr/wrs-msg.h>
#include <libwr/hal_shmem.h>
#include <hal_exports.h>
#include "driver_stuff.h"
#include "hal_ports.h"
#include "hal_port_leds.h"
#include "hal_port_fsm_rxP.h"
/**
* State machine
* States :
* - HAL_PORT_RX_SETUP_STATE_START:
* Inital state
* - HAL_PORT_RX_SETUP_STATE_CALIB_NO_LPDC :
* Calibration when LPDC is not supported
* - HAL_PORT_RX_SETUP_STATE_DONE:
* RX setup terminated
* Events :
* - timer : triggered regularly to execute background work
* - linkUp : A link up has been detected (driver ioctl)
* - Link down : Port is going down
*/
/* external prototypes */
static int _buildEvents(void * vpfg);
static int _hal_port_rx_setup_state_start(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_rx_setup_state_calib_no_lpdc(void *vpfg, int ventMsk, int isNewState);
static int _hal_port_rx_setup_state_done(void *vpfg, int ventMsk, int isNewState);
static uint32_t _pcs_readl(struct hal_port_state * ps, int reg);
static halPortStateTable_t _fsmStateTable[] =
{
{ .state=HAL_PORT_RX_SETUP_STATE_START,
.stateName="START",
FSM_SET_FCT_NAME(_hal_port_rx_setup_state_start)
},
{ .state=HAL_PORT_RX_SETUP_STATE_CALIB_NO_LPDC,
.stateName="CALIB_NO_LPDC",
FSM_SET_FCT_NAME(_hal_port_rx_setup_state_calib_no_lpdc)
},
{ .state=HAL_PORT_RX_SETUP_STATE_DONE,
.stateName="DONE",
FSM_SET_FCT_NAME(_hal_port_rx_setup_state_done)
},
{.state=1}
};
static halPortEventTable_t _fsmEvtTable[] = {
{
.evtMask = HAL_PORT_RX_SETUP_EVENT_TIMER,
.evtName="TIMER"
},
{
.evtMask = HAL_PORT_RX_SETUP_EVENT_LINK_UP,
.evtName="LINK_UP"
},
{
.evtMask = HAL_PORT_RX_SETUP_EVENT_LINK_DOWN,
.evtName="LINK_DOWN"
},
{ .evtMask = -1 } };
static halPortFsmGen_t _portFsm = {
.fsm_name="PortFsmRxSetup",
.fctBuilEvents=_buildEvents,
.pt=_fsmStateTable,
.pe=_fsmEvtTable
};
/* START state
* (Hypothesis: LPDC support has already been determined before )
*
* if link up event then
* if LPDC is not supported then state = CALIB_NO_LPDC
* else state = DONE
* fi
*/
static int _hal_port_rx_setup_state_start(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
if ( _isHalRxSetupEventLinkUp(eventMsk) ) {
_fireState(vpfg,ps->lpdc.isSupported ?
HAL_PORT_RX_SETUP_STATE_DONE : // Not yet implemented
HAL_PORT_RX_SETUP_STATE_CALIB_NO_LPDC);
}
return 0;
}
/* CALIB_NO_LPDC state
*
* if link down event then state = START
* if link up state then
* Calculate the bit slide.
* if bit slide successfully calculated then state=DONE
* fi
*/
static int _hal_port_rx_setup_state_calib_no_lpdc(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
int32_t bit_slide_steps=(_pcs_readl(ps, 16) >> 4) & 0x1f;
if ( _isHalRxSetupEventLinkDown(eventMsk) ) {
_fireState(vpfg,HAL_PORT_RX_SETUP_STATE_START);
return 0;
}
if ( _isHalRxSetupEventLinkUp(eventMsk) ) {
if ( bit_slide_steps !=-1 ) {
ps->calib.tx_calibrated = 1;
ps->calib.rx_calibrated = 1;
/* FIXME: use proper register names */
ps->calib.bitslide_ps=(uint32_t)bit_slide_steps*(uint32_t)800; /* 1 step = 800ps */
pr_info("%s:%s: bitslide= %d\n",__func__,ps->name,bit_slide_steps);
ps->calib.delta_rx_phy = ps->calib.phy_rx_min;
ps->calib.delta_tx_phy = ps->calib.phy_tx_min;
ps->tx_cal_pending = 0;
ps->rx_cal_pending = 0;
_fireState(vpfg,HAL_PORT_RX_SETUP_STATE_DONE);
}
}
return 0;
}
/*
* DONE state
*
* if link down event then state=START
* if link up event then return final state machine reached
*
*/
static int _hal_port_rx_setup_state_done(void *vpfg, int eventMsk, int isNewState) {
if ( _isHalRxSetupEventLinkDown(eventMsk) ) {
_fireState(vpfg,HAL_PORT_RX_SETUP_STATE_START);
return 0;
}
if ( _isHalRxSetupEventLinkUp(eventMsk) ) {
return 1; /* Final state reached */;
}
return 0;
}
/* Build FSM events */
static int _buildEvents(void *vpfg) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
int portEventMask=HAL_PORT_RX_SETUP_EVENT_TIMER;
if ( ps->evt_linkUp != -1 ) {
portEventMask |= ps->evt_linkUp ?
HAL_PORT_RX_SETUP_EVENT_LINK_UP : HAL_PORT_RX_SETUP_EVENT_LINK_DOWN;
}
return portEventMask;
}
/*
* Init RX SETUP FSM
*/
void hal_port_rx_setup_init_fsm(struct hal_port_state * ps ) {
_portFsm.ps=ps;
_portFsm.st=&ps->lpdc.rxSetupStates;
ps->lpdc.rxSetupStates.state=-1;
_fireState(&_portFsm,HAL_PORT_RX_SETUP_STATE_START);
}
/* FSM state machine for RX setup on a given port
* Returned value:
* 1: when final state has been reached
* 0: when final state has not been reached
* -1: error detected
*/
int hal_port_rx_setup_state_fsm( struct hal_port_state * ps ) {
_portFsm.ps=ps;
_portFsm.st=&ps->lpdc.rxSetupStates;
return hal_port_generic_fsm(&_portFsm);
}
static uint32_t _pcs_readl(struct hal_port_state * p, int reg)
{
struct ifreq ifr;
uint32_t rv;
strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
rv = NIC_READ_PHY_CMD(reg);
ifr.ifr_data = (void *)&rv;
if (ioctl(halPorts.hal_port_fd, PRIV_IOCPHYREG, &ifr) < 0) {
pr_error("%s: ioctl error: Cannot read bitslide \n",__func__);
return -1;
}
return NIC_RESULT_DATA(rv);
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_RX_H
#define HAL_PORT_FSM_RX_H
/* prototypes */
void hal_port_rx_setup_init_fsm(struct hal_port_state * ps );
int hal_port_rx_setup_state_fsm( struct hal_port_state * ps );
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_RXP_H
#define HAL_PORT_FSM_RXP_H
#include <libwr/wrs-msg.h>
#include "hal_port_gen_fsm.h"
typedef enum {
HAL_PORT_RX_SETUP_STATE_START=0,
HAL_PORT_RX_SETUP_STATE_CALIB_NO_LPDC,
HAL_PORT_RX_SETUP_STATE_DONE
} hapPortRxSetupState_t;
typedef enum
{
HAL_PORT_RX_SETUP_EVENT_TIMER=(1<<0),
HAL_PORT_RX_SETUP_EVENT_LINK_UP=(1<<1),
HAL_PORT_RX_SETUP_EVENT_LINK_DOWN=(1<<2)
}halPortRxSetupEventMask_t ;
static __inline__ int _isHalRxSetupEventTimer(halPortRxSetupEventMask_t eventMsk) {
return eventMsk & HAL_PORT_RX_SETUP_EVENT_TIMER;
}
static __inline__ int _isHalRxSetupEventLinkDown(halPortRxSetupEventMask_t eventMsk) {
return eventMsk & HAL_PORT_RX_SETUP_EVENT_LINK_DOWN;
}
static __inline__ int _isHalRxSetupEventLinkUp(halPortRxSetupEventMask_t eventMsk) {
return eventMsk & HAL_PORT_RX_SETUP_EVENT_LINK_UP;
}
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#include <hal_exports.h>
#include <libwr/hal_shmem.h>
#include "hal_port_gen_fsm.h"
#include "hal_port_fsm_txP.h"
/**
* State machine
* States :
* - HAL_PORT_TX_SETUP_STATE_START:
* Inital state
* - HAL_PORT_TX_SETUP_STATE_DONE:
* TX setup terminated
* Events :
* - timer : triggered regularly to execute background work
*/
/* external prototypes */
static int _buildEvents(void * vpfg);
static int _hal_port_tx_setup_state_start(void *vpfg, int eventMsk, int isNewState);
static int _hal_port_tx_setup_state_done(void *vpfg, int eventMsk, int isNewState);
static halPortStateTable_t _fsmStateTable[] =
{
{ .state=HAL_PORT_TX_SETUP_STATE_START,
.stateName="START",
FSM_SET_FCT_NAME(_hal_port_tx_setup_state_start)
},
{ .state=HAL_PORT_TX_SETUP_STATE_DONE,
.stateName="DONE",
FSM_SET_FCT_NAME(_hal_port_tx_setup_state_done)
},
{.state=1}
};
static halPortEventTable_t _fsmEvtTable[] = {
{
.evtMask = HAL_PORT_TX_SETUP_EVENT_TIMER,
.evtName="TIMER"
},
{ .evtMask = -1 } };
static halPortFsmGen_t _portFsm = {
.fsm_name="PortFsmTxSetup",
.fctBuilEvents=_buildEvents,
.pt=_fsmStateTable,
.pe=_fsmEvtTable
};
/*
* START state
*
* If entering in state then
* Set LPDC supported accordingly to the hardware
* fi
* if LPDC is not supported then state=DONE
*
*/
static int _hal_port_tx_setup_state_start(void *vpfg, int eventMsk, int isNewState) {
struct hal_port_state * ps=((halPortFsmGen_t *)vpfg)->ps;
if ( isNewState ) {
ps->lpdc.isSupported=0; // Not yet supported
}
if ( !ps->lpdc.isSupported ) {
// NO LPDC support
_fireState(vpfg,HAL_PORT_TX_SETUP_STATE_DONE);
return 0;
}
return 0;
}
/*
* DONE state
*
* Return final state machine reached
*/
static int _hal_port_tx_setup_state_done(void *vpfg, int eventMsk, int isNewState) {
return 1; /* Final state reached */
}
/* Build events mask */
static int _buildEvents(void *vpfg) {
return HAL_PORT_TX_SETUP_EVENT_TIMER;
}
/* Init the TX SETUP FSM on a given port */
void hal_port_tx_setup_init_fsm(struct hal_port_state * ps ) {
_portFsm.ps=ps;
_portFsm.st=&ps->lpdc.txSetupStates;
ps->lpdc.txSetupStates.state=-1;
_fireState(&_portFsm,HAL_PORT_TX_SETUP_STATE_START);
}
/* FSM state machine for TX setup on a given port
* Returned value:
* 1: when final state has been reached
* 0: when final state has not been reached
* -1: error detected
*/
int hal_port_tx_setup_state_fsm( struct hal_port_state * ps ) {
_portFsm.ps=ps;
_portFsm.st=&ps->lpdc.txSetupStates;
return hal_port_generic_fsm(&_portFsm);
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_TX_H
#define HAL_PORT_FSM_TX_H
/* prototypes */
void hal_port_tx_setup_init_fsm(struct hal_port_state * ps );
int hal_port_tx_setup_state_fsm( struct hal_port_state * ps );
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_FSM_TXP_H
#define HAL_PORT_FSM_TXP_H
#include <libwr/wrs-msg.h>
#include "hal_port_gen_fsm.h"
typedef enum {
HAL_PORT_TX_SETUP_STATE_START=0,
HAL_PORT_TX_SETUP_STATE_DONE
} hapPortTxSetupState_t;
typedef enum
{
HAL_PORT_TX_SETUP_EVENT_TIMER=(1<<0),
}halPortTxSetupEventMask_t ;
static __inline__ int _isHalTxSetupEventTimer(halPortTxSetupEventMask_t eventMsk) {
return eventMsk & HAL_PORT_TX_SETUP_EVENT_TIMER;
}
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*/
#include "hal_port_gen_fsm.h"
static char * _generic_build_events( halPortFsmGen_t *pfg, int *portEventMask);
/* Generic engine used by all ports states machine */
int hal_port_generic_fsm( halPortFsmGen_t *pfg) {
int ret=0;
if ( pfg->ps->in_use ) {
int portEventMask,isNewState;
char *evtStr=_generic_build_events(pfg, &portEventMask);
/* Check if state has changed */
if ( (isNewState=_isPendingState(pfg))==1 ) {
_consumeState(pfg);
}
/* Call state entry */
if (portEventMask || isNewState) {
halPortStateTable_t *pt=pfg->pt;
while (pt->state!=-1 ) {
if (pt->state==_getState(pfg) ) {
if ( FSM_GEN_DEBUG && pt->fctName!=NULL)
printf("%s.%s: Calling %s (newState=%d, evts=%s),\n",
pfg->ps->name,pfg->fsm_name,
pt->fctName, isNewState,evtStr);
ret=(*pt->fct)(pfg,portEventMask,isNewState);
if ( _isPendingState(pfg) ) {
/* Consume state immediately */
return hal_port_generic_fsm(pfg);
}
break;
}
pt++;
}
}
}
return ret;
}
static char * _generic_build_events( halPortFsmGen_t *pfg, int *portEventMask) {
*portEventMask=0;
if ( pfg->fctBuilEvents )
*portEventMask=(*pfg->fctBuilEvents)(pfg);
if ( FSM_GEN_DEBUG ) {
static char str[128];
int copy=*portEventMask;
halPortEventTable_t *pe=pfg->pe;
str[0]=0;
while (pe->evtMask!=-1 ) {
if (copy==0) break;
if ( (pe->evtMask & copy) !=0 ) {
if ( str[0]!=0)
strcat(str,"+");
strcat(str,pe->evtName);
copy &=~pe->evtMask;
}
pe++;
}
return str;
} else {
static char str[1]="";
return str;
}
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_GEN_FSM_H
#define HAL_PORT_GEN_FSM_H
#include <libwr/wrs-msg.h>
#include <libwr/hal_shmem.h>
#define FSM_GEN_DEBUG 1
#define FSM_SET_FCT_NAME(name) .fct=name, .fctName=#name
/*
* Used to define the callback to call for a givent state
*/
typedef struct {
int state;
char * stateName;
int (*fct)(void * vpfg/* struct halPortFsmGen_t *pfg*/, int eventMsk, int newState);
char *fctName;
}halPortStateTable_t;
typedef struct {
int evtMask;
char * evtName;
}halPortEventTable_t;
/*
* Structure containing all information needed by the state machine
*/
typedef struct {
char * fsm_name;
int (*fctBuilEvents)(void * vpfg/* struct halPortFsmGen_t *pfg*/);
halPortStateTable_t *pt;
halPortEventTable_t *pe;
struct hal_port_state *ps;
halPortFsmState_t *st;
}halPortFsmGen_t;
extern halPortFsmGen_t *pfg;
static __inline__ int _getState(halPortFsmGen_t *pfg) {
return pfg->st->state;
}
static __inline__ int _setState(halPortFsmGen_t *pfg, int newState) {
return pfg->st->state=newState;
}
static __inline__ int _getNextState(halPortFsmGen_t *pfg) {
return pfg->st->nextState;
}
static __inline__ char * _getStateName(halPortFsmGen_t *pfg) {
halPortStateTable_t *pt=pfg->pt+_getState(pfg);
return pt->stateName;
}
static __inline__ void _consumeState(halPortFsmGen_t *pfg) {
pfg->st->state=_getNextState(pfg);
if (FSM_GEN_DEBUG)
printf("%s.%s: Enter state %s\n",pfg->ps->name,pfg->fsm_name,_getStateName(pfg));
}
static __inline__ void _fireState(halPortFsmGen_t *pfg, int newState) {
pfg->st->nextState=newState;
}
static __inline__ int _isPendingState(halPortFsmGen_t *pfg) {
return _getState(pfg) != _getNextState(pfg);
}
/* prototypes */
int hal_port_generic_fsm( halPortFsmGen_t *pfg);
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#include <hal_exports.h>
#include <libwr/hal_shmem.h>
#include "hal_ports.h"
#include "hal_port_leds.h"
static struct Leds {
unsigned char sync_leds_map_to_update[HAL_MAX_PORTS];
unsigned char link_leds_map_to_update[HAL_MAX_PORTS];
unsigned char sync_leds_map[HAL_MAX_PORTS];
unsigned char link_leds_map[HAL_MAX_PORTS];
} _leds;
void led_init_all_ports(struct hal_port_state *ps ) {
int i;
// Clear data
memset(&_leds,0,sizeof(_leds));
for (i = 0; i < HAL_MAX_PORTS; i++) {
shw_sfp_set_led_synced(i, 0);
shw_sfp_set_generic(i, 0, SFP_LED_WRMODE1 | SFP_LED_WRMODE2);
}
}
/* to avoid i2c transfers to set the link LEDs, cache their state */
void led_set_wrmode(int portIndex, int value)
{
if (portIndex >= HAL_MAX_PORTS)
return;
_leds.link_leds_map_to_update[portIndex]=value;
}
void led_link_update(struct hal_port_state *ps) {
int i;
for (i = 0; i < HAL_MAX_PORTS; i++) {
unsigned char value=_leds.link_leds_map_to_update[i];
if ( value != _leds.link_leds_map[i]) {
_leds.link_leds_map[i]=value;
/* update the LED, don't forget to turn off LEDs if needed */
switch (value) {
case SFP_LED_WRMODE_SLAVE :
/* cannot set and clear LED in the same call! */
shw_sfp_set_generic(i, 1, SFP_LED_WRMODE1);
shw_sfp_set_generic(i, 0, SFP_LED_WRMODE2);
break;
case SFP_LED_WRMODE_OTHER :
/* cannot set and clear LED in the same call! */
shw_sfp_set_generic(i, 0, SFP_LED_WRMODE1);
shw_sfp_set_generic(i, 1, SFP_LED_WRMODE2);
break;
case SFP_LED_WRMODE_MASTER:
shw_sfp_set_generic(i, 1,SFP_LED_WRMODE1 | SFP_LED_WRMODE2);
break;
case SFP_LED_WRMODE_OFF :
shw_sfp_set_generic(i, 0,
SFP_LED_WRMODE1 | SFP_LED_WRMODE2);
break;
}
}
#if 0
if (port->in_use && state_up(port->state)) {
if (port->portMode == PORT_MODE_SLAVE)
set_led_wrmode(i, SFP_LED_WRMODE_SLAVE);
else if (port->portMode == PORT_MODE_MASTER)
set_led_wrmode(i, SFP_LED_WRMODE_MASTER);
else
set_led_wrmode(i, SFP_LED_WRMODE_OTHER);
}
port++;
#endif
}
}
/* to avoid i2c transfers to set the synced LEDs, cache their state */
void led_set_synched(int portIndex, int value)
{
if (portIndex >= HAL_MAX_PORTS)
return;
_leds.sync_leds_map[portIndex] = value;
}
void led_sync_update(struct hal_port_state *ps )
{
int i;
for (i = 0; i < HAL_MAX_PORTS; i++) {
#if 0
/* Check:
* --port in use
* --link is up
*/
if ( ps->in_use
&& state_up(ps->state) ) {
int ledValue;
ledValue= ps->synchronized
&& (ps->portInfoUpdated--) > -10
? 1 : 0;
set_led_synced(i, ledValue);
}
#else
unsigned char value=_leds.sync_leds_map_to_update[i];
if ( value != _leds.sync_leds_map[i]) {
// Update led
shw_sfp_set_led_synced(i, (int)value);
_leds.sync_leds_map[i] = value;
}
ps++;
#endif
}
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORT_LEDS_H
#define HAL_PORT_LEDS_H
/* Prototypes */
extern void led_init_all_ports(struct hal_port_state *ps );
extern void led_set_wrmode(int portIndex, int val);
extern void led_link_update(struct hal_port_state *port);
extern void led_set_synched(int portIndex, int val);
extern void led_sync_update(struct hal_port_state *port );
#endif
This diff is collapsed.
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*
*/
#ifndef HAL_PORTS_H
#define HAL_PORTS_H
#include <rt_ipc.h>
typedef struct {
struct hal_port_state *ports;
int numberOfPorts;
int hal_port_fd; /* An fd of always opened raw sockets for ioctl()-ing Ethernet devices */
/* RT subsystem PLL state, polled regularly via mini-ipc */
struct rts_pll_state rts_state;
int rts_state_valid;
}hal_ports_t;
#define isRtsStateValid() halPorts.rts_state_valid
#define setRtsStateValidity(value) halPorts.rts_state_valid=(value)
#define getRtsState() (halPorts.rts_state)
#define getRtsStatePtr() (&getRtsState())
extern hal_ports_t halPorts;
extern int hal_port_poll_rts_state(void);
extern int hal_port_poll_rts_state(void);
extern int hal_get_timing_mode(void);
extern int rts_lock_channel(int channel, int priority);
#endif
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*/
#include "hal_timer.h"
void timerInit(timer_parameter_t *p,int nbTimers) {
int index;
for ( index=0; index < nbTimers; index++ ) {
libwr_tmo_init(&p->timer,p->tmoMs, p->repeat);
p++;
}
}
void timerScan(timer_parameter_t *p,int nbTimers) {
int index;
for ( index=0; index < nbTimers; index++ ) {
if (libwr_tmo_expired(&p->timer) && p->cb!=NULL) {
(*p->cb)(p->id);
}
p++;
}
}
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Jean-Claude BAU - CERN
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*
*/
#ifndef HAL_TIMER_H
#define HAL_TIMER_H
#include <libwr/timeout.h>
typedef struct {
int id;
uint32_t tmoMs; // Time out value in ms
int repeat; // restart timeout automatically
timeout_t timer;
void (*cb)(int timerId);
}timer_parameter_t;
extern void timerInit(timer_parameter_t *p,int nbTimers);
extern void timerScan(timer_parameter_t *p,int nbTimers);
#endif
......@@ -11,12 +11,10 @@
#include <libwr/wrs-msg.h>
#include <libwr/timeout.h>
#include "wrsw_hal.h"
#include <rt_ipc.h>
#include <hal_exports.h>
#include "wrsw_hal.h"
#include "hal_ports.h"
extern struct rts_pll_state hal_port_rts_state;
extern int hal_port_rts_state_valid;
int hal_init_timing_mode(void)
{
......@@ -35,9 +33,9 @@ int hal_init_timing(char *filename)
int hal_get_timing_mode(void)
{
struct rts_pll_state *hs = &hal_port_rts_state;
struct rts_pll_state *hs = getRtsStatePtr();
if (hal_port_rts_state_valid)
if (isRtsStateValid())
switch (hs->mode) {
case RTS_MODE_GM_EXTERNAL:
return HAL_TIMING_MODE_GRAND_MASTER;
......@@ -51,8 +49,10 @@ int hal_get_timing_mode(void)
return -1;
}
int hal_update_timing_mode(void) {
return hal_port_poll_rts_state();
int hal_set_timing_mode(uint32_t tm) {
int ret=shw_pps_set_timing_mode(tm);
hal_port_poll_rts_state();
return ret;
}
......@@ -38,7 +38,7 @@ int hal_port_poll_rts_state(void);
int hal_init_timing_mode(void);
int hal_init_timing(char *filename);
int hal_get_timing_mode(void);
int hal_update_timing_mode(void);
int hal_set_timing_mode(uint32_t tm);
int hal_port_pshifter_busy(void);
#endif
<html>
<body>
<table border="0" cellspacing="0" cellpadding="0" align="LEFT">
<tr>
<td><img src="file:///opt/baujc/project/wr/wrs-proposed-master/wr-switch-sw-hal-review/userspace/wrsw_hal/yakindu/hal_0_0.png"/></td>
</tr>
</table>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
......@@ -108,7 +108,7 @@ static int rtu_create_static_entries(void)
for (i = 0; i < hal_nports_local; i++) {
enabled_port_mask |= (1 << hal_ports_local_copy[i].hw_index);
port_was_up[i] = state_up(hal_ports_local_copy[i].state);
port_was_up[i] = state_up(&hal_ports_local_copy[i]);
}
// VLAN-aware Bridge reserved addresses (802.1Q-2005 Table 8.1)
......@@ -180,7 +180,7 @@ static void rtu_update_ports_state(void)
if (!hal_ports_local_copy[i].in_use)
continue;
link_up = state_up(hal_ports_local_copy[i].state);
link_up = state_up(&hal_ports_local_copy[i]);
if (port_was_up[i] && !link_up) {
pr_info(
"Port %s went down, removing corresponding entries...\n",
......@@ -253,7 +253,7 @@ static int rtu_daemon_learning_process(void)
for (port_down = i = 0; i <= MAX_PORT; i++) {
p = &hal_ports_local_copy[i];
if (p->in_use && p->hw_index == req.port_id
&& !state_up(p->state)) {
&& !state_up(p)) {
port_down = 1;
pr_debug("port down %s\n", p->name);
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment