satman: ping repeater links

Tested OK on hardware.
This commit is contained in:
Sebastien Bourdeauducq 2018-09-10 20:17:02 +08:00
parent 31bef9918e
commit bc1d3fda6a
2 changed files with 146 additions and 25 deletions

View File

@ -1,4 +1,4 @@
#![feature(never_type, panic_implementation, panic_info_message)]
#![feature(never_type, panic_implementation, panic_info_message, const_slice_len)]
#![no_std]
#[macro_use]
@ -14,19 +14,27 @@ use board_artiq::serwb;
#[cfg(has_hmc830_7043)]
use board_artiq::hmc830_7043;
fn drtio_reset(reset: bool) {
mod repeater;
fn drtiosat_reset(reset: bool) {
unsafe {
csr::drtiosat::reset_write(if reset { 1 } else { 0 });
}
}
fn drtio_reset_phy(reset: bool) {
fn drtiosat_reset_phy(reset: bool) {
unsafe {
csr::drtiosat::reset_phy_write(if reset { 1 } else { 0 });
}
}
fn drtio_tsc_loaded() -> bool {
fn drtiosat_link_rx_up() -> bool {
unsafe {
csr::drtiosat::rx_up_read() == 1
}
}
fn drtiosat_tsc_loaded() -> bool {
unsafe {
let tsc_loaded = csr::drtiosat::tsc_loaded_read() == 1;
if tsc_loaded {
@ -44,11 +52,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error<!>
drtioaux::send_link(0, &drtioaux::Packet::EchoReply),
drtioaux::Packet::ResetRequest { phy } => {
if phy {
drtio_reset_phy(true);
drtio_reset_phy(false);
drtiosat_reset_phy(true);
drtiosat_reset_phy(false);
} else {
drtio_reset(true);
drtio_reset(false);
drtiosat_reset(true);
drtiosat_reset(false);
}
drtioaux::send_link(0, &drtioaux::Packet::ResetAck)
},
@ -198,7 +206,7 @@ fn process_aux_packets() {
}
}
fn process_errors() {
fn drtiosat_process_errors() {
let errors;
unsafe {
errors = csr::drtiosat::protocol_error_read();
@ -245,12 +253,6 @@ const SI5324_SETTINGS: si5324::FrequencySettings
crystal_ref: true
};
fn drtio_link_rx_up() -> bool {
unsafe {
csr::drtiosat::rx_up_read() == 1
}
}
const SIPHASER_PHASE: u16 = 32;
#[no_mangle]
@ -279,9 +281,21 @@ pub extern fn main() -> i32 {
#[cfg(has_allaki_atts)]
board_artiq::hmc542::program_all(8/*=4dB*/);
#[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
#[cfg(not(has_drtio_routing))]
let mut repeaters = [repeater::Repeater::default(); 0];
for i in 0..repeaters.len() {
repeaters[i] = repeater::Repeater::new(i as u8);
}
loop {
while !drtio_link_rx_up() {
process_errors();
while !drtiosat_link_rx_up() {
drtiosat_process_errors();
for mut rep in repeaters.iter_mut() {
rep.service();
}
}
info!("link is up, switching to recovered clock");
@ -308,13 +322,16 @@ pub extern fn main() -> i32 {
}
drtioaux::reset(0);
drtio_reset(false);
drtio_reset_phy(false);
drtiosat_reset(false);
drtiosat_reset_phy(false);
while drtio_link_rx_up() {
process_errors();
while drtiosat_link_rx_up() {
drtiosat_process_errors();
process_aux_packets();
if drtio_tsc_loaded() {
for mut rep in repeaters.iter_mut() {
rep.service();
}
if drtiosat_tsc_loaded() {
#[cfg(has_ad9154)]
{
if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() {
@ -333,9 +350,9 @@ pub extern fn main() -> i32 {
#[cfg(has_ad9154)]
board_artiq::ad9154::jesd_reset(true);
drtio_reset_phy(true);
drtio_reset(true);
drtio_tsc_loaded();
drtiosat_reset_phy(true);
drtiosat_reset(true);
drtiosat_tsc_loaded();
info!("link is down, switching to local crystal clock");
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
}

View File

@ -0,0 +1,104 @@
use board_misoc::{csr, clock};
use board_artiq::drtioaux;
#[cfg(has_drtio_routing)]
fn rep_link_rx_up(linkno: u8) -> bool {
let linkno = linkno as usize;
unsafe {
(csr::DRTIOREP[linkno].rx_up_read)() == 1
}
}
#[derive(Clone, Copy)]
enum RepeaterState {
Down,
SendPing { ping_count: u16 },
WaitPingReply { ping_count: u16, timeout: u64 },
Up,
Failed
}
impl Default for RepeaterState {
fn default() -> RepeaterState { RepeaterState::Down }
}
#[derive(Clone, Copy, Default)]
pub struct Repeater {
repno: u8,
auxno: u8,
state: RepeaterState
}
#[cfg(has_drtio_routing)]
impl Repeater {
pub fn new(repno: u8) -> Repeater {
Repeater {
repno: repno,
auxno: repno + 1,
state: RepeaterState::Down
}
}
pub fn service(&mut self) {
match self.state {
RepeaterState::Down => {
if rep_link_rx_up(self.repno) {
info!("[REP#{}] link RX became up, pinging", self.repno);
self.state = RepeaterState::SendPing { ping_count: 0 };
}
}
RepeaterState::SendPing { ping_count } => {
if rep_link_rx_up(self.repno) {
drtioaux::send_link(self.auxno, &drtioaux::Packet::EchoRequest).unwrap();
self.state = RepeaterState::WaitPingReply {
ping_count: ping_count + 1,
timeout: clock::get_ms() + 100
}
} else {
info!("[REP#{}] link RX went down during ping", self.repno);
self.state = RepeaterState::Down;
}
}
RepeaterState::WaitPingReply { ping_count, timeout } => {
if rep_link_rx_up(self.repno) {
if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) {
info!("[REP#{}] remote replied after {} packets", self.repno, ping_count);
// TODO: send TSC, routing table, and rank
self.state = RepeaterState::Up;
} else {
if clock::get_ms() > timeout {
if ping_count > 200 {
info!("[REP#{}] ping failed", self.repno);
self.state = RepeaterState::Failed;
} else {
self.state = RepeaterState::SendPing { ping_count: ping_count };
}
}
}
} else {
info!("[REP#{}] link RX went down during ping", self.repno);
self.state = RepeaterState::Down;
}
}
RepeaterState::Up => {
if !rep_link_rx_up(self.repno) {
info!("[REP#{}] link is down", self.repno);
self.state = RepeaterState::Down;
}
}
RepeaterState::Failed => {
if !rep_link_rx_up(self.repno) {
info!("[REP#{}] link is down", self.repno);
self.state = RepeaterState::Down;
}
}
}
}
}
#[cfg(not(has_drtio_routing))]
impl Repeater {
pub fn new(_repno: u8) -> Repeater { Repeater::default() }
pub fn service(&self) { }
}