From ae9fcac5cf9331456906f64688048561e26ad339 Mon Sep 17 00:00:00 2001 From: Quarky93 Date: Sun, 27 Nov 2022 02:37:27 +1100 Subject: [PATCH] ReadWritableAddressSpace helper --- sw/warpshell/src/modules/axi_firewall.rs | 52 ++++++--- sw/warpshell/src/modules/cms.rs | 77 +++++++++++++ sw/warpshell/src/modules/hbicap.rs | 11 ++ sw/warpshell/src/modules/io.rs | 66 ++++++------ sw/warpshell/src/modules/mod.rs | 2 + sw/warpshell/src/modules/xdma.rs | 102 +++++++++++++----- sw/warpshell/src/modules/xilinx/mod.rs | 0 .../src/shells/xilinx_u55n_xdma_std.rs | 16 ++- .../src/warpshell-cli/warpshell-cli.rs | 12 ++- 9 files changed, 262 insertions(+), 76 deletions(-) create mode 100644 sw/warpshell/src/modules/cms.rs create mode 100644 sw/warpshell/src/modules/hbicap.rs create mode 100644 sw/warpshell/src/modules/xilinx/mod.rs diff --git a/sw/warpshell/src/modules/axi_firewall.rs b/sw/warpshell/src/modules/axi_firewall.rs index 99d2fbf..0363249 100644 --- a/sw/warpshell/src/modules/axi_firewall.rs +++ b/sw/warpshell/src/modules/axi_firewall.rs @@ -1,31 +1,59 @@ -use super::io::ReadWritable; +use super::io::{ReadWritable, ReadWritableAddressSpace, Readable, Writable}; pub struct AxiFirewall<'a> { - pub ctrl_baseaddr: u64, - pub ctrl_channel: &'a dyn ReadWritable + pub ctrl: ReadWritableAddressSpace<'a>, } +// -- REGISTER MAP ---------------------------------------------------------------------------------------------------- const MI_SIDE_FAULT_STATUS_REGISTER_OFFSET: u64 = 0x0; const MI_SIDE_SOFT_FAULT_CONTROL_REGISTER_OFFSET: u64 = 0x4; const MI_SIDE_UNBLOCK_CONTROL_REGISTER_OFFSET: u64 = 0x8; const IP_VERSION_REGISTER_OFFSET: u64 = 0x10; // const SOFT_PAUSE_REGISTER_OFFSET: u64 = 0x14; +// -------------------------------------------------------------------------------------------------------------------- impl<'a> AxiFirewall<'a> { - pub fn get_ip_version(&self) -> u32 { - self.ctrl_channel.read_u32(self.ctrl_baseaddr + IP_VERSION_REGISTER_OFFSET).unwrap() + pub fn new(ctrl_channel: &'a dyn ReadWritable, ctrl_baseaddr: u64) -> Self { + Self { + ctrl: ReadWritableAddressSpace { + channel: ctrl_channel, + baseaddr: ctrl_baseaddr, + }, + } + } + // -- MI OPS ------------------------------------------------------------------------------------------------------ + pub fn get_mi_fault_status(&self) -> u32 { + self.ctrl.read_u32(MI_SIDE_FAULT_STATUS_REGISTER_OFFSET) + } + + pub fn mi_is_blocked(&self) -> bool { + self.get_mi_fault_status() != 0 } - pub fn get_mi_side_fault_status(&self) -> u32 { - self.ctrl_channel.read_u32(self.ctrl_baseaddr + MI_SIDE_FAULT_STATUS_REGISTER_OFFSET).unwrap() + pub fn block_mi(&self) { + self.ctrl + .write_u32(0x0100_0100, MI_SIDE_SOFT_FAULT_CONTROL_REGISTER_OFFSET); } - pub fn block(&self) { - self.ctrl_channel.write_u32(0x0100_0100, self.ctrl_baseaddr + MI_SIDE_SOFT_FAULT_CONTROL_REGISTER_OFFSET).unwrap(); + pub fn unblock_mi(&self) { + self.ctrl + .write_u32(0x0, MI_SIDE_SOFT_FAULT_CONTROL_REGISTER_OFFSET); + self.ctrl + .write_u32(0x1, MI_SIDE_UNBLOCK_CONTROL_REGISTER_OFFSET); + } + // ---------------------------------------------------------------------------------------------------------------- + + pub fn get_ip_version(&self) -> u32 { + self.ctrl.read_u32(IP_VERSION_REGISTER_OFFSET) } - pub fn unblock(&self) { - self.ctrl_channel.write_u32(0x0, self.ctrl_baseaddr + MI_SIDE_SOFT_FAULT_CONTROL_REGISTER_OFFSET).unwrap(); - self.ctrl_channel.write_u32(0x1, self.ctrl_baseaddr + MI_SIDE_UNBLOCK_CONTROL_REGISTER_OFFSET).unwrap(); + pub fn print_status(&self) { + println!("VERSION: {:?}", self.get_ip_version()); + let status = self.get_mi_fault_status(); + let mi_is_blocked = status != 0; + println!("MI_IS_BLOCKED: {:?}", mi_is_blocked); + if mi_is_blocked { + println!("MI_STATUS: {:?}", status); + } } } diff --git a/sw/warpshell/src/modules/cms.rs b/sw/warpshell/src/modules/cms.rs new file mode 100644 index 0000000..0af99de --- /dev/null +++ b/sw/warpshell/src/modules/cms.rs @@ -0,0 +1,77 @@ +use super::io::{ReadWritable, ReadWritableAddressSpace, Readable, Writable}; + +pub struct Cms<'a> { + pub ctrl: ReadWritableAddressSpace<'a>, +} + +// -- REGISTER MAP ---------------------------------------------------------------------------------------------------- +// Alveo Card Management Solution Subsystem v4.0 + +const O_MB_RESETN_REG: u64 = 0x02_0000; +const O_HOST_INTC: u64 = 0x02_2000; +const O_REG_MAP: u64 = 0x02_8000; + +const O_REG_MAP_ID: u64 = 0x0000; +const O_FW_VERSION_REG: u64 = 0x0004; +const O_STATUS_REG: u64 = 0x0008; +const O_ERROR_REG: u64 = 0x000c; +const O_PROFILE_NAME_REG: u64 = 0x0014; +const O_CONTROL_REG: u64 = 0x0018; +const O_12V_PEX_MAX_REG: u64 = 0x0020; +const O_12V_PEX_AVG_REG: u64 = 0x0024; +const O_12V_PEX_INS_REG: u64 = 0x0028; +const O_3V3_PEX_MAX_REG: u64 = 0x002c; +const O_3V3_PEX_AVG_REG: u64 = 0x0030; +const O_3V3_PEX_INS_REG: u64 = 0x0034; +const O_3V3_AUX_MAX_REG: u64 = 0x0038; +const O_3V3_AUX_AVG_REG: u64 = 0x003c; +const O_3V3_AUX_INS_REG: u64 = 0x0040; +const O_12V_AUX_MAX_REG: u64 = 0x0044; +const O_12V_AUX_AVG_REG: u64 = 0x0048; +const O_12V_AUX_INS_REG: u64 = 0x004c; +const O_DDR4_VPP_BTM_MAX_REG: u64 = 0x0050; +const O_DDR4_VPP_BTM_AVG_REG: u64 = 0x0054; +const O_DDR4_VPP_BTM_INS_REG: u64 = 0x0058; +const O_SYS_5V5_MAX_REG: u64 = 0x005c; +const O_SYS_5V5_AVG_REG: u64 = 0x0060; +const O_SYS_5V5_INS_REG: u64 = 0x0064; + +const O_HOST_STATUS2_REG: u64 = 0x030c; +// -------------------------------------------------------------------------------------------------------------------- + +impl<'a> Cms<'a> { + pub fn new(ctrl_channel: &'a dyn ReadWritable, ctrl_baseaddr: u64) -> Self { + Self { + ctrl: ReadWritableAddressSpace { + channel: ctrl_channel, + baseaddr: ctrl_baseaddr, + }, + } + } + + pub fn init(&self) { + self.ctrl.write_u32(1, O_MB_RESETN_REG); + let mut ready = false; + while !ready { + ready = (self.ctrl.read_u32(O_REG_MAP + O_HOST_STATUS2_REG) & 1) == 1; + } + } + + pub fn get_reg_map_id(&self) -> u32 { + self.ctrl.read_u32(O_REG_MAP + O_REG_MAP_ID) + } + + pub fn get_fw_version(&self) -> u32 { + self.ctrl.read_u32(O_REG_MAP + O_FW_VERSION_REG) + } + + pub fn get_profile_name(&self) -> u32 { + self.ctrl.read_u32(O_REG_MAP + O_PROFILE_NAME_REG) + } + + pub fn print_info(&self) { + println!("REG_MAP_ID: {:#010x}", self.get_reg_map_id()); + println!("FW_VERSION: {:#010x}", self.get_fw_version()); + println!("PROFILE_NAME: {:#010x}", self.get_profile_name()); + } +} diff --git a/sw/warpshell/src/modules/hbicap.rs b/sw/warpshell/src/modules/hbicap.rs new file mode 100644 index 0000000..879ebe8 --- /dev/null +++ b/sw/warpshell/src/modules/hbicap.rs @@ -0,0 +1,11 @@ +use super::io::{Readable, Writable, ReadWritableAddressSpace, ReadableAddressSpace, WritableAddressSpace}; + +pub struct HbIcap<'a> { + pub ctrl: ReadWritableAddressSpace<'a>, + pub read: ReadableAddressSpace<'a>, + pub write: WritableAddressSpace<'a> +} + +// -- REGISTER MAP ---------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/sw/warpshell/src/modules/io.rs b/sw/warpshell/src/modules/io.rs index ea21d47..a3e4ddf 100644 --- a/sw/warpshell/src/modules/io.rs +++ b/sw/warpshell/src/modules/io.rs @@ -1,70 +1,70 @@ -use std::{fs::File, os::unix::prelude::FileExt}; -use anyhow::Result; - pub trait Readable { - fn read(&self, buf: &mut [u8], offset: u64) -> Result<()>; + fn read(&self, buf: &mut [u8], offset: u64); - fn read_u32(&self, offset: u64) -> Result { + fn read_u32(&self, offset: u64) -> u32 { let mut buf: [u8; 4] = [0; 4]; - self.read(&mut buf, offset)?; - Ok(u32::from_le_bytes(buf)) + self.read(&mut buf, offset); + u32::from_le_bytes(buf) } - fn read_u64(&self, offset: u64) -> Result { + fn read_u64(&self, offset: u64) -> u64 { let mut buf: [u8; 8] = [0; 8]; - self.read(&mut buf, offset)?; - Ok(u64::from_le_bytes(buf)) + self.read(&mut buf, offset); + u64::from_le_bytes(buf) } } pub trait Writable { - fn write(&self, buf: &[u8], offset: u64) -> Result<()>; + fn write(&self, buf: &[u8], offset: u64); - fn write_u32(&self, data: u32, offset: u64) -> Result<()> { + fn write_u32(&self, data: u32, offset: u64) { self.write(&data.to_le_bytes(), offset) } - fn write_u64(&self, data: u64, offset: u64) -> Result<()> { + fn write_u64(&self, data: u64, offset: u64) { self.write(&data.to_le_bytes(), offset) } } -pub trait ReadWritable: Readable + Writable {} +pub trait ReadWritable: Readable + Writable {} -pub struct ReadableCdev { - pub cdev: File +pub struct ReadableAddressSpace<'a> { + channel: &'a dyn Readable, + baseaddr: u64 } -pub struct WritableCdev { - pub cdev: File +pub struct WritableAddressSpace<'a> { + channel: &'a dyn Writable, + baseaddr: u64 } -pub struct ReadWritableCdev { - pub cdev: File +pub struct ReadWritableAddressSpace<'a> { + pub channel: &'a dyn ReadWritable, + pub baseaddr: u64 } -impl Readable for ReadableCdev { - fn read(&self, buf: &mut [u8], offset: u64) -> Result<()> { - self.cdev.read_exact_at(buf, offset).map_err(anyhow::Error::from) +impl Readable for ReadableAddressSpace<'_> { + fn read(&self, buf: &mut [u8], offset: u64) { + self.channel.read(buf, self.baseaddr + offset); } } -impl Writable for WritableCdev { - fn write(&self, buf: &[u8], offset: u64) -> Result<()> { - self.cdev.write_all_at(buf, offset).map_err(anyhow::Error::from) +impl Writable for WritableAddressSpace<'_> { + fn write(&self, buf: &[u8], offset: u64) { + self.channel.write(buf, self.baseaddr + offset); } } -impl Readable for ReadWritableCdev { - fn read(&self, buf: &mut [u8], offset: u64) -> Result<()> { - self.cdev.read_exact_at(buf, offset).map_err(anyhow::Error::from) +impl Readable for ReadWritableAddressSpace<'_> { + fn read(&self, buf: &mut [u8], offset: u64) { + self.channel.read(buf, self.baseaddr + offset); } } -impl Writable for ReadWritableCdev { - fn write(&self, buf: &[u8], offset: u64) -> Result<()> { - self.cdev.write_all_at(buf, offset).map_err(anyhow::Error::from) +impl Writable for ReadWritableAddressSpace<'_> { + fn write(&self, buf: &[u8], offset: u64) { + self.channel.write(buf, self.baseaddr + offset); } } -impl ReadWritable for ReadWritableCdev {} \ No newline at end of file +impl ReadWritable for ReadWritableAddressSpace<'_> {} diff --git a/sw/warpshell/src/modules/mod.rs b/sw/warpshell/src/modules/mod.rs index b1e37e2..7c45063 100644 --- a/sw/warpshell/src/modules/mod.rs +++ b/sw/warpshell/src/modules/mod.rs @@ -1,3 +1,5 @@ pub mod io; pub mod xdma; +pub mod cms; +pub mod hbicap; pub mod axi_firewall; \ No newline at end of file diff --git a/sw/warpshell/src/modules/xdma.rs b/sw/warpshell/src/modules/xdma.rs index 7f90a31..ce46664 100644 --- a/sw/warpshell/src/modules/xdma.rs +++ b/sw/warpshell/src/modules/xdma.rs @@ -1,61 +1,111 @@ -use super::io::{ReadWritableCdev, ReadableCdev, WritableCdev}; -use std::fs::OpenOptions; +use super::io::{Readable, Writable, ReadWritable}; +use std::{fs::{File, OpenOptions}, os::unix::prelude::FileExt}; + +pub struct UserCdev { + fd: File, +} + +pub struct H2cCdev { + fd: File, +} + +pub struct C2hCdev { + fd: File, +} + +impl Readable for UserCdev { + // The /dev/xdma0_user cdev does not automatically break up read/write calls to 4-byte transactions. + fn read(&self, buf: &mut [u8], offset: u64) { + let mut i = 0; + let chunks = buf.chunks_mut(4); + for chunk in chunks { + self.fd.read_exact_at(chunk, offset + i).unwrap(); + i += 4; + } + } +} + +impl Writable for UserCdev { + // The /dev/xdma0_user cdev does not automatically break up read/write calls to 4-byte transactions. + fn write(&self, buf: &[u8], offset: u64) { + let mut i = 0; + let chunks = buf.chunks(4); + for chunk in chunks { + self.fd.write_all_at(chunk, offset + i).unwrap(); + i += 4; + } + } +} + +impl ReadWritable for UserCdev {} + +impl Readable for C2hCdev { + fn read(&self, buf: &mut [u8], offset: u64) { + self.fd.read_exact_at(buf, offset).unwrap(); + } +} + +impl Writable for C2hCdev { + fn write(&self, buf: &[u8], offset: u64) { + self.fd.write_all_at(buf, offset).unwrap(); + } +} pub struct Xdma { - pub user: Vec, - pub bypass: Vec, - pub h2c: Vec, - pub c2h: Vec, + pub user: Vec, + pub bypass: Vec, + pub h2c: Vec, + pub c2h: Vec, } impl Xdma { pub fn new(id: u32) -> Self { - let user_cdev = OpenOptions::new() + let user_fd = OpenOptions::new() .read(true) .write(true) .open(format!("/dev/xdma{id}_user")); - let mut user: Vec = Vec::new(); - if user_cdev.is_ok() { - user.push(ReadWritableCdev { - cdev: user_cdev.unwrap(), + let mut user: Vec = Vec::new(); + if user_fd.is_ok() { + user.push(UserCdev { + fd: user_fd.unwrap(), }); } - let bypass_cdev = OpenOptions::new() + let bypass_fd = OpenOptions::new() .read(true) .write(true) .open(format!("/dev/xdma{id}_bypass")); - let mut bypass: Vec = Vec::new(); - if bypass_cdev.is_ok() { - bypass.push(ReadWritableCdev { - cdev: bypass_cdev.unwrap(), + let mut bypass: Vec = Vec::new(); + if bypass_fd.is_ok() { + bypass.push(H2cCdev { + fd: bypass_fd.unwrap(), }); } - let mut h2c: Vec = Vec::new(); + let mut h2c: Vec = Vec::new(); for i in 0..4 { - let h2c_cdev = OpenOptions::new() + let h2c_fd = OpenOptions::new() .read(true) .write(true) .open(format!("/dev/xdma{id}_h2c_{i}")); - if h2c_cdev.is_ok() { - h2c.push(WritableCdev { - cdev: h2c_cdev.unwrap(), + if h2c_fd.is_ok() { + h2c.push(H2cCdev { + fd: h2c_fd.unwrap(), }); } else { break; } } - let mut c2h: Vec = Vec::new(); + let mut c2h: Vec = Vec::new(); for i in 0..4 { - let c2h_cdev = OpenOptions::new() + let c2h_fd = OpenOptions::new() .read(true) .write(true) .open(format!("/dev/xdma{id}_c2h_{i}")); - if c2h_cdev.is_ok() { - c2h.push(ReadableCdev { - cdev: c2h_cdev.unwrap(), + if c2h_fd.is_ok() { + c2h.push(C2hCdev { + fd: c2h_fd.unwrap(), }); } else { break; diff --git a/sw/warpshell/src/modules/xilinx/mod.rs b/sw/warpshell/src/modules/xilinx/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/sw/warpshell/src/shells/xilinx_u55n_xdma_std.rs b/sw/warpshell/src/shells/xilinx_u55n_xdma_std.rs index dc43085..b3c31d0 100644 --- a/sw/warpshell/src/shells/xilinx_u55n_xdma_std.rs +++ b/sw/warpshell/src/shells/xilinx_u55n_xdma_std.rs @@ -1,12 +1,15 @@ use anyhow::{Result, anyhow}; -use crate::modules::{xdma::Xdma, axi_firewall::AxiFirewall}; +use crate::modules::{xdma::Xdma, axi_firewall::AxiFirewall, cms::Cms}; pub struct XilinxU55nXdmaStd<'a> { pub xdma: &'a Xdma, - pub ctrl_firewall: AxiFirewall<'a> + pub cms: Cms<'a>, + pub ctrl_firewall: AxiFirewall<'a>, + pub dma_firewall: AxiFirewall<'a> } +// -- ADDRESS MAP ----------------------------------------------------------------------------------------------------- const CTRL_USER_BASEADDR: u64 = 0x0000_0000; const CTRL_CMS_BASEADDR: u64 = 0x0400_0000; const CTRL_QSPI_BASEADDR: u64 = 0x0404_0000; @@ -15,6 +18,7 @@ const CTRL_MGMT_RAM_BASEADDR: u64 = 0x0406_0000; const CTRL_CTRL_FIREWALL_BASEADDR: u64 = 0x0407_0000; const CTRL_DMA_FIREWALL_BASEADDR: u64 = 0x0408_0000; const CTRL_DECOUPLER_BASEADDR: u64 = 0x0409_0000; +// -------------------------------------------------------------------------------------------------------------------- impl<'a> XilinxU55nXdmaStd<'a> { pub fn new(xdma: &'a Xdma) -> Result { @@ -29,7 +33,13 @@ impl<'a> XilinxU55nXdmaStd<'a> { } Ok(Self { xdma, - ctrl_firewall: AxiFirewall { ctrl_baseaddr: CTRL_CTRL_FIREWALL_BASEADDR, ctrl_channel: &xdma.user[0] } + cms: Cms::new(&xdma.user[0], CTRL_CMS_BASEADDR), + ctrl_firewall: AxiFirewall::new(&xdma.user[0], CTRL_CTRL_FIREWALL_BASEADDR), + dma_firewall: AxiFirewall::new(&xdma.user[0], CTRL_DMA_FIREWALL_BASEADDR) }) } + + pub fn init(&self) { + self.cms.init(); + } } diff --git a/sw/warpshell/src/warpshell-cli/warpshell-cli.rs b/sw/warpshell/src/warpshell-cli/warpshell-cli.rs index f9f5fb6..15ff3c8 100644 --- a/sw/warpshell/src/warpshell-cli/warpshell-cli.rs +++ b/sw/warpshell/src/warpshell-cli/warpshell-cli.rs @@ -1,7 +1,15 @@ use warpshell::{shells::xilinx_u55n_xdma_std::XilinxU55nXdmaStd, modules::xdma::Xdma}; fn main() { - println!("Hello, world!"); + println!("Detecting XDMA..."); let xdma = Xdma::new(0); - let _shell = XilinxU55nXdmaStd::new(&xdma).unwrap(); + println!("Initializing Warpshell..."); + let shell = XilinxU55nXdmaStd::new(&xdma).unwrap(); + shell.init(); + println!("--[CMS]----------------------------"); + shell.cms.print_info(); + println!("--[CTRL_FIREWALL]------------------"); + shell.dma_firewall.print_status(); + println!("--[DMA_FIREWALL]-------------------"); + shell.dma_firewall.print_status(); }