forked from M-Labs/artiq-zynq
satman: implement cfg/mgmt operations
This commit is contained in:
parent
873dd86b4d
commit
0c3474f5b5
|
@ -38,16 +38,18 @@ use libboard_artiq::{drtio_routing, drtioaux,
|
||||||
pl::csr};
|
pl::csr};
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
use libboard_zynq::error_led::ErrorLED;
|
use libboard_zynq::error_led::ErrorLED;
|
||||||
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
|
use libboard_zynq::{i2c::I2c, print, println, slcr, time::Milliseconds, timer::GlobalTimer};
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
|
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
|
||||||
use libregister::RegisterR;
|
use libregister::RegisterR;
|
||||||
use libsupport_zynq::{exception_vectors, ram};
|
use libsupport_zynq::{exception_vectors, ram};
|
||||||
|
use mgmt::Manager as CoreManager;
|
||||||
use routing::Router;
|
use routing::Router;
|
||||||
use subkernel::Manager as KernelManager;
|
use subkernel::Manager as KernelManager;
|
||||||
|
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
mod dma;
|
mod dma;
|
||||||
|
mod mgmt;
|
||||||
mod repeater;
|
mod repeater;
|
||||||
mod routing;
|
mod routing;
|
||||||
mod subkernel;
|
mod subkernel;
|
||||||
|
@ -149,6 +151,7 @@ fn process_aux_packet(
|
||||||
dma_manager: &mut DmaManager,
|
dma_manager: &mut DmaManager,
|
||||||
analyzer: &mut Analyzer,
|
analyzer: &mut Analyzer,
|
||||||
kernel_manager: &mut KernelManager,
|
kernel_manager: &mut KernelManager,
|
||||||
|
core_manager: &mut CoreManager,
|
||||||
router: &mut Router,
|
router: &mut Router,
|
||||||
) -> Result<(), drtioaux::Error> {
|
) -> Result<(), drtioaux::Error> {
|
||||||
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
||||||
|
@ -1010,6 +1013,279 @@ fn process_aux_packet(
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtGetLogRequest {
|
||||||
|
destination: _destination,
|
||||||
|
clear,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
let mut data_slice = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||||
|
let meta = core_manager.log_get_slice(&mut data_slice);
|
||||||
|
if clear && meta.status.is_first() {
|
||||||
|
mgmt::clear_log();
|
||||||
|
}
|
||||||
|
drtioaux::send(
|
||||||
|
0,
|
||||||
|
&drtioaux::Packet::CoreMgmtGetLogReply {
|
||||||
|
last: meta.status.is_last(),
|
||||||
|
length: meta.len as u16,
|
||||||
|
data: data_slice,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtClearLogRequest {
|
||||||
|
destination: _destination,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
mgmt::clear_log();
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtSetLogLevelRequest {
|
||||||
|
destination: _destination,
|
||||||
|
log_level,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
|
||||||
|
info!("Changing log level to {}", level_filter);
|
||||||
|
log::set_max_level(level_filter);
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)
|
||||||
|
} else {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtSetUartLogLevelRequest {
|
||||||
|
destination: _destination,
|
||||||
|
log_level,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
|
||||||
|
info!("Changing log level to {}", level_filter);
|
||||||
|
unsafe {
|
||||||
|
logger::BufferLogger::get_logger()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.set_uart_log_level(level_filter);
|
||||||
|
}
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)
|
||||||
|
} else {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtConfigReadRequest {
|
||||||
|
destination: _destination,
|
||||||
|
length,
|
||||||
|
key,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||||
|
|
||||||
|
let key_slice = &key[..length as usize];
|
||||||
|
if !key_slice.is_ascii() {
|
||||||
|
error!("invalid key");
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
} else {
|
||||||
|
let key = core::str::from_utf8(key_slice).unwrap();
|
||||||
|
if core_manager.fetch_config_value(key).is_ok() {
|
||||||
|
let meta = core_manager.get_config_value_slice(&mut value_slice);
|
||||||
|
drtioaux::send(
|
||||||
|
0,
|
||||||
|
&drtioaux::Packet::CoreMgmtConfigReadReply {
|
||||||
|
last: meta.status.is_last(),
|
||||||
|
length: meta.len as u16,
|
||||||
|
value: value_slice,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtConfigReadContinue {
|
||||||
|
destination: _destination,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||||
|
let meta = core_manager.get_config_value_slice(&mut value_slice);
|
||||||
|
drtioaux::send(
|
||||||
|
0,
|
||||||
|
&drtioaux::Packet::CoreMgmtConfigReadReply {
|
||||||
|
last: meta.status.is_last(),
|
||||||
|
length: meta.len as u16,
|
||||||
|
value: value_slice,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtConfigWriteRequest {
|
||||||
|
destination: _destination,
|
||||||
|
last,
|
||||||
|
length,
|
||||||
|
data,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
core_manager.add_data(&data, length as usize);
|
||||||
|
|
||||||
|
let mut succeeded = true;
|
||||||
|
if last {
|
||||||
|
succeeded = core_manager.write_config().is_ok();
|
||||||
|
core_manager.clear_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
if succeeded {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)
|
||||||
|
} else {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtConfigRemoveRequest {
|
||||||
|
destination: _destination,
|
||||||
|
length,
|
||||||
|
key,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
let key_slice = &key[..length as usize];
|
||||||
|
if !key_slice.is_ascii() {
|
||||||
|
error!("invalid key");
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
} else {
|
||||||
|
let key = core::str::from_utf8(key_slice).unwrap();
|
||||||
|
if core_manager.remove_config(key).is_ok() {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)
|
||||||
|
} else {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtConfigEraseRequest {
|
||||||
|
destination: _destination,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
error!("config erase not supported on zynq device");
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtRebootRequest {
|
||||||
|
destination: _destination,
|
||||||
|
} => {
|
||||||
|
info!("received reboot request");
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)?;
|
||||||
|
info!("reboot imminent");
|
||||||
|
slcr::reboot();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
drtioaux::Packet::CoreMgmtAllocatorDebugRequest {
|
||||||
|
destination: _destination,
|
||||||
|
} => {
|
||||||
|
forward!(
|
||||||
|
router,
|
||||||
|
_routing_table,
|
||||||
|
_destination,
|
||||||
|
*rank,
|
||||||
|
*self_destination,
|
||||||
|
_repeaters,
|
||||||
|
&packet,
|
||||||
|
timer
|
||||||
|
);
|
||||||
|
|
||||||
|
error!("debug allocator not supported on zynq device");
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack)
|
||||||
|
}
|
||||||
|
|
||||||
p => {
|
p => {
|
||||||
warn!("received unexpected aux packet: {:?}", p);
|
warn!("received unexpected aux packet: {:?}", p);
|
||||||
|
@ -1028,6 +1304,7 @@ fn process_aux_packets(
|
||||||
dma_manager: &mut DmaManager,
|
dma_manager: &mut DmaManager,
|
||||||
analyzer: &mut Analyzer,
|
analyzer: &mut Analyzer,
|
||||||
kernel_manager: &mut KernelManager,
|
kernel_manager: &mut KernelManager,
|
||||||
|
core_manager: &mut CoreManager,
|
||||||
router: &mut Router,
|
router: &mut Router,
|
||||||
) {
|
) {
|
||||||
let result = drtioaux::recv(0).and_then(|packet| {
|
let result = drtioaux::recv(0).and_then(|packet| {
|
||||||
|
@ -1043,6 +1320,7 @@ fn process_aux_packets(
|
||||||
dma_manager,
|
dma_manager,
|
||||||
analyzer,
|
analyzer,
|
||||||
kernel_manager,
|
kernel_manager,
|
||||||
|
core_manager,
|
||||||
router,
|
router,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1239,7 +1517,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
#[cfg(has_si549)]
|
#[cfg(has_si549)]
|
||||||
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
|
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
|
||||||
|
|
||||||
let cfg = match Config::new() {
|
let mut cfg = match Config::new() {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("config initialization failed: {}", err);
|
warn!("config initialization failed: {}", err);
|
||||||
|
@ -1314,6 +1592,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
let mut dma_manager = DmaManager::new();
|
let mut dma_manager = DmaManager::new();
|
||||||
let mut analyzer = Analyzer::new();
|
let mut analyzer = Analyzer::new();
|
||||||
let mut kernel_manager = KernelManager::new(&mut control);
|
let mut kernel_manager = KernelManager::new(&mut control);
|
||||||
|
let mut core_manager = CoreManager::new(&mut cfg);
|
||||||
|
|
||||||
drtioaux::reset(0);
|
drtioaux::reset(0);
|
||||||
drtiosat_reset(false);
|
drtiosat_reset(false);
|
||||||
|
@ -1331,6 +1610,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
&mut dma_manager,
|
&mut dma_manager,
|
||||||
&mut analyzer,
|
&mut analyzer,
|
||||||
&mut kernel_manager,
|
&mut kernel_manager,
|
||||||
|
&mut core_manager,
|
||||||
&mut router,
|
&mut router,
|
||||||
);
|
);
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use io::{Cursor, ProtoRead, ProtoWrite};
|
||||||
|
use libboard_artiq::{drtioaux_proto::SAT_PAYLOAD_MAX_SIZE,
|
||||||
|
logger::{BufferLogger, LogBufferRef}};
|
||||||
|
use libconfig::Config;
|
||||||
|
use log::{self, debug, error, info, warn, LevelFilter};
|
||||||
|
|
||||||
|
use crate::routing::{SliceMeta, Sliceable};
|
||||||
|
|
||||||
|
type Result<T> = core::result::Result<T, ()>;
|
||||||
|
|
||||||
|
pub fn byte_to_level_filter(level_byte: u8) -> Result<log::LevelFilter> {
|
||||||
|
Ok(match level_byte {
|
||||||
|
0 => log::LevelFilter::Off,
|
||||||
|
1 => log::LevelFilter::Error,
|
||||||
|
2 => log::LevelFilter::Warn,
|
||||||
|
3 => log::LevelFilter::Info,
|
||||||
|
4 => log::LevelFilter::Debug,
|
||||||
|
5 => log::LevelFilter::Trace,
|
||||||
|
lv => {
|
||||||
|
error!("unknown log level: {}", lv);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_logger_buffer_pred() -> LogBufferRef<'static> {
|
||||||
|
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
||||||
|
loop {
|
||||||
|
if let Some(buffer_ref) = logger.buffer() {
|
||||||
|
return buffer_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_logger_buffer() -> LogBufferRef<'static> {
|
||||||
|
get_logger_buffer_pred()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_log() {
|
||||||
|
let mut buffer = get_logger_buffer();
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Manager<'a> {
|
||||||
|
cfg: &'a mut Config,
|
||||||
|
last_log: Sliceable,
|
||||||
|
current_payload: Cursor<Vec<u8>>,
|
||||||
|
last_value: Sliceable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Manager<'_> {
|
||||||
|
pub fn new(cfg: &mut Config) -> Manager {
|
||||||
|
Manager {
|
||||||
|
cfg: cfg,
|
||||||
|
last_log: Sliceable::new(0, Vec::new()),
|
||||||
|
current_payload: Cursor::new(Vec::new()),
|
||||||
|
last_value: Sliceable::new(0, Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
|
||||||
|
// Populate buffer if depleted
|
||||||
|
if self.last_log.at_end() {
|
||||||
|
self.last_log.extend(get_logger_buffer().extract().as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_log.get_slice_satellite(data_slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_config_value(&mut self, key: &str) -> Result<()> {
|
||||||
|
self.cfg
|
||||||
|
.read(&key)
|
||||||
|
.map(|value| {
|
||||||
|
debug!("got value");
|
||||||
|
self.last_value = Sliceable::new(0, value)
|
||||||
|
})
|
||||||
|
.map_err(|_| warn!("read error: no such key"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_config_value_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
|
||||||
|
self.last_value.get_slice_satellite(data_slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_data(&mut self, data: &[u8], data_len: usize) {
|
||||||
|
self.current_payload.write_all(&data[..data_len]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_data(&mut self) {
|
||||||
|
self.current_payload.get_mut().clear();
|
||||||
|
self.current_payload.set_position(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_config(&mut self) -> Result<()> {
|
||||||
|
let key = self
|
||||||
|
.current_payload
|
||||||
|
.read_string()
|
||||||
|
.map_err(|_err| error!("error on reading key"))?;
|
||||||
|
debug!("write key: {}", key);
|
||||||
|
let value = self.current_payload.read_bytes().unwrap();
|
||||||
|
|
||||||
|
self.cfg
|
||||||
|
.write(&key, value)
|
||||||
|
.map(|()| debug!("write success"))
|
||||||
|
.map_err(|err| error!("failed to write: {:?}", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_config(&mut self, key: &str) -> Result<()> {
|
||||||
|
debug!("erase key: {}", key);
|
||||||
|
self.cfg
|
||||||
|
.remove(&key)
|
||||||
|
.map(|()| debug!("erase success"))
|
||||||
|
.map_err(|err| warn!("failed to erase: {:?}", err))
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ use core::cmp::min;
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
use libboard_artiq::pl::csr;
|
use libboard_artiq::pl::csr;
|
||||||
use libboard_artiq::{drtio_routing, drtioaux,
|
use libboard_artiq::{drtio_routing, drtioaux,
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
|
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}};
|
||||||
|
|
||||||
pub struct SliceMeta {
|
pub struct SliceMeta {
|
||||||
pub destination: u8,
|
pub destination: u8,
|
||||||
|
@ -58,6 +58,7 @@ impl Sliceable {
|
||||||
}
|
}
|
||||||
|
|
||||||
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
||||||
|
get_slice_fn!(get_slice_satellite, SAT_PAYLOAD_MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packets from downstream (further satellites) are received and routed appropriately.
|
// Packets from downstream (further satellites) are received and routed appropriately.
|
||||||
|
|
Loading…
Reference in New Issue