Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
wr-switch-sw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
white-rabbit
wr-switch-sw
Commits
dc1af753
Commit
dc1af753
authored
May 17, 2011
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
userspace/wrsw_hal from svn 1116
parent
43ffdb3c
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1583 additions
and
0 deletions
+1583
-0
Makefile
userspace/wrsw_hal/Makefile
+32
-0
hal_config.c
userspace/wrsw_hal/hal_config.c
+122
-0
hal_exports.c
userspace/wrsw_hal/hal_exports.c
+136
-0
hal_exports.h
userspace/wrsw_hal/hal_exports.h
+151
-0
hal_main.c
userspace/wrsw_hal/hal_main.c
+286
-0
hal_ports.c
userspace/wrsw_hal/hal_ports.c
+761
-0
wrsw_hal.h
userspace/wrsw_hal/wrsw_hal.h
+95
-0
No files found.
userspace/wrsw_hal/Makefile
0 → 100644
View file @
dc1af753
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
userspace/wrsw_hal/hal_config.c
0 → 100644
View file @
dc1af753
#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
;
}
userspace/wrsw_hal/hal_exports.c
0 → 100644
View file @
dc1af753
#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
;
}
userspace/wrsw_hal/hal_exports.h
0 → 100644
View file @
dc1af753
#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
userspace/wrsw_hal/hal_main.c
0 → 100644
View file @
dc1af753
#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
;
}
userspace/wrsw_hal/hal_ports.c
0 → 100644
View file @
dc1af753
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <wr_ipc.h>
#include <hw/trace.h>
#include <hw/hpll.h>
#include <hw/dmpll.h>
#include <hw/phy_calibration.h>
#include <hw/pio.h>
#include <hw/pio_pins.h>
#include <hw/fpga_regs.h>
#include <hw/endpoint_regs.h>
#include <hw/watchdog.h>
#include "wrsw_hal.h"
#include "hal_exports.h"
#define MAX_PORTS 64
#define HAL_PORT_MODE_WR_UPLINK 1
#define HAL_PORT_MODE_WR_DOWNLINK 2
#define HAL_PORT_MODE_NON_WR 3
#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 LOCK_STATE_NONE 0
#define LOCK_STATE_WAIT_HPLL 1
#define LOCK_STATE_WAIT_DMPLL 2
#define LOCK_STATE_LOCKED 3
#define LOCK_STATE_START 4
#define DEFAULT_FIBER_ALPHA_COEF (1.4682e-04*1.76)
/* Internal port state structure */
typedef
struct
{
int
in_use
;
char
name
[
16
];
uint8_t
hw_addr
[
6
];
int
hw_index
;
int
fd
;
int
hw_addr_auto
;
int
mode
;
int
state
;
int
index
;
int
locked
;
hal_port_calibration_t
calib
;
uint32_t
phase_val
;
int
phase_val_valid
;
int
lock_state
;
int
tx_cal_pending
;
int
rx_cal_pending
;
int
led_index
;
uint32_t
ep_base
;
}
hal_port_state_t
;
#define LED_DOWN_MASK 0x00
#define LED_UP_MASK 0x80
static
hal_port_state_t
ports
[
MAX_PORTS
];
static
int
fd_raw
;
static
uint32_t
fix_phy_delay
(
int32_t
delay
,
int32_t
bias
,
int32_t
min_val
,
int32_t
range
)
{
int32_t
brange
=
(
bias
+
range
)
%
8000
;
TRACE
(
TRACE_INFO
,
"dly %d bias %d range %d brange %d"
,
delay
,
bias
,
range
,
brange
);
if
(
bias
+
range
>
8000
)
{
if
(
brange
<
0
)
brange
+=
8000
;
if
(
delay
>
bias
||
(
delay
<
bias
&&
delay
>
brange
))
{
return
delay
-
bias
+
min_val
;
}
{
return
delay
+
(
8000
-
bias
)
+
min_val
;
}
}
else
{
return
delay
-
bias
+
min_val
;
}
return
delay
;
}
// FIXME: MAC addresses should be kept in some EEPROM
static
int
get_mac_address
(
const
char
*
if_name
,
uint8_t
*
mac_addr
)
{
struct
ifreq
ifr
;
int
idx
;
int
uniq_num
;
idx
=
(
if_name
[
2
]
==
'u'
?
32
:
0
)
+
(
if_name
[
3
]
-
'0'
);
strncpy
(
ifr
.
ifr_name
,
"eth0"
,
sizeof
(
ifr
.
ifr_name
));
if
(
ioctl
(
fd_raw
,
SIOCGIFHWADDR
,
&
ifr
)
<
0
)
return
-
1
;
uniq_num
=
(
int
)
ifr
.
ifr_hwaddr
.
sa_data
[
4
]
*
256
+
(
int
)
ifr
.
ifr_hwaddr
.
sa_data
[
5
]
+
idx
;
mac_addr
[
0
]
=
0x2
;
// locally administered MAC
mac_addr
[
1
]
=
0x4a
;
mac_addr
[
2
]
=
0xbc
;
mac_addr
[
3
]
=
(
uniq_num
>>
16
)
&
0xff
;
mac_addr
[
4
]
=
(
uniq_num
>>
8
)
&
0xff
;
mac_addr
[
5
]
=
uniq_num
&
0xff
;
return
0
;
}
static
void
reset_port_state
(
hal_port_state_t
*
p
)
{
p
->
calib
.
rx_calibrated
=
0
;
p
->
calib
.
tx_calibrated
=
0
;
p
->
locked
=
0
;
p
->
state
=
HAL_PORT_STATE_LINK_DOWN
;
p
->
lock_state
=
LOCK_STATE_NONE
;
p
->
tx_cal_pending
=
0
;
p
->
rx_cal_pending
=
0
;
}
#define AT_INT32 0
#define AT_DOUBLE 1
static
void
cfg_get_port_param
(
const
char
*
port_name
,
const
char
*
param_name
,
void
*
rval
,
int
param_type
,
...)
{
va_list
ap
;
char
str
[
1024
];
snprintf
(
str
,
sizeof
(
str
),
"ports.%s.%s"
,
port_name
,
param_name
);
va_start
(
ap
,
param_type
);
switch
(
param_type
)
{
case
AT_INT32
:
if
(
hal_config_get_int
(
str
,
(
int
*
)
rval
))
*
(
int
*
)
rval
=
va_arg
(
ap
,
int
);
break
;
case
AT_DOUBLE
:
if
(
hal_config_get_double
(
str
,
(
double
*
)
rval
))
*
(
double
*
)
rval
=
va_arg
(
ap
,
double
);
break
;
default:
break
;
}
va_end
(
ap
);
}
static
int
check_port_presence
(
const
char
*
if_name
)
{
struct
ifreq
ifr
;
strncpy
(
ifr
.
ifr_name
,
if_name
,
sizeof
(
ifr
.
ifr_name
));
if
(
ioctl
(
fd_raw
,
SIOCGIFHWADDR
,
&
ifr
)
<
0
)
return
-
1
;
return
0
;
}
/* Performs one-time TX path calibration for a certain port, right after the HAL startup
(TX latency never changes as long as the PHY is enabled, even if the link goes down) */
static
int
port_startup_tx_calibration
(
hal_port_state_t
*
p
)
{
uint32_t
raw_phase
;
TRACE
(
TRACE_INFO
,
"Pre-calibratinmg TX for port %s"
,
p
->
name
);
if
(
shw_cal_enable_pattern
(
p
->
name
,
1
)
<
0
)
{
return
-
1
;
}
TRACE
(
TRACE_INFO
,
"Pattern"
);
if
(
shw_cal_enable_feedback
(
p
->
name
,
1
,
PHY_CALIBRATE_TX
)
<
0
)
{
shw_cal_enable_pattern
(
p
->
name
,
0
);
return
-
1
;
}
TRACE
(
TRACE_INFO
,
"Feedback"
);
while
(
!
shw_cal_measure
(
&
raw_phase
))
usleep
(
1000
);
TRACE
(
TRACE_INFO
,
"Poll"
);
p
->
calib
.
delta_tx_phy
=
fix_phy_delay
(
8000
-
raw_phase
,
p
->
calib
.
phy_tx_bias
,
p
->
calib
.
phy_tx_min
,
p
->
calib
.
phy_tx_range
);
p
->
calib
.
tx_calibrated
=
1
;
TRACE
(
TRACE_INFO
,
"port %s, delta_tx_phy = %d ps"
,
p
->
name
,
p
->
calib
.
delta_tx_phy
);
shw_cal_enable_pattern
(
p
->
name
,
0
);
return
0
;
}
int
hal_init_port
(
const
char
*
name
,
int
index
)
{
char
key_name
[
128
];
char
val
[
128
];
char
cmd
[
128
];
hal_port_state_t
*
p
=
&
ports
[
index
];
uint8_t
mac_addr
[
6
];
if
(
check_port_presence
(
name
)
<
0
)
{
reset_port_state
(
p
);
p
->
in_use
=
0
;
return
0
;
}
reset_port_state
(
p
);
p
->
in_use
=
1
;
get_mac_address
(
name
,
mac_addr
);
TRACE
(
TRACE_INFO
,
"Initializing port '%s' [%02x:%02x:%02x:%02x:%02x:%02x]"
,
name
,
mac_addr
[
0
],
mac_addr
[
1
],
mac_addr
[
2
],
mac_addr
[
3
],
mac_addr
[
4
],
mac_addr
[
5
]
);
strncpy
(
p
->
name
,
name
,
16
);
memcpy
(
p
->
hw_addr
,
mac_addr
,
6
);
snprintf
(
cmd
,
sizeof
(
cmd
),
"/sbin/ifconfig %s hw ether %02x:%02x:%02x:%02x:%02x:%02x"
,
name
,
mac_addr
[
0
],
mac_addr
[
1
],
mac_addr
[
2
],
mac_addr
[
3
],
mac_addr
[
4
],
mac_addr
[
5
]
);
system
(
cmd
);
snprintf
(
cmd
,
sizeof
(
cmd
),
"/sbin/ifconfig %s up"
,
name
);
system
(
cmd
);
cfg_get_port_param
(
name
,
"phy_rx_bias"
,
&
p
->
calib
.
phy_rx_bias
,
AT_INT32
,
7800
);
cfg_get_port_param
(
name
,
"phy_rx_min"
,
&
p
->
calib
.
phy_rx_min
,
AT_INT32
,
18
*
800
);
cfg_get_port_param
(
name
,
"phy_rx_range"
,
&
p
->
calib
.
phy_rx_range
,
AT_INT32
,
7
*
800
);
cfg_get_port_param
(
name
,
"phy_tx_bias"
,
&
p
->
calib
.
phy_tx_bias
,
AT_INT32
,
7800
);
cfg_get_port_param
(
name
,
"phy_tx_min"
,
&
p
->
calib
.
phy_tx_min
,
AT_INT32
,
18
*
800
);
cfg_get_port_param
(
name
,
"phy_tx_range"
,
&
p
->
calib
.
phy_tx_range
,
AT_INT32
,
7
*
800
);
cfg_get_port_param
(
name
,
"delta_tx_sfp"
,
&
p
->
calib
.
delta_tx_sfp
,
AT_INT32
,
0
);
cfg_get_port_param
(
name
,
"delta_rx_sfp"
,
&
p
->
calib
.
delta_rx_sfp
,
AT_INT32
,
0
);
cfg_get_port_param
(
name
,
"delta_tx_board"
,
&
p
->
calib
.
delta_tx_board
,
AT_INT32
,
0
);
cfg_get_port_param
(
name
,
"delta_rx_board"
,
&
p
->
calib
.
delta_rx_board
,
AT_INT32
,
0
);
cfg_get_port_param
(
name
,
"fiber_alpha"
,
&
p
->
calib
.
fiber_alpha
,
AT_DOUBLE
,
DEFAULT_FIBER_ALPHA_COEF
);
p
->
calib
.
fiber_fix_alpha
=
(
double
)
pow
(
2
.
0
,
40
.
0
)
*
((
p
->
calib
.
fiber_alpha
+
1
.
0
)
/
(
p
->
calib
.
fiber_alpha
+
2
.
0
)
-
0
.
5
);
TRACE
(
TRACE_INFO
,
"Alpha: %.10f FixAlpha: %d"
,
p
->
calib
.
fiber_alpha
,
p
->
calib
.
fiber_fix_alpha
);
p
->
led_index
=
(
int
)
(
p
->
name
[
3
]
-
'0'
);
if
(
p
->
name
[
2
]
==
'u'
)
p
->
led_index
|=
LED_UP_MASK
;
if
(
p
->
name
[
2
]
==
'd'
)
{
p
->
hw_index
=
2
+
(
p
->
name
[
3
]
-
'0'
);
}
else
{
p
->
hw_index
=
0
+
(
p
->
name
[
3
]
-
'0'
);
}
p
->
ep_base
=
FPGA_BASE_EP_UP0
+
0x10000
*
p
->
hw_index
;
// TRACE(TRACE_INFO,"port %s regs 0x%08x\n", p->name, p->ep_base);
snprintf
(
key_name
,
sizeof
(
key_name
),
"ports.%s.mode"
,
p
->
name
);
if
(
!
hal_config_get_string
(
key_name
,
val
,
sizeof
(
val
)))
{
if
(
!
strcasecmp
(
val
,
"wr_master"
))
p
->
mode
=
HEXP_PORT_MODE_WR_MASTER
;
else
if
(
!
strcasecmp
(
val
,
"wr_slave"
))
p
->
mode
=
HEXP_PORT_MODE_WR_SLAVE
;
else
if
(
!
strcasecmp
(
val
,
"non_wr"
))
p
->
mode
=
HEXP_PORT_MODE_NON_WR
;
else
{
TRACE
(
TRACE_ERROR
,
"Invalid mode specified for port %s. Defaulting to Non-WR"
,
p
->
name
);
p
->
mode
=
HEXP_PORT_MODE_NON_WR
;
}
TRACE
(
TRACE_INFO
,
"Port %s: mode %s"
,
p
->
name
,
val
);
}
else
{
p
->
mode
=
HEXP_PORT_MODE_NON_WR
;
}
port_startup_tx_calibration
(
p
);
return
0
;
}
int
hal_init_ports
()
{
int
index
=
0
;
char
port_name
[
128
];
TRACE
(
TRACE_INFO
,
"Initializing switch ports"
);
fd_raw
=
socket
(
AF_PACKET
,
SOCK_DGRAM
,
0
);
if
(
fd_raw
<
0
)
return
-
1
;
memset
(
ports
,
0
,
sizeof
(
ports
));
for
(;;)
{
if
(
!
hal_config_iterate
(
"ports"
,
index
++
,
port_name
,
sizeof
(
port_name
)))
break
;
hal_init_port
(
port_name
,
index
);
}
return
0
;
}
static
int
check_link_up
(
const
char
*
if_name
)
{
struct
ifreq
ifr
;
strncpy
(
ifr
.
ifr_name
,
if_name
,
sizeof
(
ifr
.
ifr_name
));
if
(
ioctl
(
fd_raw
,
SIOCGIFFLAGS
,
&
ifr
)
>
0
)
return
-
1
;
return
(
ifr
.
ifr_flags
&
IFF_UP
&&
ifr
.
ifr_flags
&
IFF_RUNNING
);
}
static
void
port_locking_fsm
(
hal_port_state_t
*
p
)
{
switch
(
p
->
lock_state
)
{
case
LOCK_STATE_NONE
:
return
;
case
LOCK_STATE_START
:
shw_hpll_switch_reference
(
p
->
name
);
p
->
lock_state
=
LOCK_STATE_WAIT_HPLL
;
break
;
case
LOCK_STATE_WAIT_HPLL
:
if
(
shw_hpll_check_lock
())
{
TRACE
(
TRACE_INFO
,
"HPLL locked to port: %s"
,
p
->
name
);
shw_dmpll_lock
(
p
->
name
);
p
->
lock_state
=
LOCK_STATE_WAIT_DMPLL
;
}
break
;
case
LOCK_STATE_WAIT_DMPLL
:
if
(
!
shw_hpll_check_lock
())
{
p
->
lock_state
=
LOCK_STATE_NONE
;
}
else
if
(
shw_dmpll_check_lock
())
{
TRACE
(
TRACE_INFO
,
"DMPLL locked to port: %s"
,
p
->
name
);
p
->
lock_state
=
LOCK_STATE_LOCKED
;
}
break
;
case
LOCK_STATE_LOCKED
:
if
(
!
shw_hpll_check_lock
())
{
TRACE
(
TRACE_ERROR
,
"HPLL de-locked"
);
p
->
lock_state
=
LOCK_STATE_NONE
;
p
->
locked
=
0
;
}
else
if
(
!
shw_dmpll_check_lock
())
{
TRACE
(
TRACE_ERROR
,
"DMPLL de-locked"
);
p
->
lock_state
=
LOCK_STATE_NONE
;
p
->
locked
=
0
;
}
else
p
->
locked
=
1
;
break
;
}
}
static
void
poll_dmtd
(
hal_port_state_t
*
p
)
{
uint32_t
phase_val
;
if
(
shw_poll_dmtd
(
p
->
name
,
&
phase_val
)
>
0
)
{
p
->
phase_val
=
phase_val
;
p
->
phase_val_valid
=
1
;
}
else
{
p
->
phase_val_valid
=
0
;
};
}
static
void
calibration_fsm
(
hal_port_state_t
*
p
)
{
if
(
p
->
name
[
2
]
==
'd'
)
{
TRACE
(
TRACE_INFO
,
"Bypassing calibration for downlink port %s"
,
p
->
name
);
p
->
calib
.
tx_calibrated
=
1
;
p
->
calib
.
rx_calibrated
=
1
;
p
->
calib
.
delta_rx_phy
=
0
;
p
->
calib
.
delta_tx_phy
=
0
;
p
->
tx_cal_pending
=
0
;
p
->
rx_cal_pending
=
0
;
return
;
}
if
(
p
->
tx_cal_pending
||
p
->
rx_cal_pending
)
{
uint32_t
phase
;
if
(
shw_cal_measure
(
&
phase
)
>
0
)
{
TRACE
(
TRACE_INFO
,
"MeasuredPhase: %d"
,
phase
);
if
(
p
->
tx_cal_pending
)
{
p
->
calib
.
tx_calibrated
=
1
;
p
->
calib
.
raw_delta_tx_phy
=
8000
-
phase
;
p
->
calib
.
delta_tx_phy
=
fix_phy_delay
(
8000
-
phase
,
p
->
calib
.
phy_tx_bias
,
p
->
calib
.
phy_tx_min
,
p
->
calib
.
phy_tx_range
);
TRACE
(
TRACE_INFO
,
"TXCal: raw %d fixed %d
\n
"
,
phase
,
p
->
calib
.
delta_tx_phy
);
p
->
tx_cal_pending
=
0
;
// TX DMTD is connected in the opposite direction - it measures input - refclk value, so we need to invert it.
}
if
(
p
->
rx_cal_pending
)
{
p
->
calib
.
rx_calibrated
=
1
;
p
->
calib
.
raw_delta_rx_phy
=
phase
;
p
->
calib
.
delta_rx_phy
=
fix_phy_delay
(
phase
,
p
->
calib
.
phy_rx_bias
,
p
->
calib
.
phy_rx_min
,
p
->
calib
.
phy_rx_range
);
TRACE
(
TRACE_INFO
,
"RXCal: raw %d fixed %d
\n
"
,
phase
,
p
->
calib
.
delta_rx_phy
);
p
->
rx_cal_pending
=
0
;
}
}
}
}
static
int
update_port_leds
(
hal_port_state_t
*
p
)
{
uint32_t
dsr
=
_fpga_readl
(
p
->
ep_base
+
EP_REG_DSR
);
if
(
p
->
led_index
&
LED_UP_MASK
)
{
int
i
=
p
->
led_index
&
0xf
;
if
(
i
==
1
)
shw_pio_set
(
&
PIN_fled4
[
0
],
dsr
&
EP_DSR_LSTATUS
?
0
:
1
);
else
shw_pio_set
(
&
PIN_fled0
[
0
],
dsr
&
EP_DSR_LSTATUS
?
0
:
1
);
// uplinks....
}
else
{
// printf("li %d\n", p->led_index);
shw_mbl_set_leds
(
p
->
led_index
,
0
,
dsr
&
EP_DSR_LSTATUS
?
MBL_LED_ON
:
MBL_LED_OFF
);
}
return
0
;
}
static
void
port_fsm
(
hal_port_state_t
*
p
)
{
int
link_up
=
check_link_up
(
p
->
name
);
// update_port_leds(p);
if
(
!
link_up
&&
p
->
state
!=
HAL_PORT_STATE_LINK_DOWN
)
{
TRACE
(
TRACE_INFO
,
"%s: link down"
,
p
->
name
);
p
->
state
=
HAL_PORT_STATE_LINK_DOWN
;
reset_port_state
(
p
);
p
->
calib
.
rx_calibrated
=
0
;
return
;
}
port_locking_fsm
(
p
);
switch
(
p
->
state
)
{
case
HAL_PORT_STATE_LINK_DOWN
:
{
if
(
link_up
)
{
TRACE
(
TRACE_INFO
,
"%s: link up"
,
p
->
name
);
p
->
state
=
HAL_PORT_STATE_UP
;
}
break
;
}
case
HAL_PORT_STATE_UP
:
poll_dmtd
(
p
);
break
;
case
HAL_PORT_STATE_LOCKING
:
if
(
p
->
locked
)
{
TRACE
(
TRACE_INFO
,
"[main-fsm] Port %s locked."
,
p
->
name
);
p
->
state
=
HAL_PORT_STATE_UP
;
}
break
;
case
HAL_PORT_STATE_CALIBRATION
:
if
(
p
->
rx_cal_pending
||
p
->
tx_cal_pending
)
calibration_fsm
(
p
);
else
p
->
state
=
HAL_PORT_STATE_UP
;
break
;
}
}
void
hal_update_ports
()
{
int
i
;
for
(
i
=
0
;
i
<
MAX_PORTS
;
i
++
)
if
(
ports
[
i
].
in_use
)
port_fsm
(
&
ports
[
i
]);
}
static
hal_port_state_t
*
lookup_port
(
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
MAX_PORTS
;
i
++
)
if
(
ports
[
i
].
in_use
&&
!
strcmp
(
name
,
ports
[
i
].
name
))
return
&
ports
[
i
];
return
NULL
;
}
int
hal_port_start_lock
(
const
char
*
port_name
,
int
priority
)
{
hal_port_state_t
*
p
=
lookup_port
(
port_name
);
if
(
!
p
)
return
PORT_ERROR
;
if
(
p
->
state
!=
HAL_PORT_STATE_UP
)
return
PORT_BUSY
;
p
->
state
=
HAL_PORT_STATE_LOCKING
;
p
->
lock_state
=
LOCK_STATE_START
;
TRACE
(
TRACE_INFO
,
"Locking to port: %s"
,
port_name
);
return
PORT_OK
;
}
int
hal_port_check_lock
(
const
char
*
port_name
)
{
hal_port_state_t
*
p
=
lookup_port
(
port_name
);
if
(
!
p
)
return
PORT_ERROR
;
if
(
p
->
lock_state
==
LOCK_STATE_LOCKED
)
return
1
;
return
0
;
}
int
halexp_get_port_state
(
hexp_port_state_t
*
state
,
const
char
*
port_name
)
{
hal_port_state_t
*
p
=
lookup_port
(
port_name
);
if
(
!
p
)
return
-
1
;
state
->
valid
=
1
;
state
->
mode
=
p
->
mode
;
state
->
up
=
p
->
state
!=
HAL_PORT_STATE_LINK_DOWN
;
state
->
is_locked
=
p
->
lock_state
==
LOCK_STATE_LOCKED
;
state
->
phase_val
=
p
->
phase_val
;
state
->
phase_val_valid
=
p
->
phase_val_valid
;
state
->
tx_calibrated
=
p
->
calib
.
tx_calibrated
;
state
->
rx_calibrated
=
p
->
calib
.
rx_calibrated
;
state
->
delta_tx
=
p
->
calib
.
delta_tx_phy
+
p
->
calib
.
delta_tx_sfp
+
p
->
calib
.
delta_tx_board
;
state
->
delta_rx
=
p
->
calib
.
delta_rx_phy
+
p
->
calib
.
delta_rx_sfp
+
p
->
calib
.
delta_rx_board
;
state
->
t2_phase_transition
=
1400
;
state
->
t4_phase_transition
=
1400
;
state
->
clock_period
=
8000
;
state
->
fiber_fix_alpha
=
p
->
calib
.
fiber_fix_alpha
;
memcpy
(
state
->
hw_addr
,
p
->
hw_addr
,
6
);
state
->
hw_index
=
p
->
hw_index
;
return
0
;
}
static
int
any_port_calibrating
()
{
int
i
;
for
(
i
=
0
;
i
<
MAX_PORTS
;
i
++
)
if
(
ports
[
i
].
state
==
HAL_PORT_STATE_CALIBRATION
&&
ports
[
i
].
in_use
)
return
1
;
return
0
;
}
int
halexp_calibration_cmd
(
const
char
*
port_name
,
int
command
,
int
on_off
)
{
hal_port_state_t
*
p
=
lookup_port
(
port_name
);
// TRACE(TRACE_INFO,"cal_cmd port %s cmn %d\n", port_name, command);
if
(
!
p
)
return
-
1
;
switch
(
command
)
{
case
HEXP_CAL_CMD_CHECK_IDLE
:
return
!
any_port_calibrating
()
&&
p
->
state
==
HAL_PORT_STATE_UP
?
HEXP_CAL_RESP_OK
:
HEXP_CAL_RESP_BUSY
;
case
HEXP_CAL_CMD_GET_RAW_DELTA_RX
:
return
p
->
calib
.
raw_delta_rx_phy
;
break
;
case
HEXP_CAL_CMD_GET_RAW_DELTA_TX
:
return
p
->
calib
.
raw_delta_tx_phy
;
break
;
case
HEXP_CAL_CMD_TX_PATTERN
:
TRACE
(
TRACE_INFO
,
"TXPattern %s, port %s"
,
on_off
?
"ON"
:
"OFF"
,
port_name
);
// FIXME: error handling
if
(
on_off
)
p
->
state
=
HAL_PORT_STATE_CALIBRATION
;
else
p
->
state
=
HAL_PORT_STATE_UP
;
shw_cal_enable_pattern
(
p
->
name
,
on_off
);
return
HEXP_CAL_RESP_OK
;
break
;
case
HEXP_CAL_CMD_TX_MEASURE
:
TRACE
(
TRACE_INFO
,
"TXMeasure %s, port %s"
,
on_off
?
"ON"
:
"OFF"
,
port_name
);
p
->
calib
.
tx_calibrated
=
0
;
if
(
on_off
)
{
// if(p->state == HAL_PORT_STATE_CALIBRATION)
// {
// TRACE(TRACE_INFO, "TXFeedbackOn");
p
->
tx_cal_pending
=
1
;
p
->
calib
.
tx_calibrated
=
0
;
shw_cal_enable_feedback
(
p
->
name
,
1
,
PHY_CALIBRATE_TX
);
p
->
state
=
HAL_PORT_STATE_CALIBRATION
;
return
HEXP_CAL_RESP_OK
;
// } else return HEXP_CAL_RESP_ERROR;
}
else
{
p
->
state
=
HAL_PORT_STATE_UP
;
p
->
tx_cal_pending
=
0
;
shw_cal_enable_feedback
(
p
->
name
,
0
,
PHY_CALIBRATE_TX
);
return
HEXP_CAL_RESP_OK
;
}
break
;
case
HEXP_CAL_CMD_RX_MEASURE
:
TRACE
(
TRACE_INFO
,
"RXMeasure %s, port %s"
,
on_off
?
"ON"
:
"OFF"
,
port_name
);
if
(
on_off
)
{
p
->
rx_cal_pending
=
1
;
p
->
calib
.
rx_calibrated
=
0
;
shw_cal_enable_feedback
(
p
->
name
,
1
,
PHY_CALIBRATE_RX
);
p
->
state
=
HAL_PORT_STATE_CALIBRATION
;
return
HEXP_CAL_RESP_OK
;
}
else
{
shw_cal_enable_feedback
(
p
->
name
,
0
,
PHY_CALIBRATE_RX
);
p
->
state
=
HAL_PORT_STATE_UP
;
p
->
rx_cal_pending
=
0
;
return
HEXP_CAL_RESP_OK
;
}
break
;
};
return
0
;
}
// returns the name of the interface for given index (0..max) or an empty string if
// there is no such interface
int
halexp_query_ports
(
hexp_port_list_t
*
list
)
{
int
i
;
int
n
=
0
;
TRACE
(
TRACE_INFO
,
" client queried port list."
);
for
(
i
=
0
;
i
<
MAX_PORTS
;
i
++
)
{
if
(
ports
[
i
].
in_use
)
strcpy
(
list
->
port_names
[
n
++
],
ports
[
i
].
name
);
}
list
->
num_ports
=
n
;
return
0
;
}
userspace/wrsw_hal/wrsw_hal.h
0 → 100644
View file @
dc1af753
#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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment