satman: implement cfg/mgmt operations

This commit is contained in:
occheung 2024-08-28 13:34:03 +08:00
parent 873dd86b4d
commit 0c3474f5b5
3 changed files with 400 additions and 3 deletions

View File

@ -38,16 +38,18 @@ use libboard_artiq::{drtio_routing, drtioaux,
pl::csr};
#[cfg(feature = "target_kasli_soc")]
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 libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR;
use libsupport_zynq::{exception_vectors, ram};
use mgmt::Manager as CoreManager;
use routing::Router;
use subkernel::Manager as KernelManager;
mod analyzer;
mod dma;
mod mgmt;
mod repeater;
mod routing;
mod subkernel;
@ -149,6 +151,7 @@ fn process_aux_packet(
dma_manager: &mut DmaManager,
analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager,
core_manager: &mut CoreManager,
router: &mut Router,
) -> Result<(), drtioaux::Error> {
// 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(())
}
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 => {
warn!("received unexpected aux packet: {:?}", p);
@ -1028,6 +1304,7 @@ fn process_aux_packets(
dma_manager: &mut DmaManager,
analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager,
core_manager: &mut CoreManager,
router: &mut Router,
) {
let result = drtioaux::recv(0).and_then(|packet| {
@ -1043,6 +1320,7 @@ fn process_aux_packets(
dma_manager,
analyzer,
kernel_manager,
core_manager,
router,
)
} else {
@ -1239,7 +1517,7 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_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,
Err(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 analyzer = Analyzer::new();
let mut kernel_manager = KernelManager::new(&mut control);
let mut core_manager = CoreManager::new(&mut cfg);
drtioaux::reset(0);
drtiosat_reset(false);
@ -1331,6 +1610,7 @@ pub extern "C" fn main_core0() -> i32 {
&mut dma_manager,
&mut analyzer,
&mut kernel_manager,
&mut core_manager,
&mut router,
);
#[allow(unused_mut)]

116
src/satman/src/mgmt.rs Normal file
View File

@ -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))
}
}

View File

@ -4,7 +4,7 @@ use core::cmp::min;
#[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr;
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 destination: u8,
@ -58,6 +58,7 @@ impl Sliceable {
}
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.