ksupport: move async error reporting to runtime

This commit is contained in:
2025-08-21 17:34:57 +08:00
parent 7f28167279
commit 54ce700fde
8 changed files with 91 additions and 134 deletions

View File

@@ -11,7 +11,6 @@ build_zynq = { path = "../libbuild_zynq" }
[dependencies]
cslice = "0.3"
log = "0.4"
nb = "0.1"
core_io = { git = "https://git.m-labs.hk/M-Labs/rs-core_io.git", rev = "e9d3edf027", features = ["collections"] }
byteorder = { version = "1.3", default-features = false }
void = { version = "1", default-features = false }

View File

@@ -14,7 +14,7 @@ use log::{debug, error, info};
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
KERNEL_IMAGE, Message, api::resolve, dma, rpc::rpc_send_async};
use crate::{eh_artiq, get_async_errors};
use crate::eh_artiq;
// linker symbols
extern "C" {
@@ -183,8 +183,7 @@ pub extern "C" fn main_core1() {
}
}
info!("kernel finished");
let async_errors = unsafe { get_async_errors() };
core1_tx.send(Message::KernelFinished(async_errors));
core1_tx.send(Message::KernelFinished);
}
_ => error!("Core1 received unexpected message: {:?}", message),
}
@@ -199,8 +198,7 @@ pub fn terminate(
) -> ! {
{
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
let errors = unsafe { get_async_errors() };
core1_tx.send(Message::KernelException(exceptions, stack_pointers, backtrace, errors));
core1_tx.send(Message::KernelException(exceptions, stack_pointers, backtrace));
}
loop {}
}

View File

@@ -45,12 +45,11 @@ pub enum Message {
LoadCompleted,
LoadFailed,
StartRequest,
KernelFinished(u8),
KernelFinished,
KernelException(
&'static [Option<eh_artiq::Exception<'static>>],
&'static [eh_artiq::StackPointerBacktrace],
&'static [(usize, usize)],
u8,
),
#[cfg(has_drtio)]

View File

@@ -8,13 +8,10 @@
#[macro_use]
extern crate alloc;
use libasync::block_async;
use log::error;
#[cfg(has_drtiosat)]
pub use pl::csr::drtiosat as rtio_core;
#[cfg(has_rtio_core)]
pub use pl::csr::rtio_core;
use void::Void;
pub mod eh_artiq;
pub mod irq;
@@ -34,117 +31,3 @@ pub struct RPCException {
pub column: i32,
pub function: u32,
}
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
pub unsafe fn get_async_errors() -> u8 {
let errors = SEEN_ASYNC_ERRORS;
SEEN_ASYNC_ERRORS = 0;
errors
}
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
unsafe {
#[cfg(has_rtio_core)]
let errors = rtio_core::async_error_read();
#[cfg(has_drtiosat)]
let errors = rtio_core::protocol_error_read();
if errors != 0 {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
pub async fn report_async_rtio_errors() {
loop {
let _ = block_async!(wait_for_async_rtio_error()).await;
unsafe {
#[cfg(has_rtio_core)]
let errors = rtio_core::async_error_read();
#[cfg(has_drtiosat)]
let errors = rtio_core::protocol_error_read();
if errors & ASYNC_ERROR_COLLISION != 0 {
let channel = rtio_core::collision_channel_read();
error!(
"RTIO collision involving channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
);
}
if errors & ASYNC_ERROR_BUSY != 0 {
let channel = rtio_core::busy_channel_read();
error!(
"RTIO busy error involving channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
);
}
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
let channel = rtio_core::sequence_error_channel_read();
error!(
"RTIO sequence error involving channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
);
}
SEEN_ASYNC_ERRORS = errors;
#[cfg(has_rtio_core)]
rtio_core::async_error_write(errors);
#[cfg(has_drtiosat)]
rtio_core::protocol_error_write(errors);
}
}
}
static RTIO_DEVICE_MAP: OnceLock<BTreeMap<u32, String>> = OnceLock::new();
fn read_device_map() -> BTreeMap<u32, String> {
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
let _ = libconfig::read("device_map")
.and_then(|raw_bytes| {
let mut bytes_cr = Cursor::new(raw_bytes);
let size = bytes_cr.read_u32::<NativeEndian>().unwrap();
for _ in 0..size {
let channel = bytes_cr.read_u32::<NativeEndian>().unwrap();
let device_name = bytes_cr.read_string::<NativeEndian>().unwrap();
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
warn!(
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
channel, old_entry, device_name
);
}
}
Ok(())
})
.or_else(|err| {
warn!(
"error reading device map ({}), device names will not be available in RTIO error messages",
err
);
Err(err)
});
device_map
}
pub fn resolve_channel_name(channel: u32) -> String {
match RTIO_DEVICE_MAP
.get()
.expect("cannot get device map before it is set up")
.get(&channel)
{
Some(val) => val.clone(),
None => String::from("unknown"),
}
}
pub fn setup_device_map() {
RTIO_DEVICE_MAP
.set(read_device_map())
.expect("device map can only be initialized once");
}

