Commit 68aaa1be authored by Adam Wujek's avatar Adam Wujek 💬

Merge branch 'wrs_watchdog'

Add wrs_watchdog.
parents f43421ef f1e9c39e
......@@ -183,6 +183,15 @@ config WRS_LOG_MONIT
Please note that unknown facility names will generate a runtime error
on the switch.
config WRS_LOG_WRSWATCHDOG
string "Logging directions for the wrs_watchdog"
default "daemon.info"
help
The string can be a pathname (e.g. /dev/kmsg) or a <facility>.<level>
spefification like "daemon.debug". An empty strings is used
to represent no logging (like /dev/null). Please note that
unknown facility names will generate a runtime error on the switch.
config KEEP_ROOTFS
bool "Keep generated filesystem and related script"
help
......
......@@ -495,6 +495,7 @@ value is changed by the web interface, proper action is taken.
@item CONFIG_WRS_LOG_HAL
@itemx CONFIG_WRS_LOG_RTU
@itemx CONFIG_WRS_LOG_PTP
@itemx CONFIG_WRS_LOG_WRSWATCHDOG
Logging options for the three main WRS processes. Each value
can be a pathname, to select logging to file (and @t{/dev/kmsg}
......@@ -502,7 +503,7 @@ value is changed by the web interface, proper action is taken.
like @t{daemon.debug}, for syslog-based logging.
An empty strings selects no logging at all. Please note that
unknown facility names will generate a runtime error on the switch.
All three strings default to ``@t{daemon.info}''.
All four strings default to ``@t{daemon.info}''.
@item CONFIG_WRS_LOG_SNMPD
......
......@@ -20,7 +20,7 @@ WB_GEN10 = $(MODULES_WRS)/wrsw_rt_subsystem/wrsw_gen_10mhz.wb
WB_SOFTPLL = $(MODULES_WRC)/wr_softpll_ng/spll_wb_slave.wb
HEADERS = endpoint-regs.h endpoint-mdio.h ppsg-regs.h tstamp-regs.h rtu-regs.h \
nic-regs.h softpll-regs.h pstats-regs.h gen10mhz-regs.h
nic-regs.h softpll-regs.h pstats-regs.h gen10mhz-regs.h wdog-regs.h
WBINPUT = $(HEADERS:.h=wb)
# No default, for people who types "make" everywhere (like me)
......
/*
Register definitions for slave core: WR Watchdog module
* File : wdog-regs.h
* Author : auto-generated by wbgen2 from wdog-regs.wb
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wdog-regs.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_WDOG
#define __WBGEN2_REGDEFS_WDOG
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Restart counter */
/* definitions for register: Control Register */
/* definitions for field: Port select in reg: Control Register */
#define WDOG_CR_PORT_MASK WBGEN2_GEN_MASK(0, 8)
#define WDOG_CR_PORT_SHIFT 0
#define WDOG_CR_PORT_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define WDOG_CR_PORT_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for field: Force reset in reg: Control Register */
#define WDOG_CR_RST WBGEN2_GEN_MASK(31, 1)
/* definitions for register: Port FSM activity register */
/* definitions for register: Port FSM register */
/* definitions for field: IB alloc FSM state in reg: Port FSM register */
#define WDOG_FSM_IB_ALLOC_MASK WBGEN2_GEN_MASK(0, 4)
#define WDOG_FSM_IB_ALLOC_SHIFT 0
#define WDOG_FSM_IB_ALLOC_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define WDOG_FSM_IB_ALLOC_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: IB transfer FSM state in reg: Port FSM register */
#define WDOG_FSM_IB_TRANS_MASK WBGEN2_GEN_MASK(4, 4)
#define WDOG_FSM_IB_TRANS_SHIFT 4
#define WDOG_FSM_IB_TRANS_W(value) WBGEN2_GEN_WRITE(value, 4, 4)
#define WDOG_FSM_IB_TRANS_R(reg) WBGEN2_GEN_READ(reg, 4, 4)
/* definitions for field: IB receive FSM state in reg: Port FSM register */
#define WDOG_FSM_IB_RCV_MASK WBGEN2_GEN_MASK(8, 4)
#define WDOG_FSM_IB_RCV_SHIFT 8
#define WDOG_FSM_IB_RCV_W(value) WBGEN2_GEN_WRITE(value, 8, 4)
#define WDOG_FSM_IB_RCV_R(reg) WBGEN2_GEN_READ(reg, 8, 4)
/* definitions for field: IB LL FSM state in reg: Port FSM register */
#define WDOG_FSM_IB_LL_MASK WBGEN2_GEN_MASK(12, 4)
#define WDOG_FSM_IB_LL_SHIFT 12
#define WDOG_FSM_IB_LL_W(value) WBGEN2_GEN_WRITE(value, 12, 4)
#define WDOG_FSM_IB_LL_R(reg) WBGEN2_GEN_READ(reg, 12, 4)
/* definitions for field: OB prepare FSM state in reg: Port FSM register */
#define WDOG_FSM_OB_PREP_MASK WBGEN2_GEN_MASK(16, 4)
#define WDOG_FSM_OB_PREP_SHIFT 16
#define WDOG_FSM_OB_PREP_W(value) WBGEN2_GEN_WRITE(value, 16, 4)
#define WDOG_FSM_OB_PREP_R(reg) WBGEN2_GEN_READ(reg, 16, 4)
/* definitions for field: OB send FSM state in reg: Port FSM register */
#define WDOG_FSM_OB_SEND_MASK WBGEN2_GEN_MASK(20, 4)
#define WDOG_FSM_OB_SEND_SHIFT 20
#define WDOG_FSM_OB_SEND_W(value) WBGEN2_GEN_WRITE(value, 20, 4)
#define WDOG_FSM_OB_SEND_R(reg) WBGEN2_GEN_READ(reg, 20, 4)
/* definitions for field: FREE FSM state in reg: Port FSM register */
#define WDOG_FSM_FREE_MASK WBGEN2_GEN_MASK(24, 4)
#define WDOG_FSM_FREE_SHIFT 24
#define WDOG_FSM_FREE_W(value) WBGEN2_GEN_WRITE(value, 24, 4)
#define WDOG_FSM_FREE_R(reg) WBGEN2_GEN_READ(reg, 24, 4)
PACKED struct WDOG_WB {
/* [0x0]: REG Restart counter */
uint32_t RST_CNT;
/* [0x4]: REG Control Register */
uint32_t CR;
/* [0x8]: REG Port FSM activity register */
uint32_t ACT;
/* [0xc]: REG Port FSM register */
uint32_t FSM;
};
#endif
-- -*- Mode: LUA; tab-width: 2 -*-
-- White-Rabbit Watchdog Module
-- author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
--
-- Use wbgen2 to generate code, documentation and more.
-- wbgen2 is available at:
-- http://www.ohwr.org/projects/wishbone-gen
--
peripheral {
name = "WR Watchdog module";
description = "The module monitors the Switching Core and performs a reset when swcore is stuck";
hdl_entity = "wdog_wishbone_slave";
prefix = "wdog";
reg {
name = "Restart counter";
description = "Counts how many times watchdog had to restart the swcore";
prefix = "RST_CNT";
field {
name = "counter value";
size = 32;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
};
reg {
name = "Control Register";
prefix = "CR";
field {
name = "Port select";
prefix = "PORT";
size = 8;
type = SLV;
access_dev = READ_WRITE;
access_bus = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Force reset";
prefix = "RST";
size = 1;
align = 31;
type = MONOSTABLE;
access_dev = READ_ONLY;
access_bus = WRITE_ONLY;
};
};
reg {
name = "Port FSM activity register";
prefix = "ACT";
field {
name = "bit-per-fsm activity since the last readout";
size = 7;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
};
reg {
name = "Port FSM register";
prefix = "FSM";
field {
name = "IB alloc FSM state";
prefix = "IB_ALLOC";
size = 4;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
field {
name = "IB transfer FSM state";
prefix = "IB_TRANS";
size = 4;
align = 4;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
field {
name = "IB receive FSM state";
prefix = "IB_RCV";
size = 4;
align = 8;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
field {
name = "IB LL FSM state";
prefix = "IB_LL";
size = 4;
align = 12;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
field {
name = "OB prepare FSM state";
prefix = "OB_PREP";
size = 4;
align = 16;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
field {
name = "OB send FSM state";
prefix = "OB_SEND";
size = 4;
align = 20;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
field {
name = "FREE FSM state";
prefix = "FREE";
size = 4;
align = 24;
type = SLV;
access_dev = WRITE_ONLY;
access_bus = READ_ONLY;
};
};
};
......@@ -5,7 +5,8 @@ WRDEV_DIR ?= $(WRS_BASE_DIR)/..
# subdirectories we want to compile
SUBDIRS = libwr mini-rpc libsdb \
wrsw_hal wrsw_rtud tools snmpd
wrsw_hal wrsw_rtud tools snmpd \
wrs_watchdog
# all variables are exported
export
......
......@@ -32,6 +32,9 @@
/* HardWare Debugging Unit */
#define FPGA_BASE_HWDU 0x59000
/* Watchdog Module */
#define FPGA_BASE_WDOG 0x5A000
/* Endpoint */
#define FPGA_BASE_EP0 0x30000
......
#!/bin/sh
WDG_PID=/var/run/wrs_watchdog.pid
dotconfig=/wr/etc/dot-config
start_counter() {
# increase boot counter
COUNTER_FILE="/tmp/start_cnt_wrs_watchdog"
START_COUNTER=1
if [ -f "$COUNTER_FILE" ];
then
read -r START_COUNTER < $COUNTER_FILE
START_COUNTER=$((START_COUNTER+1))
fi
echo "$START_COUNTER" > $COUNTER_FILE
}
start() {
echo -n "Starting wrs_watchdog daemon: "
if [ -f $WDG_PID ] && kill -0 `cat $WDG_PID` &> /dev/null; then
# wrs_watchdog already running
echo "Failed (already running?)"
else
if [ -f $dotconfig ]; then
. $dotconfig
else
echo "$0 unable to source dot-config ($dotconfig)!"
fi
WRS_LOG=$CONFIG_WRS_LOG_WRSWATCHDOG
# if empty turn it to /dev/null
if [ -z $WRS_LOG ]; then
WRS_LOG="/dev/null";
fi
# if a pathname, use it
if echo "$WRS_LOG" | grep / > /dev/null; then
eval LOGPIPE=\" \> $WRS_LOG 2\>\&1 \";
else
# not a pathname: use verbatim
eval LOGPIPE=\" 2\>\&1 \| logger -t wr-switch -p $WRS_LOG\"
fi
eval /wr/bin/wrs_watchdog -d -p $WDG_PID $LOGPIPE \&
start_counter
echo "OK"
fi
}
stop() {
echo -n "Stopping wrs_watchdog "
start-stop-daemon -K -q -p $WDG_PID
if [ $? -eq 0 ]; then
echo "OK"
else
echo "Failed"
fi
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
;;
esac
check process wrs_watchdog with pidfile /var/run/wrs_watchdog.pid
start program = "/etc/init.d/wrs_watchdog.sh start"
stop program = "/etc/init.d/wrs_watchdog.sh stop"
if 5 restarts within 10 cycles then exec "/etc/init.d/reboot.sh wrs_watchdog"
../init.d/wrs_watchdog.sh
\ No newline at end of file
......@@ -703,6 +703,15 @@ wrsBootUserspaceDaemonsMissing OBJECT-TYPE
are reported as maximum number of missing modules"
::= { wrsBootStatusGroup 14 }
wrsGwWatchdogTimeouts OBJECT-TYPE
SYNTAX Counter32
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Number of times the watchdog has restarted the HDL module responsible
for the Ethernet switching process."
::= { wrsBootStatusGroup 15 }
-- wrsTemperatureGroup (.7.1.3)
wrsTemperatureGroup OBJECT IDENTIFIER ::= { wrsOperationStatus 3 }
......@@ -976,6 +985,14 @@ wrsStartCntSyslogd OBJECT-TYPE
"Nmber of SYSLOG daemon starts"
::= { wrsStartCntGroup 7 }
wrsStartCntWrsWatchdog OBJECT-TYPE
SYNTAX Counter32
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Nmber of wrs_watchdog daemon starts"
::= { wrsStartCntGroup 8 }
-- wrsSpllState (.7.3)
wrsSpllState OBJECT IDENTIFIER ::= { wrsExpertStatus 3 }
......
......@@ -18,6 +18,9 @@
/* get process list, output only process' command */
#define PROCESS_COMMAND "/bin/ps axo command"
/* get number of GW watchdog timeouts */
#define WDOG_COMMAND "/wr/bin/wrs_watchdog -g"
/* Macros for fscanf function to read line with maximum of "x" characters
* without new line. Macro expands to something like: "%10[^\n]" */
#define LINE_READ_LEN_HELPER(x) "%"#x"[^\n]"
......@@ -42,6 +45,7 @@ static struct pickinfo wrsBootStatus_pickinfo[] = {
FIELD(wrsBootStatus_s, ASN_INTEGER, wrsBootLoadLM32),
FIELD(wrsBootStatus_s, ASN_INTEGER, wrsBootKernelModulesMissing),
FIELD(wrsBootStatus_s, ASN_INTEGER, wrsBootUserspaceDaemonsMissing),
FIELD(wrsBootStatus_s, ASN_COUNTER, wrsGwWatchdogTimeouts),
};
struct wrsBootStatus_s wrsBootStatus_s;
......@@ -456,6 +460,26 @@ static void get_daemons_status(void)
pclose(f);
}
static void get_n_watchdog_timouts(void)
{
FILE *f;
wrsBootStatus_s.wrsGwWatchdogTimeouts = 0;
f = popen(WDOG_COMMAND, "r");
if (!f) {
snmp_log(LOG_ERR, "SNMP: wrsBootStatusGroup failed to execute "
WDOG_COMMAND"\n");
return;
}
/* Number of watchdog restarts is returned as a int value,
* if error there nothing we can do */
fscanf(f, "%d", &wrsBootStatus_s.wrsGwWatchdogTimeouts);
pclose(f);
}
time_t wrsBootStatus_data_fill(void)
{
static time_t time_update;
......@@ -483,6 +507,9 @@ time_t wrsBootStatus_data_fill(void)
/* get info about running daemons */
get_daemons_status();
/* get info about number of gateware watchdog timeouts */
get_n_watchdog_timouts();
/* there was an update, return current time */
return time_update;
}
......
......@@ -53,6 +53,7 @@ struct wrsBootStatus_s {
int32_t wrsBootLoadLM32;
int32_t wrsBootKernelModulesMissing;
int32_t wrsBootUserspaceDaemonsMissing;
int32_t wrsGwWatchdogTimeouts;
};
extern struct wrsBootStatus_s wrsBootStatus_s;
......
......@@ -6,6 +6,7 @@
#define START_CNT_HTTPD "/tmp/start_cnt_httpd"
#define START_CNT_SNMPD "/tmp/start_cnt_snmpd"
#define START_CNT_SYSLOGD "/tmp/start_cnt_syslogd"
#define START_CNT_WRSWATCHDOG "/tmp/start_cnt_wrs_watchdog"
static struct pickinfo wrsStartCnt_pickinfo[] = {
FIELD(wrsStartCnt_s, ASN_COUNTER, wrsStartCntHAL),
......@@ -15,6 +16,7 @@ static struct pickinfo wrsStartCnt_pickinfo[] = {
FIELD(wrsStartCnt_s, ASN_COUNTER, wrsStartCntHttpd),
FIELD(wrsStartCnt_s, ASN_COUNTER, wrsStartCntSnmpd),
FIELD(wrsStartCnt_s, ASN_COUNTER, wrsStartCntSyslogd),
FIELD(wrsStartCnt_s, ASN_COUNTER, wrsStartCntWrsWatchdog),
};
struct wrsStartCnt_s wrsStartCnt_s;
......@@ -59,6 +61,7 @@ time_t wrsStartCnt_data_fill(void){
read_start_count(START_CNT_HTTPD, &wrsStartCnt_s.wrsStartCntHttpd);
read_start_count(START_CNT_SNMPD, &wrsStartCnt_s.wrsStartCntSnmpd);
read_start_count(START_CNT_SYSLOGD, &wrsStartCnt_s.wrsStartCntSyslogd);
read_start_count(START_CNT_WRSWATCHDOG, &wrsStartCnt_s.wrsStartCntWrsWatchdog);
/* there was an update, return current time */
return time_update;
......
......@@ -12,6 +12,7 @@ struct wrsStartCnt_s {
uint32_t wrsStartCntHttpd;
uint32_t wrsStartCntSnmpd;
uint32_t wrsStartCntSyslogd;
uint32_t wrsStartCntWrsWatchdog;
};
extern struct wrsStartCnt_s wrsStartCnt_s;
......
OBJS = wrs_watchdog.o
BINARY = wrs_watchdog
WR_INSTALL_ROOT ?= /usr/lib/white-rabbit
# # Standard stanza for cross-compilation (courtesy of the linux makefile)
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
CFLAGS = -O -g -Wall \
-I../include \
-I../libwr/include \
-I../mini-rpc \
-I$(LINUX)/arch/arm/mach-at91/include
GIT_VER = $(shell git describe --always --dirty | sed 's;^wr-switch-sw-;;')
CFLAGS += -D__GIT_VER__="\"${GIT_VER}\""
LDFLAGS = -L../libwr -L../mini-rpc \
-lm -ldl -lwr -lminipc
all: $(BINARY)
$(BINARY): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
install: all
install -d $(WR_INSTALL_ROOT)/bin
install $(BINARY) $(WR_INSTALL_ROOT)/bin
clean:
rm -f $(BINARY) *.o *~
/*
* Copyright (c) 2015, CERN
*
* Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <getopt.h>
#include <inttypes.h>
#include <stddef.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <libwr/switch_hw.h>
#include <libwr/wrs-msg.h>
#include <fpga_io.h>
#include <regs/wdog-regs.h>
#include "wrs_watchdog.h"
#include <libwr/shmem.h>
#include <libwr/hal_shmem.h>
#define RST_THR 2
#define wdog_write(reg, val) \
_fpga_writel(FPGA_BASE_WDOG + offsetof(struct WDOG_WB, reg), val)
#define wdog_read(reg) \
_fpga_readl(FPGA_BASE_WDOG + offsetof(struct WDOG_WB, reg))
static char *prgname;
int daemon_mode;
int list_mode;
int port_num = 0;
int get_nports_from_hal(void)
{
struct hal_shmem_header *h;
struct wrs_shm_head *hal_head;
int hal_nports_local; /* local copy of number of ports */
int ii;
int n_wait = 0;
/* wait forever for HAL */
while (!(hal_head = wrs_shm_get(wrs_shm_hal, "",
WRS_SHM_READ | WRS_SHM_LOCKED))) {
if (n_wait > 5) {
/* print if waiting more than 5 seconds, some waiting
* is expected since hal requires few seconds to start
*/
pr_error("unable to open shm for HAL!\n");
}
n_wait++;
sleep(1);
}
h = (void *)hal_head + hal_head->data_off;
n_wait = 0;
while (1) { /* wait forever for HAL to produce consistent nports */
ii = wrs_shm_seqbegin(hal_head);
/* Assume number of ports does not change in runtime */
hal_nports_local = h->nports;
if (!wrs_shm_seqretry(hal_head, ii))
break;
if (n_wait > 5) {
/* print if waiting more than 5 seconds, some waiting
* is expected since hal requires few seconds to start
*/
pr_error("Wait for HAL.\n");
}
n_wait++;
sleep(1);
}
/* check hal's shm version */
if (hal_head->version != HAL_SHMEM_VERSION) {
pr_error("unknown hal's shm version %i (known is %i)\n",
hal_head->version, HAL_SHMEM_VERSION);
exit(-1);
}
if (hal_nports_local > HAL_MAX_PORTS) {
pr_error("Too many ports reported by HAL. %d vs %d "
"supported\n", hal_nports_local, HAL_MAX_PORTS);
exit(-1);
}
return hal_nports_local;
}
uint32_t show_counter(void)
{
uint32_t val;
val = wdog_read(RST_CNT);
printf("%u\n", val);
return val;
}
void force_rst(void)
{
wdog_write(CR, WDOG_CR_RST);
}
struct swc_fsms read_port(int port)
{
int i;
struct swc_fsms fsms;
uint32_t val_fsm, val_act;
wdog_write(CR, WDOG_CR_PORT_W(port));
val_fsm = wdog_read(FSM);
val_act = wdog_read(ACT);
/* parsing results */
fsms.state[0] = WDOG_FSM_IB_ALLOC_R(val_fsm);
fsms.state[1] = WDOG_FSM_IB_TRANS_R(val_fsm);
fsms.state[2] = WDOG_FSM_IB_RCV_R(val_fsm);
fsms.state[3] = WDOG_FSM_IB_LL_R(val_fsm);
fsms.state[4] = WDOG_FSM_OB_PREP_R(val_fsm);
fsms.state[5] = WDOG_FSM_OB_SEND_R(val_fsm);
fsms.state[6] = WDOG_FSM_FREE_R(val_fsm);
for (i = 0; i < FSMS_NO; ++i) {
fsms.act[i] = (val_act & (1<<i)) >> i;
}
return fsms;
}
void list_fsms(void)
{
int i;
struct swc_fsms fsms;
for (i = 0; i <= port_num; ++i) {
/* yes, it is i<=port_num because we're reading FSMs for all WR
* ports + NIC */
fsms = read_port(i);
printf("PORT %2d: ", i);
printf("ib_alloc(%d): %-14s",
fsms.act[ALLOC_IDX], alloc_states[fsms.state[ALLOC_IDX]]);
printf("ib_trans(%d): %-15s",
fsms.act[TRANS_IDX], trans_states[fsms.state[TRANS_IDX]]);
printf("ib_rcv(%d): %-12s",
fsms.act[RCV_IDX], rcv_states[fsms.state[RCV_IDX]]);
printf("ib_ll(%d): %-17s",
fsms.act[LL_IDX], ll_states[fsms.state[LL_IDX]]);
printf("ob_prep(%d): %-18s",
fsms.act[PREP_IDX], prep_states[fsms.state[PREP_IDX]]);
printf("ob_send(%d): %-14s",
fsms.act[SEND_IDX], send_states[fsms.state[SEND_IDX]]);
printf("free(%d): %s\n",
fsms.act[FREE_IDX], free_states[fsms.state[FREE_IDX]]);
}
}
int update_stuck(struct swc_fsms *fsms, int *stuck_cnt)
{
int fsm_it;
for (fsm_it = 0; fsm_it < FSMS_NO; ++fsm_it) {
if (fsms->state[fsm_it] != idles[fsm_it] &&
fsms->act[fsm_it] == 0) {
stuck_cnt[fsm_it]++;
} else {
stuck_cnt[fsm_it] = 0;
}
/* and we also check if reset is needed */
if (stuck_cnt[fsm_it] >= RST_THR) {
return 1;
}
}
return 0;
}
void clear_stuck(int cnt[][FSMS_NO])
{
int port_it, fsm_it;
for (port_it = 0; port_it <= port_num; ++port_it) {
for (fsm_it = 0; fsm_it < FSMS_NO; ++fsm_it) {
cnt[port_it][fsm_it] = 0;
}
}
}
void write_pidfile(char *file, pid_t pid)
{
FILE *f;
if (file == NULL)
return;
f = fopen(file, "w");
if (f == NULL) {
pr_error("Could not create PID file\n");
return;
}
fprintf(f, "%d\n", (int)pid);
fclose(f);
}
void endless_watchdog(void)
{
struct swc_fsms fsms[19];
int stuck_cnt[19][FSMS_NO] = { {0} };
int port_it;
int rst = 0;
while (1) {
/* first we read all the ports */
for (port_it = 0; port_it <= port_num; ++port_it) {
fsms[port_it] = read_port(port_it);
rst = update_stuck(&(fsms[port_it]), stuck_cnt[port_it]);
if (rst)
break;
}
/* handle reset if needed */
if (rst) {
pr_warning("SWCore stuck... resetting\n");
force_rst();
clear_stuck(stuck_cnt);
}
sleep(1);
}
}
void print_help(char *prgname)
{
printf("wrs_watchdog. Commit %s, built on " __DATE__ "\n",
__GIT_VER__);
printf("usage: %s <options>\n", prgname);
printf(" -d Run as daemon\n"
" -l List FSMs state for all ports\n"
" -n <8/18> Set the number of ports\n"
" -g Show current value of the restart counter\n"
" -r Force restart of the Swcore\n"
" -h Show this help message\n");
}
int main(int argc, char *argv[])
{
int c = 0;
char *pidfile = NULL;
prgname = argv[0];
if (argc == 1) {
print_help(prgname);
return 0;
}
wrs_msg_init(argc, argv);
if (shw_fpga_mmap_init() < 0) {
pr_error("%s: Can't access device memory\n", prgname);
exit(1);
}
while ((c = getopt(argc, argv, "dhrgqvn:lp:")) != -1) {
switch (c) {
case 'd':
daemon_mode = 1;
break;
case 'l':
list_mode = 1;
break;
case 'r':
force_rst();
break;
case 'g':
show_counter();
break;
case 'n':
port_num = atoi(optarg);
pr_info("Read %d ports from cmdline\n", port_num);
break;
case 'p':
pidfile = optarg;
break;
case 'q': break; /* done in wrs_msg_init() */
case 'v': break; /* done in wrs_msg_init() */
case 'h':
default:
print_help(prgname);
exit(1);
}
}
if (!port_num) {
/* if port_num not read from parameter read it from HAL */
port_num = get_nports_from_hal();
pr_info("Read %d ports from HAL\n", port_num);
}
if (!daemon_mode && list_mode) {
list_fsms();
}
if (daemon_mode) {
wrs_msg(LOG_ALERT, "wrs_watchdog. Commit %s, built on "
__DATE__ "\n", __GIT_VER__);
write_pidfile(pidfile, getpid());
pr_info("Demonize\n");
endless_watchdog();
}
return 0;
}
#ifndef __WRS_WATCHDOG__
#define __WRS_WATCHDOG__
static const char * const alloc_states[] = {
"IDLE",
"START_SETUCNT",
"START_PGE_REQ",
"INTER_PGE_REQ",
"START_SET&REQ",
"Unknown"};
static const char * const trans_states[] = {
"IDLE",
"READY",
"WAIT_RTU_V",
"WAIT_SOF",
"SET_USECNT",
"WAIT_W_TRANSFER",
"TOO_LONG_TR",
"TRANSFER",
"TRANSFERRED",
"DROP",
"Unknown"};
static const char * const rcv_states[] = {
"IDLE",
"READY",
"PAUSE",
"RCV_DATA",
"DROP",
"WAIT_F_FREE",
"INPUT_STUCK",
"Unknown"};
static const char * const ll_states[] = {
"IDLE",
"RDY_PGR_&_DLAST",
"RDY_DLAST_ONLY",
"WRITE",
"EOF_ON_WR",
"SOF_ON_WR",
"Unknown"};
static const char * const prep_states[] = {
"RETRY_RDY",
"NEWPCK_PG_RDY",
"NEWPCK_PG_SET_ADV",
"NEWPCK_PG_USED",
"RETRY_PREPARE",
"IDLE",
"Unknown",
"cycle frozen"};
static const char * const send_states[] = {
"IDLE",
"DATA",
"FLUSH_STALL",
"FINISH_CYCLE",
"EOF",
"RETRY",
"WAIT_FREE_PCK",
"Unknown"};
static const char * const free_states[] = {
"IDLE",
"REQ_RD_FIFO",
"RD_FIFO",
"RD_NEXT_PG_ADR",
"FREE_CUR_PG_ADR",
"F_FREE_CUR_PG_ADR",
"Unknown"};
static const char idles[] = {
0, /*alloc: s_idle */
1, /* trans: s_ready */
1, /* rcv: s_ready */
1, /* ll: s_ready_for_pgr_and_dlast */
5, /* prep: s_idle */
0, /* send: s_idle */
0 /* free: s_idle */
};
#define FSMS_NO 7
#define ALLOC_IDX 0
#define TRANS_IDX 1
#define RCV_IDX 2
#define LL_IDX 3
#define PREP_IDX 4
#define SEND_IDX 5
#define FREE_IDX 6
struct swc_fsms {
int state[FSMS_NO];
char act[FSMS_NO];
};
#endif
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