From 432e61bbb450185fb64d15ce6c078e3425a3f861 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 5 Mar 2018 00:23:55 +0800 Subject: [PATCH] drtio: add kernel API to check for link status. Closes #941 --- artiq/coredevice/core.py | 12 ++++++++++++ artiq/firmware/ksupport/api.rs | 5 +++-- artiq/firmware/ksupport/rtio.rs | 7 ++++++- artiq/firmware/libproto/kernel_proto.rs | 3 +++ artiq/firmware/runtime/kern_hwreq.rs | 5 +++++ artiq/firmware/runtime/rtio_mgt.rs | 9 ++++++++- doc/manual/installing.rst | 2 ++ 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 8f96bb7c9..300085882 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -47,6 +47,10 @@ def rtio_init() -> TNone: def rtio_get_counter() -> TInt64: raise NotImplementedError("syscall not simulated") +@syscall(flags={"nounwind", "nowrite"}) +def drtio_get_link_status(linkno: TInt32) -> TBool: + raise NotImplementedError("syscall not simulated") + class Core: """Core device driver. @@ -155,6 +159,14 @@ class Core: def get_rtio_counter_mu(self): return rtio_get_counter() + @kernel + def get_drtio_link_status(self, linkno): + """Returns whether the specified DRTIO link is up. + + This is particularly useful in startup kernels to delay + startup until certain DRTIO links are up.""" + return drtio_get_link_status(linkno) + @kernel def reset(self): """Clear RTIO FIFOs, release RTIO PHY reset, and set the time cursor diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index b2d608b1f..75b8b928b 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -108,8 +108,9 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_retrieve = ::dma_retrieve), api!(dma_playback = ::dma_playback), - api!(drtio_get_packet_counts = ::rtio::drtio_dbg::get_packet_counts), - api!(drtio_get_buffer_space_req_count = ::rtio::drtio_dbg::get_buffer_space_req_count), + api!(drtio_get_link_status = ::rtio::drtio::get_link_status), + api!(drtio_get_packet_counts = ::rtio::drtio::get_packet_counts), + api!(drtio_get_buffer_space_req_count = ::rtio::drtio::get_buffer_space_req_count), api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 7af22169c..a3afb6d79 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -210,11 +210,16 @@ mod imp { pub use self::imp::*; -pub mod drtio_dbg { +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) + } + #[repr(C)] pub struct PacketCounts(i32, i32); diff --git a/artiq/firmware/libproto/kernel_proto.rs b/artiq/firmware/libproto/kernel_proto.rs index babd9fbcf..ae794ec34 100644 --- a/artiq/firmware/libproto/kernel_proto.rs +++ b/artiq/firmware/libproto/kernel_proto.rs @@ -46,6 +46,9 @@ pub enum Message<'a> { duration: u64 }, + DrtioLinkStatusRequest { linkno: u8 }, + DrtioLinkStatusReply { up: bool }, + DrtioPacketCountRequest { linkno: u8 }, DrtioPacketCountReply { tx_cnt: u32, rx_cnt: u32 }, DrtioBufferSpaceReqCountRequest { linkno: u8 }, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index be1a380e8..b3f77f567 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -300,6 +300,11 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result kern_acknowledge() } + #[cfg(has_rtio_core)] + &kern::DrtioLinkStatusRequest { linkno } => { + let up = rtio_mgt::drtio::link_up(linkno); + kern_send(io, &kern::DrtioLinkStatusReply { up: up }) + } #[cfg(has_rtio_core)] &kern::DrtioPacketCountRequest { linkno } => { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 490535fee..279c9c865 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,8 +54,14 @@ pub mod drtio { } } - fn link_up(linkno: u8) -> bool { + pub fn link_up(linkno: u8) -> bool { let linkno = linkno as usize; + /* This function may be called by kernels with arbitrary + * linkno values. + */ + if linkno >= csr::DRTIO.len() { + return false; + } unsafe { (csr::DRTIO[linkno].link_up_read)() == 1 } @@ -195,6 +201,7 @@ mod drtio { pub fn startup(_io: &Io) {} pub fn init() {} + pub fn link_up(_linkno: u8) -> bool { false } } fn async_error_thread(io: Io) { diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index e9a82226c..574af6ac8 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -187,6 +187,8 @@ 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 ``artiq_coreconfig``. +For DRTIO systems, the startup kernel should wait until the desired links are up, using :method:`artiq.coredevice.Core.get_drtio_link_status`. + * (optional) Select the startup clock The core device may use either an external clock signal or its internal clock. This clock can be switched dynamically after the PC is connected using the ``external_clock`` parameter of the core device driver; however, one may want to select the clock at power-up so that it is used for the startup and idle kernels. Use one of these commands: ::