Soft panic for RTIO PLL reasons #199

Merged
sb10q merged 16 commits from mwojcik/artiq-zynq:pll_error into master 2022-10-21 17:56:34 +08:00
4 changed files with 113 additions and 13 deletions

View File

@ -22,6 +22,8 @@ use futures::{select_biased, future::FutureExt};
use libasync::{smoltcp::{Sockets, TcpStream}, task}; use libasync::{smoltcp::{Sockets, TcpStream}, task};
use libconfig::{Config, net_settings}; use libconfig::{Config, net_settings};
use libboard_artiq::drtio_routing; use libboard_artiq::drtio_routing;
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use crate::proto_async::*; use crate::proto_async::*;
use crate::kernel; use crate::kernel;
@ -490,3 +492,61 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
Instant::from_millis(timer.get_time().0 as i32) Instant::from_millis(timer.get_time().0 as i32)
}); });
} }
pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
let net_addresses = net_settings::get_addresses(&cfg);
info!("network addresses: {}", net_addresses);
let eth = zynq::eth::Eth::eth0(net_addresses.hardware_addr.0.clone());
const RX_LEN: usize = 64;
// Number of transmission buffers (minimum is two because with
// one, duplicate packet transmission occurs)
const TX_LEN: usize = 64;
let eth = eth.start_rx(RX_LEN);
let mut eth = eth.start_tx(TX_LEN);
let neighbor_cache = NeighborCache::new(alloc::collections::BTreeMap::new());
let mut iface = match net_addresses.ipv6_addr {
Some(addr) => {
let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
IpCidr::new(addr, 0)
];
EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)
.finalize()
}
None => {
let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0)
];
EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)
.finalize()
}
};
Sockets::init(32);
mgmt::start(cfg);
// getting eth settings disables the LED as it resets GPIO
// need to re-enable it here
#[cfg(feature = "target_kasli_soc")]
{
let mut err_led = ErrorLED::error_led();
Outdated
Review

Why does it disable the LED?

Why does it disable the LED?

getting eth settings sets up I2C to communicate with the ethernet controller;

I2C setup also resets GPIO:
https://git.m-labs.hk/M-Labs/zynq-rs/src/branch/master/libboard_zynq/src/i2c/mod.rs#L57

and I2C GPIO (MIO 33, 50, 51) is in the same bank as the error led (MIO 37); so resetting the entire port again causes the LED to go off.

getting eth settings sets up I2C to communicate with the ethernet controller; I2C setup also resets GPIO: https://git.m-labs.hk/M-Labs/zynq-rs/src/branch/master/libboard_zynq/src/i2c/mod.rs#L57 and I2C GPIO (MIO 33, 50, 51) is in the same bank as the error led (MIO 37); so resetting the entire port again causes the LED to go off.
Outdated
Review

Okay I see. Maybe make the comment a bit more clear (e.g. "we reinitialized the GPIO controller, so only now can we turn on the error LED")
Also, the non-mgmt panic handler should also turn on the LED to make sure.

Okay I see. Maybe make the comment a bit more clear (e.g. "we reinitialized the GPIO controller, so only now can we turn on the error LED") Also, the non-mgmt panic handler should also turn on the LED to make sure.
err_led.toggle(true);
}
Sockets::run(&mut iface, || {
Instant::from_millis(timer.get_time().0 as i32)
});
}

View File

@ -222,12 +222,15 @@ extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32
if &__text_start as *const u32 <= pc && pc < &__text_end as *const u32 { if &__text_start as *const u32 <= pc && pc < &__text_end as *const u32 {
length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32; length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32;
start = &__exidx_start; start = &__exidx_start;
} else { } else if KERNEL_IMAGE != ptr::null() {
let exidx = KERNEL_IMAGE.as_ref() let exidx = KERNEL_IMAGE.as_ref()
.expect("dl_unwind_find_exidx kernel image") .expect("dl_unwind_find_exidx kernel image")
.library.get().as_ref().unwrap().exidx(); .library.get().as_ref().unwrap().exidx();
length = exidx.len() as u32; length = exidx.len() as u32;
start = exidx.as_ptr(); start = exidx.as_ptr();
} else {
length = 0;
start = ptr::null();
} }
*len_ptr = length; *len_ptr = length;
} }

