mirror of https://github.com/m-labs/artiq.git
firmware: send DRTIO routing table to satellite
This commit is contained in:
parent
3d29a7ed14
commit
b38c57d73b
|
@ -5,11 +5,11 @@ pub const DEST_COUNT: usize = 256;
|
|||
pub const MAX_HOPS: usize = 32;
|
||||
pub const INVALID_HOP: u8 = 0xff;
|
||||
|
||||
pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]);
|
||||
pub struct RoutingTable(pub [[u8; MAX_HOPS]; DEST_COUNT]);
|
||||
|
||||
impl RoutingTable {
|
||||
// default routing table is for star topology with no hops
|
||||
fn default_master(default_n_links: usize) -> RoutingTable {
|
||||
pub fn default_master(default_n_links: usize) -> RoutingTable {
|
||||
let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]);
|
||||
for i in 0..default_n_links {
|
||||
ret.0[i][0] = i as u8;
|
||||
|
@ -20,9 +20,9 @@ impl RoutingTable {
|
|||
ret
|
||||
}
|
||||
|
||||
// satellites receive the routing table from the master
|
||||
// by default, block everything
|
||||
fn default_satellite() -> RoutingTable {
|
||||
// use this by default on satellite, as they receive
|
||||
// the routing table from the master
|
||||
pub fn default_empty() -> RoutingTable {
|
||||
RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT])
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable {
|
|||
ret
|
||||
}
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
pub fn program_interconnect(rt: &RoutingTable, rank: u8)
|
||||
{
|
||||
for i in 0..DEST_COUNT {
|
||||
|
|
|
@ -48,5 +48,4 @@ pub mod grabber;
|
|||
|
||||
#[cfg(has_drtio)]
|
||||
pub mod drtioaux;
|
||||
#[cfg(has_drtio_routing)]
|
||||
pub mod drtio_routing;
|
||||
|
|
|
@ -14,7 +14,7 @@ impl<T> From<IoError<T>> for Error<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Packet {
|
||||
EchoRequest,
|
||||
EchoReply,
|
||||
|
|
|
@ -25,6 +25,7 @@ extern crate board_artiq;
|
|||
extern crate logger_artiq;
|
||||
extern crate proto_artiq;
|
||||
|
||||
use core::cell::RefCell;
|
||||
use core::convert::TryFrom;
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
|
||||
|
||||
|
@ -282,14 +283,16 @@ fn startup_ethernet() {
|
|||
.finalize();
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
let drtio_routing_table = drtio_routing::config_routing_table(csr::DRTIO.len());
|
||||
#[cfg(has_drtio_routing)]
|
||||
drtio_routing::program_interconnect(&drtio_routing_table, 0);
|
||||
let drtio_routing_table = urc::Urc::new(RefCell::new(
|
||||
drtio_routing::config_routing_table(csr::DRTIO.len())));
|
||||
|
||||
let mut scheduler = sched::Scheduler::new();
|
||||
let io = scheduler.io();
|
||||
|
||||
rtio_mgt::startup(&io);
|
||||
#[cfg(has_drtio_routing)]
|
||||
rtio_mgt::startup(&io, &drtio_routing_table);
|
||||
#[cfg(not(has_drtio_routing))]
|
||||
rtio_mgt::startup(&io, &drtio_routing::RoutingTable::default_empty());
|
||||
|
||||
io.spawn(4096, mgmt::thread);
|
||||
io.spawn(16384, session::thread);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use board_misoc::csr;
|
||||
use core::cell::RefCell;
|
||||
use urc::Urc;
|
||||
use board_misoc::{csr, clock};
|
||||
#[cfg(has_rtio_clock_switch)]
|
||||
use board_misoc::config;
|
||||
use board_artiq::drtio_routing;
|
||||
use sched::Io;
|
||||
|
||||
#[cfg(has_rtio_crg)]
|
||||
|
@ -42,11 +45,15 @@ pub mod drtio {
|
|||
use super::*;
|
||||
use drtioaux;
|
||||
|
||||
pub fn startup(io: &Io) {
|
||||
pub fn startup(io: &Io, routing_table: &Urc<RefCell<drtio_routing::RoutingTable>>) {
|
||||
unsafe {
|
||||
csr::drtio_transceiver::stable_clkin_write(1);
|
||||
}
|
||||
io.spawn(4096, link_thread);
|
||||
let routing_table = routing_table.clone();
|
||||
io.spawn(4096, move |io| {
|
||||
let routing_table = routing_table.borrow();
|
||||
link_thread(io, &routing_table)
|
||||
});
|
||||
}
|
||||
|
||||
fn link_rx_up(linkno: u8) -> bool {
|
||||
|
@ -106,28 +113,51 @@ pub mod drtio {
|
|||
}
|
||||
}
|
||||
|
||||
fn sync_tsc(linkno: u8, io: &Io) -> Result<(), &'static str> {
|
||||
fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result<drtioaux::Packet, &'static str> {
|
||||
let max_time = clock::get_ms() + timeout as u64;
|
||||
loop {
|
||||
if !link_rx_up(linkno) {
|
||||
return Err("link went down");
|
||||
}
|
||||
if clock::get_ms() > max_time {
|
||||
return Err("timeout");
|
||||
}
|
||||
match drtioaux::recv_link(linkno) {
|
||||
Ok(Some(packet)) => return Ok(packet),
|
||||
Ok(None) => (),
|
||||
Err(_) => return Err("aux packet error")
|
||||
}
|
||||
io.relinquish().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn sync_tsc(io: &Io, linkno: u8) -> Result<(), &'static str> {
|
||||
unsafe {
|
||||
(csr::DRTIO[linkno as usize].set_time_write)(1);
|
||||
while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {}
|
||||
}
|
||||
// TSCAck is the only aux packet that is sent spontaneously
|
||||
// by the satellite, in response to a TSC set on the RT link.
|
||||
let reply = recv_aux_timeout(io, linkno, 10000)?;
|
||||
if reply == drtioaux::Packet::TSCAck {
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err("unexpected reply");
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut count = 0;
|
||||
if !link_rx_up(linkno) {
|
||||
return Err("link went down");
|
||||
}
|
||||
count += 1;
|
||||
if count > 200 {
|
||||
return Err("timeout");
|
||||
}
|
||||
io.sleep(100).unwrap();
|
||||
// TSCAck is the only aux packet that is sent spontaneously
|
||||
// by the satellite, in response to a TSC set on the RT link.
|
||||
if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(linkno) {
|
||||
return Ok(())
|
||||
fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> {
|
||||
for i in 0..drtio_routing::DEST_COUNT {
|
||||
drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath {
|
||||
destination: i as u8,
|
||||
hops: routing_table.0[i]
|
||||
}).unwrap();
|
||||
let reply = recv_aux_timeout(io, linkno, 200)?;
|
||||
if reply != drtioaux::Packet::RoutingAck {
|
||||
return Err("unexpected reply");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_local_errors(linkno: u8) {
|
||||
|
@ -166,7 +196,7 @@ pub mod drtio {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn link_thread(io: Io) {
|
||||
pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) {
|
||||
loop {
|
||||
for linkno in 0..csr::DRTIO.len() {
|
||||
let linkno = linkno as u8;
|
||||
|
@ -188,11 +218,13 @@ pub mod drtio {
|
|||
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
|
||||
set_link_up(linkno, true);
|
||||
init_buffer_space(linkno);
|
||||
if sync_tsc(linkno, &io).is_err() {
|
||||
error!("[LINK#{}] remote failed to ack TSC", linkno);
|
||||
} else {
|
||||
info!("[LINK#{}] link initialization completed", linkno);
|
||||
if let Err(e) = sync_tsc(&io, linkno) {
|
||||
error!("[LINK#{}] failed to sync TSC ({})", linkno, e);
|
||||
}
|
||||
if let Err(e) = load_routing_table(&io, linkno, routing_table) {
|
||||
error!("[LINK#{}] failed to load routing table ({})", linkno, e);
|
||||
}
|
||||
info!("[LINK#{}] link initialization completed", linkno);
|
||||
} else {
|
||||
error!("[LINK#{}] ping failed", linkno);
|
||||
}
|
||||
|
@ -223,7 +255,7 @@ pub mod drtio {
|
|||
pub mod drtio {
|
||||
use super::*;
|
||||
|
||||
pub fn startup(_io: &Io) {}
|
||||
pub fn startup(_io: &Io, _routing_table: &Urc<RefCell<drtio_routing::RoutingTable>>) {}
|
||||
pub fn init() {}
|
||||
pub fn link_up(_linkno: u8) -> bool { false }
|
||||
}
|
||||
|
@ -250,7 +282,7 @@ fn async_error_thread(io: Io) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn startup(io: &Io) {
|
||||
pub fn startup(io: &Io, routing_table: &Urc<RefCell<drtio_routing::RoutingTable>>) {
|
||||
#[cfg(has_rtio_crg)]
|
||||
{
|
||||
#[cfg(has_rtio_clock_switch)]
|
||||
|
@ -290,7 +322,13 @@ pub fn startup(io: &Io) {
|
|||
}
|
||||
}
|
||||
|
||||
drtio::startup(io);
|
||||
#[cfg(has_drtio_routing)]
|
||||
{
|
||||
let routing_table = routing_table.clone();
|
||||
drtio_routing::program_interconnect(&routing_table.borrow(), 0);
|
||||
}
|
||||
|
||||
drtio::startup(io, &routing_table);
|
||||
init_core(true);
|
||||
io.spawn(4096, async_error_thread);
|
||||
}
|
||||
|
|
|
@ -96,6 +96,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error<!>
|
|||
}
|
||||
}
|
||||
|
||||
drtioaux::Packet::RoutingSetPath { destination, hops } => {
|
||||
info!("routing: {} -> {:?}", destination, hops);
|
||||
drtioaux::send_link(0, &drtioaux::Packet::RoutingAck)
|
||||
}
|
||||
|
||||
drtioaux::Packet::MonitorRequest { channel, probe } => {
|
||||
let value;
|
||||
#[cfg(has_rtio_moninj)]
|
||||
|
@ -343,8 +348,8 @@ pub extern fn main() -> i32 {
|
|||
}
|
||||
}
|
||||
for rep in repeaters.iter() {
|
||||
if rep.sync_tsc().is_err() {
|
||||
error!("remote failed to ack TSC");
|
||||
if let Err(e) = rep.sync_tsc() {
|
||||
error!("failed to sync TSC ({})", e);
|
||||
}
|
||||
}
|
||||
if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) {
|
||||
|
|
|
@ -63,8 +63,8 @@ impl Repeater {
|
|||
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);
|
||||
if self.sync_tsc().is_err() {
|
||||
error!("[REP#{}] remote failed to ack TSC", self.repno);
|
||||
if let Err(e) = self.sync_tsc() {
|
||||
error!("[REP#{}] failed to sync TSC ({})", self.repno, e);
|
||||
self.state = RepeaterState::Failed;
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue