From c8cd830118c04953474bdb60ef31e191a7c854cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 19:11:22 +0800 Subject: [PATCH] drtio: implement get_rtio_destination_status for kernels --- artiq/coredevice/core.py | 12 ++-- .../repository/sines_2sayma.py | 6 +- .../repository/sines_urukul_sayma.py | 4 +- .../sayma_masterdac/repository/sines_drtio.py | 2 +- artiq/firmware/ksupport/api.rs | 3 +- artiq/firmware/ksupport/rtio.rs | 21 +++--- artiq/firmware/libproto_artiq/kernel_proto.rs | 6 +- artiq/firmware/runtime/kern_hwreq.rs | 18 +++-- artiq/firmware/runtime/main.rs | 7 +- artiq/firmware/runtime/rtio_mgt.rs | 69 +++++++++++-------- artiq/firmware/runtime/session.rs | 32 ++++++--- doc/manual/installing.rst | 2 +- 12 files changed, 110 insertions(+), 72 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 9f84efe60..4c33fd266 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -44,11 +44,11 @@ def rtio_init() -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def rtio_get_counter() -> TInt64: +def rtio_get_destination_status(linkno: TInt32) -> TBool: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def drtio_get_link_status(linkno: TInt32) -> TBool: +def rtio_get_counter() -> TInt64: raise NotImplementedError("syscall not simulated") @@ -154,12 +154,12 @@ class Core: return rtio_get_counter() @kernel - def get_drtio_link_status(self, linkno): - """Returns whether the specified DRTIO link is up. + def get_rtio_destination_status(self, destination): + """Returns whether the specified RTIO destination is up. This is particularly useful in startup kernels to delay - startup until certain DRTIO links are up.""" - return drtio_get_link_status(linkno) + startup until certain DRTIO destinations are up.""" + return rtio_get_destination_status(destination) @kernel def reset(self): diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py index 9b8e4d661..b6bc7884c 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py @@ -10,8 +10,8 @@ class Sines2Sayma(EnvExperiment): def run(self): while True: print("waiting for DRTIO ready...") - while not (self.core.get_drtio_link_status(0) and - self.core.get_drtio_link_status(1)): + while not (self.core.get_rtio_destination_status(0) and + self.core.get_rtio_destination_status(1)): pass print("OK") @@ -27,5 +27,5 @@ class Sines2Sayma(EnvExperiment): # Do not use a sub-multiple of oscilloscope sample rates. sawg.frequency0.set(9*MHz) - while self.core.get_drtio_link_status(0) and self.core.get_drtio_link_status(1): + while self.core.get_rtio_destination_status(0) and self.core.get_rtio_destination_status(1): pass diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 318a6e1ab..9b9ab68de 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -23,7 +23,7 @@ class SinesUrukulSayma(EnvExperiment): while True: print("waiting for DRTIO ready...") - while not self.core.get_drtio_link_status(0): + while not self.core.get_rtio_destination_status(0): pass print("OK") @@ -38,5 +38,5 @@ class SinesUrukulSayma(EnvExperiment): sawg.amplitude1.set(.4) sawg.frequency0.set(9*MHz) - while self.core.get_drtio_link_status(0): + while self.core.get_rtio_destination_status(0): pass diff --git a/artiq/examples/sayma_masterdac/repository/sines_drtio.py b/artiq/examples/sayma_masterdac/repository/sines_drtio.py index 7f242e4b8..70a7b3484 100644 --- a/artiq/examples/sayma_masterdac/repository/sines_drtio.py +++ b/artiq/examples/sayma_masterdac/repository/sines_drtio.py @@ -10,7 +10,7 @@ class SAWGTestDRTIO(EnvExperiment): @kernel def run(self): core_log("waiting for DRTIO ready...") - while not self.core.get_drtio_link_status(0): + while not self.core.get_rtio_destination_status(0): pass core_log("OK") diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index c1a0c22ff..be616256f 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -95,6 +95,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* direct syscalls */ api!(rtio_init = ::rtio::init), + api!(rtio_get_destination_status = ::rtio::get_destination_status), api!(rtio_get_counter = ::rtio::get_counter), api!(rtio_log), api!(rtio_output = ::rtio::output), @@ -108,8 +109,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_retrieve = ::dma_retrieve), api!(dma_playback = ::dma_playback), - api!(drtio_get_link_status = ::rtio::drtio::get_link_status), - api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), api!(i2c_stop = ::nrt_bus::i2c::stop), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index e0368b593..1324c0353 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -5,6 +5,7 @@ mod imp { use board_misoc::csr; use ::send; + use ::recv; use kernel_proto::*; pub const RTIO_O_STATUS_WAIT: u8 = 1; @@ -19,6 +20,15 @@ mod imp { send(&RtioInitRequest); } + pub extern fn get_destination_status(destination: i32) -> bool { + if 0 <= destination && destination <= 255 { + send(&RtioDestinationStatusRequest { destination: destination as u8 }); + recv!(&RtioDestinationStatusReply { up } => up) + } else { + false + } + } + pub extern fn get_counter() -> i64 { unsafe { csr::rtio::counter_update_write(1); @@ -209,14 +219,3 @@ mod imp { } pub use self::imp::*; - -pub mod drtio { - use ::send; - use ::recv; - use kernel_proto::*; - - pub extern fn get_link_status(linkno: i32) -> bool { - send(&DrtioLinkStatusRequest { linkno: linkno as u8 }); - recv!(&DrtioLinkStatusReply { up } => up) - } -} diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 477c00a1b..73c9e2765 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -28,6 +28,9 @@ pub enum Message<'a> { RtioInitRequest, + RtioDestinationStatusRequest { destination: u8 }, + RtioDestinationStatusReply { up: bool }, + DmaRecordStart(&'a str), DmaRecordAppend(&'a [u8]), DmaRecordStop { @@ -46,9 +49,6 @@ pub enum Message<'a> { duration: u64 }, - DrtioLinkStatusRequest { linkno: u8 }, - DrtioLinkStatusReply { up: bool }, - RunFinished, RunException { exception: Exception<'a>, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 7a9ce6061..631209923 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,7 +1,9 @@ +use core::cell::RefCell; use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; +use urc::Urc; use board_artiq::drtio_routing; use board_artiq::i2c as local_i2c; use board_artiq::spi as local_spi; @@ -203,7 +205,9 @@ macro_rules! dispatch { }} } -pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, +pub fn process_kern_hwreq(io: &Io, + _routing_table: &drtio_routing::RoutingTable, + _up_destinations: &Urc>, request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { @@ -212,9 +216,15 @@ pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, kern_acknowledge() } - &kern::DrtioLinkStatusRequest { linkno } => { - let up = rtio_mgt::drtio::link_up(linkno); - kern_send(io, &kern::DrtioLinkStatusReply { up: up }) + &kern::RtioDestinationStatusRequest { destination: _destination } => { + #[cfg(has_drtio)] + let up = { + let up_destinations = _up_destinations.borrow(); + up_destinations[_destination as usize] + }; + #[cfg(not(has_drtio))] + let up = true; + kern_send(io, &kern::RtioDestinationStatusReply { up: up }) } &kern::I2cStartRequest { busno } => { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6ecf79dd0..fe7a26d91 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -287,16 +287,19 @@ fn startup_ethernet() { #[cfg(not(has_drtio))] let drtio_routing_table = urc::Urc::new(RefCell::new( drtio_routing::RoutingTable::default_empty())); + let up_destinations = urc::Urc::new(RefCell::new( + [false; drtio_routing::DEST_COUNT])); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io, &drtio_routing_table); + rtio_mgt::startup(&io, &drtio_routing_table, &up_destinations); io.spawn(4096, mgmt::thread); { let drtio_routing_table = drtio_routing_table.clone(); - io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table) }); + let up_destinations = up_destinations.clone(); + io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table, &up_destinations) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 042db050f..e3688fb57 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -47,14 +47,16 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io, routing_table: &Urc>) { + pub fn startup(io: &Io, routing_table: &Urc>, + up_destinations: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); io.spawn(4096, move |io| { let routing_table = routing_table.borrow(); - link_thread(io, &routing_table) + link_thread(io, &routing_table, &up_destinations); }); } @@ -206,31 +208,46 @@ pub mod drtio { } } + fn destination_set_up(routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, + destination: u8, up: bool) { + let mut up_destinations = up_destinations.borrow_mut(); + up_destinations[destination as usize] = up; + if up { + drtio_routing::interconnect_enable(routing_table, 0, destination); + info!("[DEST#{}] destination is up", destination); + } else { + drtio_routing::interconnect_disable(destination); + info!("[DEST#{}] destination is down", destination); + } + } + + fn destination_up(up_destinations: &Urc>, destination: u8) -> bool { + let up_destinations = up_destinations.borrow(); + up_destinations[destination as usize] + } + fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, - up_destinations: &mut [bool; drtio_routing::DEST_COUNT]) { + up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; + let destination = destination as u8; if hop == 0 { /* local RTIO */ - if !up_destinations[destination] { - info!("[DEST#{}] destination is up", destination); - up_destinations[destination] = true; - drtio_routing::interconnect_enable(routing_table, 0, destination as u8); + if !destination_up(up_destinations, destination) { + destination_set_up(routing_table, up_destinations, destination, true); } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; - if up_destinations[destination] { + if destination_up(up_destinations, destination) { if link_up(linkno) { drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { - destination: destination as u8 + destination: destination }).unwrap(); match recv_aux_timeout(io, linkno, 200) { - Ok(drtioaux::Packet::DestinationDownReply) => { - info!("[DEST#{}] destination is down", destination); - up_destinations[destination] = false; - drtio_routing::interconnect_disable(destination as u8); - }, + Ok(drtioaux::Packet::DestinationDownReply) => + destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel), @@ -242,21 +259,17 @@ pub mod drtio { Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) } } else { - info!("[DEST#{}] destination is down", destination); - up_destinations[destination] = false; - drtio_routing::interconnect_disable(destination as u8); + destination_set_up(routing_table, up_destinations, destination, false); } } else { if link_up(linkno) { drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { - destination: destination as u8 + destination: destination }).unwrap(); match recv_aux_timeout(io, linkno, 200) { Ok(drtioaux::Packet::DestinationDownReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => { - info!("[DEST#{}] destination is up", destination); - up_destinations[destination] = true; - drtio_routing::interconnect_enable(routing_table, 0, destination as u8); + destination_set_up(routing_table, up_destinations, destination, true); init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -268,8 +281,8 @@ pub mod drtio { } } - pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { - let mut up_destinations = [false; drtio_routing::DEST_COUNT]; + pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>) { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -306,7 +319,7 @@ pub mod drtio { } } } - destination_survey(&io, routing_table, &mut up_destinations); + destination_survey(&io, routing_table, up_destinations); io.sleep(200).unwrap(); } } @@ -331,7 +344,8 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io, _routing_table: &Urc>) {} + pub fn startup(_io: &Io, _routing_table: &Urc>, + _up_destinations: &Urc>) {} pub fn init() {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -358,7 +372,8 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io, routing_table: &Urc>) { +pub fn startup(io: &Io, routing_table: &Urc>, + up_destinations: &Urc>) { #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -398,7 +413,7 @@ pub fn startup(io: &Io, routing_table: &Urc } } - drtio::startup(io, &routing_table); + drtio::startup(io, routing_table, up_destinations); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 4c081810e..e413e8749 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -324,7 +324,9 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn process_kern_message(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { @@ -343,7 +345,7 @@ fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, routing_table, request)? { + if kern_hwreq::process_kern_hwreq(io, routing_table, up_destinations, request)? { return Ok(false) } @@ -492,7 +494,9 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn host_kernel_worker(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -509,7 +513,9 @@ fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } if mailbox::receive() != 0 { - process_kern_message(io, routing_table, Some(stream), &mut session)?; + process_kern_message(io, + routing_table, up_destinations, + Some(stream), &mut session)?; } if session.kernel_state == KernelState::Running { @@ -528,7 +534,9 @@ fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } } -fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn flash_kernel_worker(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -551,7 +559,7 @@ fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } if mailbox::receive() != 0 { - if process_kern_message(io, routing_table, None, &mut session)? { + if process_kern_message(io, routing_table, up_destinations, None, &mut session)? { return Ok(()) } } @@ -583,7 +591,8 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io, routing_table: &Urc>) { +pub fn thread(io: Io, routing_table: &Urc>, + up_destinations: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -593,12 +602,13 @@ pub fn thread(io: Io, routing_table: &Urc>) let mut kernel_thread = None; { let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &routing_table, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -628,13 +638,14 @@ pub fn thread(io: Io, routing_table: &Urc>) info!("new connection from {}", stream.remote_endpoint()); let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &routing_table, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &routing_table, &up_destinations, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -653,11 +664,12 @@ pub fn thread(io: Io, routing_table: &Urc>) info!("no connection, starting idle kernel"); let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &routing_table, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 05a761493..5030d63d1 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -190,7 +190,7 @@ To flash the idle kernel: The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in the ``artiq_coremgmt`` command. -For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. +For DRTIO systems, the startup kernel should wait until the desired destinations (including local RTIO) are up, using :meth:`artiq.coredevice.Core.get_rtio_destination_status`. * (optional) Select the RTIO clock source