View File

@ -3,20 +3,21 @@ use libregister::RegisterR;
use libcortex_a9::regs::MPIDR; use libcortex_a9::regs::MPIDR;
use unwind::backtrace; use unwind::backtrace;
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use crate::comms::soft_panic_main;
use log::error;
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config;
static mut PANICKED: [bool; 2] = [false; 2]; static mut PANICKED: [bool; 2] = [false; 2];
static mut SOFT_PANICKED: bool = false;
#[panic_handler] #[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! { fn panic(info: &core::panic::PanicInfo) -> ! {
let id = MPIDR.read().cpu_id() as usize; let id = MPIDR.read().cpu_id() as usize;
print!("Core {} ", id); let soft_panicked = unsafe { SOFT_PANICKED };
unsafe { print!("Core {} panic at ", id);
if PANICKED[id] {
println!("nested panic!");
loop {}
}
PANICKED[id] = true;
}
print!("panic at ");
if let Some(location) = info.location() { if let Some(location) = info.location() {
print!("{}:{}:{}", location.file(), location.line(), location.column()); print!("{}:{}:{}", location.file(), location.line(), location.column());
} else { } else {
@ -27,6 +28,20 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
} else { } else {
println!(""); println!("");
} }
unsafe {
// soft panics only allowed for core 0
if PANICKED[id] && (SOFT_PANICKED || id == 1) {
println!("nested panic!");
loop {}
}
SOFT_PANICKED = true;
PANICKED[id] = true;
}
#[cfg(feature = "target_kasli_soc")]
{
let mut err_led = ErrorLED::error_led();
err_led.toggle(true);
}
println!("Backtrace: "); println!("Backtrace: ");
let _ = backtrace(|ip| { let _ = backtrace(|ip| {
// Backtrace gives us the return address, i.e. the address after the delay slot, // Backtrace gives us the return address, i.e. the address after the delay slot,
@ -34,6 +49,28 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
print!("{:#08x} ", ip - 2 * 4); print!("{:#08x} ", ip - 2 * 4);
}); });
println!("\nEnd backtrace"); println!("\nEnd backtrace");
if !soft_panicked && id == 0 {
soft_panic(info);
}
loop {} loop {}
} }
fn soft_panic(info: &core::panic::PanicInfo) -> ! {
// write panic info to log, so coremgmt can also read it
Outdated
Review

Had to read that twice...

Maybe reformulate along the lines:
"Write panic info to the log, so that coremgmt can see it"

Had to read that twice... Maybe reformulate along the lines: "Write panic info to the log, so that coremgmt can see it"
if let Some(location) = info.location() {
error!("panic at {}:{}:{}", location.file(), location.line(), location.column());
} else {
error!("panic at unknown location");
}
if let Some(message) = info.message() {
error!("panic message: {}", message);
}
let timer = GlobalTimer::start();
let cfg = match Config::new() {
Ok(cfg) => cfg,
Err(_) => {
Config::new_dummy()
}
};
soft_panic_main(timer, cfg);
}

View File

@ -1,4 +1,4 @@
use log::{info, warn, error}; use log::{info, warn};
use libboard_zynq::timer::GlobalTimer; use libboard_zynq::timer::GlobalTimer;
use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::delay::DelayMs;
use libconfig::Config; use libconfig::Config;
@ -95,7 +95,7 @@ fn init_rtio(timer: &mut GlobalTimer, _clk: RtioClock) {
if locked { if locked {
info!("RTIO PLL locked"); info!("RTIO PLL locked");
} else { } else {
error!("RTIO PLL failed to lock"); panic!("RTIO PLL failed to lock");
} }
unsafe { unsafe {