View File

@@ -28,6 +28,7 @@ futures = { version = "0.3", default-features = false, features = ["async-await"
async-recursion = "1.1"
log_buffer = { version = "1.2" }
vcell = "0.1"
nb = "0.1"
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq", features = ["ipv6", "async"]}
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }

View File

@@ -12,7 +12,8 @@ use io::Cursor;
use ksupport::kernel;
#[cfg(has_drtio)]
use ksupport::rpc;
use libasync::{smoltcp::{Sockets, TcpStream},
use libasync::{block_async,
smoltcp::{Sockets, TcpStream},
task};
#[cfg(has_drtio)]
use libboard_artiq::drtioaux::Packet;
@@ -35,10 +36,15 @@ use libcortex_a9::{mutex::Mutex,
use log::{error, info, warn};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
#[cfg(has_drtiosat)]
use pl::csr::drtiosat as rtio_core;
#[cfg(has_rtio_core)]
use pl::csr::rtio_core;
#[cfg(has_drtio)]
use tar_no_std::TarArchiveRef;
use void::Void;
#[cfg(has_drtio)]
#[cfg(any(has_rtio_core, has_drtiosat, has_drtio))]
use crate::pl;
use crate::{analyzer, mgmt, moninj, proto_async::*, rpc_async, rtio_dma, rtio_mgt};
#[cfg(has_drtio)]
@@ -117,6 +123,73 @@ enum Reply {
ClockFailure = 15,
}
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
pub unsafe fn get_async_errors() -> u8 {
let errors = SEEN_ASYNC_ERRORS;
SEEN_ASYNC_ERRORS = 0;
errors
}
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
unsafe {
#[cfg(has_rtio_core)]
let errors = rtio_core::async_error_read();
#[cfg(has_drtiosat)]
let errors = rtio_core::protocol_error_read();
if errors != 0 {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
pub async fn report_async_rtio_errors() {
loop {
let _ = block_async!(wait_for_async_rtio_error()).await;
unsafe {
#[cfg(has_rtio_core)]
let errors = rtio_core::async_error_read();
#[cfg(has_drtiosat)]
let errors = rtio_core::protocol_error_read();
if errors & ASYNC_ERROR_COLLISION != 0 {
let channel = rtio_core::collision_channel_read();
error!(
"RTIO collision involving channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
);
}
if errors & ASYNC_ERROR_BUSY != 0 {
let channel = rtio_core::busy_channel_read();
error!(
"RTIO busy error involving channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
);
}
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
let channel = rtio_core::sequence_error_channel_read();
error!(
"RTIO sequence error involving channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
);
}
SEEN_ASYNC_ERRORS = errors;
#[cfg(has_rtio_core)]
rtio_core::async_error_write(errors);
#[cfg(has_drtiosat)]
rtio_core::protocol_error_write(errors);
}
}
}
static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new());
pub static RESTART_IDLE: Semaphore = Semaphore::new(1, 1);
@@ -286,14 +359,16 @@ async fn handle_run_kernel(
}
}
}
kernel::Message::KernelFinished(async_errors) => {
kernel::Message::KernelFinished => {
let async_errors = unsafe { get_async_errors() };
if let Some(stream) = stream {
write_header(stream, Reply::KernelFinished).await?;
write_i8(stream, async_errors as i8).await?;
}
break;
}
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
kernel::Message::KernelException(exceptions, stack_pointers, backtrace) => {
let async_errors = unsafe { get_async_errors() };
match stream {
Some(stream) => {
// only send the exception data to host if there is host,
@@ -993,6 +1068,7 @@ pub fn main() {
#[cfg(has_drtio_routing)]
drtio_routing::interconnect_disable_all();
task::spawn(report_async_rtio_errors());
rtio_mgt::startup(&up_destinations);
libboard_artiq::setup_device_map();

View File

@@ -143,8 +143,6 @@ pub fn main_core0() {
#[cfg(has_grabber)]
task::spawn(grabber::grabber_thread());
task::spawn(ksupport::report_async_rtio_errors());
#[cfg(has_cxp_grabber)]
{
cxp_phys::setup();

View File

@@ -10,8 +10,7 @@ pub mod drtio {
use alloc::vec::Vec;
use core::fmt;
use ksupport::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS,
kernel::Message as KernelMessage};
use ksupport::kernel::Message as KernelMessage;
use libasync::task;
#[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem;
@@ -25,7 +24,11 @@ pub mod drtio {
use log::{error, info, warn};
use super::*;
use crate::{analyzer::remote_analyzer::RemoteBuffer, comms::ROUTING_TABLE, rtio_dma::remote_dma, subkernel};
use crate::{analyzer::remote_analyzer::RemoteBuffer,
comms::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, ROUTING_TABLE,
SEEN_ASYNC_ERRORS},
rtio_dma::remote_dma,
subkernel};
#[cfg(has_drtio_eem)]
const DRTIO_EEM_LINKNOS: core::ops::Range<usize> =