Commit dc1af753 authored by Alessandro Rubini's avatar Alessandro Rubini

userspace/wrsw_hal from svn 1116

parent 43ffdb3c
include ../../Makedefs
OBJS = hal_exports.o hal_main.o hal_ports.o hal_config.o
OUTPUT = wrsw_hal
CC=$(CROSS_COMPILE_ARM)gcc
CFLAGS=-I. -g -Wall -I../rubi-repos/ptp-noposix/libwripc -I../include -I../3rdparty/include -DDEBUG
LDFLAGS=-L../rubi-repos/ptp-noposix -L../libswitchhw -lswitchhw -lwripc -L../3rdparty/lib -llua -lm
all: $(OBJS)
make -C ../libswitchhw
${CC} -o $(OUTPUT) $(OBJS) $(LDFLAGS)
%.o: %.c
${CC} -c $^ $(CFLAGS)
deploy: all
mkdir -p $(WR_INSTALL_ROOT)/bin
cp $(OUTPUT) $(WR_INSTALL_ROOT)/bin
upload: all
# - scp ../rootfs_override/wr/etc/wrsw_hal.conf root@$(T):/wr/etc
- scp $(OUTPUT) root@$(T):/wr/bin
run: upload
#- ssh -t root@$(T) "export LD_LIBRARY_PATH=/wr/lib && /wr/bin/$(OUTPUT)"
run:
clean:
rm -f $(OUTPUT) $(OBJS)
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <hw/trace.h>
#define HAL_CONFIG_FILE "/wr/etc/wrsw_hal.conf"
static lua_State *cfg_file = NULL;
static char *extra_cmdline = NULL;
static char *hal_config_file = HAL_CONFIG_FILE;
void hal_config_set_config_file(const char *str)
{
hal_config_file = strdup(str);
}
int hal_config_extra_cmdline(const char *str)
{
extra_cmdline = strdup(str);
}
int hal_parse_config()
{
TRACE(TRACE_INFO, "Parsing wrsw_hal configuration file: %s", HAL_CONFIG_FILE);
cfg_file = lua_open();
luaL_openlibs(cfg_file);
if (luaL_dofile(cfg_file, hal_config_file))
TRACE(TRACE_ERROR, "Error parsing the configuration file: %s", lua_tostring(cfg_file,-1));
luaL_dostring(cfg_file, "\
function get_var(name) \
local t = _G \
for w in name:gmatch(\"([%w_]+)\\.?\") do \
t = t[w] \
end \
return t \
end");
if(extra_cmdline)
luaL_dostring(cfg_file, extra_cmdline);
return 0;
}
static int global_get_var(const char *name)
{
lua_getglobal(cfg_file, "get_var");
lua_pushstring(cfg_file, name);
if(lua_pcall(cfg_file, 1, 1, 0) != 0)
return -1;
return 0;
}
int hal_config_get_int(const char *name, int *value)
{
if(global_get_var(name) < 0)
return -1;
if(!lua_isnumber(cfg_file, -1))
return -1;
*value = (int)lua_tonumber(cfg_file, -1);
return 0;
}
int hal_config_get_double(const char *name, double *value)
{
if(global_get_var(name) < 0)
return -1;
if(!lua_isnumber(cfg_file, -1))
return -1;
*value = (double)lua_tonumber(cfg_file, -1);
return 0;
}
int hal_config_get_string(const char *name, char *value, int max_len)
{
if(global_get_var(name) < 0)
return -1;
if(!lua_isstring(cfg_file, -1))
return -1;
strncpy(value, lua_tostring(cfg_file, -1), max_len);
return 0;
}
int hal_config_iterate(const char *section, int index, char *subsection, int max_len)
{
int i = 0;
if(global_get_var(section) < 0) return -1;
lua_pushnil(cfg_file); /* first key */
while (lua_next(cfg_file, -2) != 0) {
/* uses 'key' (at index -2) and 'value' (at index -1) */
char *key_type = lua_typename(cfg_file, lua_type(cfg_file, -1));
if(!strcmp(key_type, "table") && i == index)
{
strncpy(subsection, lua_tostring(cfg_file, -2), max_len);
return 1;
}
else if(!strcmp(key_type, "string") && i == index)
{
strncpy(subsection, lua_tostring(cfg_file, -1), max_len);
return 1;
}
i++;
/* removes 'value'; keeps 'key' for next iteration */
lua_pop(cfg_file, 1);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <hw/trace.h>
#include <hw/dmpll.h>
#include "wrsw_hal.h"
#include "hal_exports.h"
#include <wr_ipc.h>
#define WRSW_HAL_SERVER_ADDR "wrsw_hal"
static wripc_handle_t hal_ipc;
int halexp_check_running()
{
return 1;
}
int halexp_reset_port(const char *port_name)
{
TRACE(TRACE_INFO, "resetting port %s\n", port_name);
return 0;
}
int halexp_lock_cmd(const char *port_name, int command, int priority)
{
int rval;
// TRACE(TRACE_INFO,"Command %d", command);
switch(command)
{
case HEXP_LOCK_CMD_START:
return hal_port_start_lock(port_name, priority);
case HEXP_LOCK_CMD_CHECK:
rval = hal_port_check_lock(port_name);
if(rval > 0)
return HEXP_LOCK_STATUS_LOCKED;
else if (!rval)
return HEXP_LOCK_STATUS_BUSY;
else
return HEXP_LOCK_STATUS_NONE;
break;
}
return -100;
}
int halexp_query_port(char *port_name, int id)
{
}
int halexp_pps_cmd(int cmd, hexp_pps_params_t *params)
{
switch(cmd)
{
case HEXP_PPSG_CMD_ADJUST_PHASE:
shw_dmpll_phase_shift(params->port_name, params->adjust_phase_shift);
return 0;
case HEXP_PPSG_CMD_ADJUST_NSEC:
shw_pps_gen_adjust_nsec(params->adjust_nsec);
return 0;
case HEXP_PPSG_CMD_ADJUST_UTC:
shw_pps_gen_adjust_utc(params->adjust_utc);
return 0;
case HEXP_PPSG_CMD_POLL:
return shw_dmpll_shifter_busy(params->port_name) || shw_pps_gen_busy();
}
}
int halexp_pll_cmd(int cmd, hexp_pll_cmd_t *params)
{
}
static void hal_cleanup_wripc()
{
wripc_close(hal_ipc);
}
int hal_init_wripc()
{
hal_ipc = wripc_create_server(WRSW_HAL_SERVER_ADDR);
if(hal_ipc < 0)
return -1;
wripc_export(hal_ipc, T_INT32, "halexp_pps_cmd", halexp_pps_cmd, 2, T_INT32, T_STRUCT(hexp_pps_params_t));
wripc_export(hal_ipc, T_INT32, "halexp_pll_cmd", halexp_pll_cmd, 2, T_INT32, T_STRUCT(hexp_pll_cmd_t));
wripc_export(hal_ipc, T_INT32, "halexp_check_running", halexp_check_running, 0);
wripc_export(hal_ipc, T_STRUCT(hexp_port_state_t), "halexp_get_port_state", halexp_get_port_state, 1, T_STRING);
wripc_export(hal_ipc, T_INT32, "halexp_calibration_cmd", halexp_calibration_cmd, 3, T_STRING, T_INT32, T_INT32);
wripc_export(hal_ipc, T_INT32, "halexp_lock_cmd", halexp_lock_cmd, 3, T_STRING, T_INT32, T_INT32);
wripc_export(hal_ipc, T_STRUCT(hexp_port_list_t), "halexp_query_ports", halexp_query_ports, 0);
hal_add_cleanup_callback(hal_cleanup_wripc);
TRACE(TRACE_INFO, "Started WRIPC server '%s'", WRSW_HAL_SERVER_ADDR);
return 0;
}
int hal_update_wripc()
{
return wripc_process(hal_ipc);
}
int hal_check_running()
{
wripc_handle_t fd;
fd = wripc_connect(WRSW_HAL_SERVER_ADDR);
if(fd >= 0)
{
wripc_close(fd);
return 1;
}
return 0;
}
#ifndef __HAL_EXPORTS_H
#define __HAL_EXPORTS_H
#include <stdint.h>
#define HAL_MAX_PORTS 64
#define WRSW_HAL_SERVER_ADDR "wrsw_hal"
// checks if the calibration unit is idle
#define HEXP_CAL_CMD_CHECK_IDLE 1
// enables/disables transmission of calibration pattern
#define HEXP_CAL_CMD_TX_PATTERN 2
// requests a measurement of TX delta
#define HEXP_CAL_CMD_TX_MEASURE 4
// requests a measurement of RX delta
#define HEXP_CAL_CMD_RX_MEASURE 5
// get the raw delta_rx
#define HEXP_CAL_CMD_GET_RAW_DELTA_RX 6
// get the raw delta_tx
#define HEXP_CAL_CMD_GET_RAW_DELTA_TX 7
#define HEXP_CAL_RESP_BUSY 1
#define HEXP_CAL_RESP_OK 0
#define HEXP_CAL_RESP_ERROR -1
#define HEXP_LOCK_CMD_START 1
#define HEXP_LOCK_CMD_CHECK 2
#define HEXP_LOCK_STATUS_LOCKED 0
#define HEXP_LOCK_STATUS_BUSY 1
#define HEXP_LOCK_STATUS_NONE 2
#define HEXP_PPSG_CMD_GET 0
#define HEXP_PPSG_CMD_ADJUST_PHASE 1
#define HEXP_PPSG_CMD_ADJUST_UTC 2
#define HEXP_PPSG_CMD_ADJUST_NSEC 3
#define HEXP_PPSG_CMD_POLL 4
#define HEXP_ON 1
#define HEXP_OFF 0
#define HEXP_HPLL 0
#define HEXP_DMPLL 1
#define HEXP_FREQ 0
#define HEXP_PHASE 1
typedef struct {
char port_name[16];
uint32_t current_phase_shift;
int32_t adjust_phase_shift;
int64_t adjust_utc;
int32_t adjust_nsec;
uint64_t current_utc;
uint32_t current_nsec;
} hexp_pps_params_t;
/* Port modes (hexp_port_state_t.mode) */
#define HEXP_PORT_MODE_WR_MASTER 1
#define HEXP_PORT_MODE_WR_SLAVE 2
#define HEXP_PORT_MODE_NON_WR 3
#define FIX_ALPHA_FRACBITS 40
/*
#define HEXP_PORT_TSC_RISING 1
#define HEXP_PORT_TSC_FALLING 2
*/
typedef struct {
/* When non-zero: port state is valid */
int valid;
/* WR-PTP role of the port (Master, Slave, etc.) */
int mode;
/* TX and RX delays (combined, big Deltas from the link model in the spec) */
uint32_t delta_tx;
uint32_t delta_rx;
/* DDMTD raw phase value in picoseconds */
uint32_t phase_val;
/* When non-zero: phase_val contains a valid phase readout */
int phase_val_valid;
/* When non-zero: link is up */
int up;
/* When non-zero: TX path is calibrated (delta_tx contains valid value) */
int tx_calibrated;
/* When non-zero: RX path is calibrated (delta_rx contains valid value) */
int rx_calibrated;
int tx_tstamp_counter;
int rx_tstamp_counter;
int is_locked;
int lock_priority;
// timestamp linearization paramaters
uint32_t phase_setpoint; // DMPLL phase setpoint (picoseconds)
uint32_t clock_period; // reference lock period in picoseconds
uint32_t t2_phase_transition; // approximate DMTD phase value (on slave port) at which RX timestamp (T2) counter transistion occurs (picoseconds)
uint32_t t4_phase_transition; // approximate phase value (on master port) at which RX timestamp (T4) counter transistion occurs (picoseconds)
uint8_t hw_addr[6];
int hw_index;
int32_t fiber_fix_alpha;
} hexp_port_state_t;
typedef struct {
int num_ports;
char port_names[HAL_MAX_PORTS][16];
} hexp_port_list_t;
typedef struct {
int ki, kp;
int pll;
int branch;
} hexp_pll_cmd_t;
int halexp_check_running();
int halexp_reset_port(const char *port_name);
int halexp_calibration_cmd(const char *port_name, int command, int on_off);
int halexp_lock_cmd(const char *port_name, int command, int priority);
int halexp_query_ports(hexp_port_list_t *list);
int halexp_get_port_state(hexp_port_state_t *state, const char *port_name);
int halexp_pps_cmd(int cmd, hexp_pps_params_t *params);
int halexp_pll_set_gain(int pll, int branch, int kp, int ki);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <wr_ipc.h>
#include <hw/trace.h>
#include <hw/switch_hw.h>
#include "wrsw_hal.h"
#define MAX_CLEANUP_CALLBACKS 16
static int daemon_mode= 0;
static hal_cleanup_callback_t cleanup_cb[MAX_CLEANUP_CALLBACKS];
int hal_add_cleanup_callback(hal_cleanup_callback_t cb)
{
int i;
for(i=0;i<MAX_CLEANUP_CALLBACKS;i++)
if(!cleanup_cb[i])
{
cleanup_cb[i] = cb;
return 0;
}
return -1;
}
static void call_cleanup_cbs()
{
int i;
TRACE(TRACE_INFO, "Cleaning up...");
for(i=0;i<MAX_CLEANUP_CALLBACKS;i++)
if(cleanup_cb[i]) cleanup_cb[i]();
}
int hal_setup_fpga_images()
{
char fpga_dir[128];
char fw_name[128];
if( hal_config_get_string("global.hal_firmware_path", fpga_dir, sizeof(fpga_dir)) < 0)
return -1;
// shw_fpga_force_firmware_reload();
shw_set_fpga_firmware_path(fpga_dir);
if( !hal_config_get_string("global.main_firmware", fw_name, sizeof(fw_name)))
shw_request_fpga_firmware(FPGA_ID_MAIN, fw_name);
if( !hal_config_get_string("global.clkb_firmware", fw_name, sizeof(fw_name)))
shw_request_fpga_firmware(FPGA_ID_CLKB, fw_name);
return 0;
}
static int load_unload_kmod(const char *name, int load)
{
static char modules_path[128];
static int modules_path_valid = 0;
char cmd[256];
if(!modules_path_valid)
{
if(hal_config_get_string("global.hal_modules_path", modules_path, sizeof(modules_path)) < 0)
{
TRACE(TRACE_ERROR, "Unable to locate kernel modules directory!");
return -1;
}
modules_path_valid = 1;
}
TRACE(TRACE_INFO, "%s kernel module '%s'", load ? "Loading" : "Unloading", name);
snprintf(cmd, sizeof(cmd), "%s %s/%s", load ? "/sbin/insmod" : "/sbin/rmmod", modules_path, name);
system(cmd);
return 0;
}
#define assert_init(proc) { int ret; if((ret = proc) < 0) return ret; }
static void unload_kernel_modules()
{
char module_name[80];
int index = 0;
for(;;)
{
if(!hal_config_iterate("global.modules", index++, module_name, sizeof(module_name)))
break;
load_unload_kmod(module_name, 0);
}
}
int hal_load_kernel_modules()
{
char module_name[80];
int index = 0;
TRACE(TRACE_INFO, "Loading kernel modules...");
for(;;)
{
if(!hal_config_iterate("global.modules", index++, module_name, sizeof(module_name)))
break;
assert_init(load_unload_kmod(module_name, 1));
}
hal_add_cleanup_callback(unload_kernel_modules);
return 0;
}
void sighandler(int sig)
{
TRACE(TRACE_ERROR, "signal caught (%d)!", sig);
call_cleanup_cbs();
exit(0);
}
int hal_shutdown()
{
call_cleanup_cbs();
return 0;
}
int hal_init()
{
int enable;
trace_log_stderr();
TRACE(TRACE_INFO,"HAL initializing...");
memset(cleanup_cb, 0, sizeof(cleanup_cb));
signal(SIGSEGV, sighandler);
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
signal(SIGILL, sighandler);
assert_init(hal_parse_config());
assert_init(hal_setup_fpga_images());
if(!hal_config_get_int("timing.use_external_clock", &enable))
shw_use_external_reference(enable);
assert_init(shw_init());
assert_init(hal_load_kernel_modules());
assert_init(hal_init_ports());
assert_init(hal_init_wripc());
return 0;
}
void hal_update()
{
hal_update_wripc();
hal_update_ports();
usleep(1000);
}
void hal_deamonize()
{
pid_t pid, sid;
/* already a daemon */
if ( getppid() == 1 ) return;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
/* At this point we are executing as the child process */
/* Change the file mode mask */
umask(0);
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
exit(EXIT_FAILURE);
}
/* Change the current working directory. This prevents the current
directory from being locked; hence not being able to remove it. */
if ((chdir("/")) < 0) {
exit(EXIT_FAILURE);
}
/* Redirect standard files to /dev/null */
freopen( "/dev/null", "r", stdin);
freopen( "/dev/null", "w", stdout);
freopen( "/dev/null", "w", stderr);
}
static void show_help()
{
printf("WR Switch Hardware Abstraction Layer daemon (wrsw_hal)\n\
Usage: wrsw_hal [options], where [options] can be:\n\
-f : force FPGA firmware reload\n\
-d : fork into background (daemon mode)\n\
-x [code]: execute arbitrary Lua [code] before loading configuration file\n\
-c [file]: specify your own config file\n\n");
}
void hal_parse_cmdline(int argc, char *argv[])
{
int opt;
while((opt=getopt(argc, argv, "dfhx:c:")) != -1)
{
switch(opt)
{
case 'd':
daemon_mode = 1;
break;
case 'x':
hal_config_extra_cmdline(optarg);
break;
case 'c':
hal_config_set_config_file(optarg);
break;
case 'f':
shw_fpga_force_firmware_reload();
break;
case 'h':
show_help();
exit(0);
break;
default:
fprintf(stderr,"Unrecognized option. Call %s -h for help.\n", argv[0]);
break;
}
}
}
int main(int argc, char *argv[])
{
if(hal_check_running())
{
fprintf(stderr, "Fatal: There is another WR HAL instance running. We can't work together.\n\n");
return -1;
}
hal_parse_cmdline(argc, argv);
hal_init();
if(daemon_mode)
hal_deamonize();
for(;;) hal_update();
hal_shutdown();
return 0;
}
This diff is collapsed.
#ifndef __WRSW_HAL_H
#define __WRSW_HAL_H
#include <inttypes.h>
typedef void (*hal_cleanup_callback_t)();
#define PORT_BUSY 1
#define PORT_OK 0
#define PORT_ERROR -1
/* Port delay calibration parameters */
typedef struct {
/* PHY delay measurement parameters for PHYs which require external calibration (i.e. with
the feedback network. */
/* minimum possible delay introduced by the PHY. Expressed as time
(in picoseconds) between the beginning of the symbol on the serial input
and the rising edge of the RX clock at which the deserialized word is
available at the parallel output of the PHY. */
uint32_t phy_rx_min;
/* RX delay range of the PHY, expressed as a difference (in picoseconds)
between the maximum and minimum possible RX delays. For example, a 1.25 Gbps
PHY with minimum delay of 8 UI and maximum delay of 12 UI will have
phy_rx_range equal to (12 - 8) * 800 ps = 3200 ps. Due to the nature of the
calibration method, the measurement range is limited to one parallel clock cycle,
i.e. 10 UIs, which is true for most 802.3z serdeses. PHYs which have bigger
delay variance can't be calibrated using this method. */
uint32_t phy_rx_range;
/* value of the phase shift (in picoseconds) measured by the calibrator DMTD
when the PHY has locked on the minimum possible delay. Used to "unwind" the phase
measurement into the PHY RX delay. This parameter must be determined experimentally. */
uint32_t phy_rx_bias;
/* the same set of parameters, but for the TX path of the PHY */
uint32_t phy_tx_bias;
uint32_t phy_tx_min;
uint32_t phy_tx_range;
/* Current PHY (clock-to-serial-symbol) TX and RX delays, in picoseconds */
uint32_t delta_tx_phy;
uint32_t delta_rx_phy;
/* Current SFP (electrical in to optical out) TX and RX delays, in picoseconds */
uint32_t delta_tx_sfp;
uint32_t delta_rx_sfp;
/* Current board routing delays (between the DDMTD inputs to the PHY clock
inputs/outputs), in picoseconds */
uint32_t delta_tx_board;
uint32_t delta_rx_board;
uint32_t raw_delta_rx_phy;
uint32_t raw_delta_tx_phy;
/* Fiber "alpha" asymmetry coefficient, as defined in the WRPTP Specification */
double fiber_alpha;
/* Fixed point fiber asymmetry coefficient. Expressed as (2 ^ 40 * (fiber_alpha - 1)). */ int32_t fiber_fix_alpha;
/* When non-zero: RX path is calibrated (delta_*_rx contain valid values) */
int rx_calibrated;
/* When non-zero: TX path is calibrated */
int tx_calibrated;
} hal_port_calibration_t;
int hal_parse_config();
int hal_check_running();
int hal_config_get_int(const char *name, int *value);
int hal_config_get_double(const char *name, double *value);
int hal_config_get_string(const char *name, char *value, int max_len);
int hal_config_iterate(const char *section, int index, char *subsection, int max_len);
int hal_init_ports();
void hal_update_ports();
int hal_init_wripc();
int hal_update_wripc();
int hal_add_cleanup_callback(hal_cleanup_callback_t cb);
int hal_port_start_lock(const char *port_name, int priority);
int hal_port_check_lock(const char *port_name);
#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