diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c7e7fb73e..d53dca4f0 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -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"); } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs new file mode 100644 index 000000000..aabd0e3a7 --- /dev/null +++ b/artiq/firmware/satman/repeater.rs @@ -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) { } +}