Fixed config writing and added a test for it

rust_native
ko1N 5 years ago
parent 522414f956
commit 2dc77dd79b

@ -0,0 +1,2 @@
[target.'cfg(unix)']
runner = "sudo"

@ -36,7 +36,7 @@ bitfield! {
pl_directed_link_speed, _: 3;
pl_directed_link_width, _: 5, 4;
pl_upstream_prefer_deemph, _: 6;
pl_transmit_hot_rst, _: 7;
pl_transmit_hot_rst, set_pl_transmit_hot_rst: 7;
pl_downstream_deemph_source, _: 8;
//_, _: 16, 9;
}
@ -101,29 +101,42 @@ impl Device {
Ok(Self { ft60 })
}
pub fn get_version(&mut self) -> Result<()> {
/// Restarts the PCIE device
pub fn restart(mut self) -> Result<()> {
let reset_code: [u8; 2] = [0x00, 0x80];
self.write_config(
0x0002,
reset_code,
FPGA_CONFIG_CORE | FPGA_CONFIG_SPACE_READWRITE,
)?;
std::thread::sleep(Duration::from_millis(1000));
Ok(())
}
pub fn get_devid(&mut self) -> Result<()> {
// DeviceFPGA_GetDeviceId_FpgaVersion_ClearPipe
self.read_version_clear_pipe()?;
self.read_devid_clear_pipe()?;
self.read_version_v4()?;
Ok(())
}
fn read_version_clear_pipe(&mut self) -> Result<()> {
fn read_devid_clear_pipe(&mut self) -> Result<()> {
let dummy = [
// cmd msg: FPGA bitstream version (major.minor) v4
// dword->qword resynch v4.5+
0x66, 0x66, 0x55, 0x55, 0x66, 0x66, 0x55, 0x55, 0x66, 0x66, 0x55, 0x55, 0x66, 0x66,
0x55, 0x55, // cmd msg: FPGA bitstream version (major.minor) v4
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x13, 0x77,
// cmd msg: FPGA bitstream version (major) v3
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x77,
];
self.ft60.write_pipe(&dummy)?;
let mut buf = vec![0u8; size::mb(16)];
let bytes = self.ft60.read_pipe(&mut buf[..0x1000])?;
if bytes >= 0x1000 {
self.ft60.read_pipe(&mut buf)?;
let mut buf = vec![0u8; size::mb(1)];
if self.ft60.read_pipe(&mut buf[..0x1000])? >= 0x1000 {
if self.ft60.read_pipe(&mut buf)? == buf.len() {
// TODO: reset
}
}
Ok(())
@ -132,41 +145,48 @@ impl Device {
fn read_version_v4(&mut self) -> Result<()> {
let version_major =
self.read_config::<u8>(0x0008, FPGA_CONFIG_CORE | FPGA_CONFIG_SPACE_READONLY)?;
println!("version_major = {}", version_major);
info!("version_major = {}", version_major);
if version_major != 4 {
return Err(Error::Connector("incompatible fpga version found"));
}
let version_minor =
self.read_config::<u8>(0x0009, FPGA_CONFIG_CORE | FPGA_CONFIG_SPACE_READONLY)?;
println!("version_minor = {}", version_minor);
info!("version_minor={}", version_minor);
let fpga_id =
self.read_config::<u8>(0x000a, FPGA_CONFIG_CORE | FPGA_CONFIG_SPACE_READONLY)?;
println!("fpga_id = {}", fpga_id);
info!("fpga_id={}", fpga_id);
// this will cause the hardware to reset briefly
/*
let inactivity_timer = 0x000186a0u32; // set inactivity timer to 1ms (0x0186a0 * 100MHz) [only later activated on UDP bitstreams]
self.write_config(
0x0008,
inactivity_timer,
FPGA_CONFIG_CORE | FPGA_CONFIG_SPACE_READWRITE,
)?;
*/
let mut device_id = self
.read_config::<u16>(0x0008, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READONLY)
.unwrap_or_default();
info!("device_id={}", device_id);
if device_id == 0 {
info!("pci device_id is unset. checking pcie magic.");
let magic_pcie = self
.read_config::<u16>(0x0000, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READWRITE)
.unwrap_or_default();
println!("magic_pcie = {:?}", magic_pcie);
info!("magic_pcie={:?}", magic_pcie);
if magic_pcie == 0x6745 {
println!("failed to get device_id - trying to recover via hot reset");
warn!("failed to get device_id. trying to recover via hot reset");
self.hot_reset_v4().ok();
device_id = self
.read_config::<u16>(0x0008, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READONLY)
.unwrap_or_default();
}
}
println!("device_id = {:?}", device_id);
info!("device_id={:?}", device_id);
let (wr, rd) = self.get_phy_v4()?;
println!("wr: {:?}", wr);
@ -182,9 +202,13 @@ impl Device {
fn hot_reset_v4(&mut self) -> Result<()> {
trace!("hot resetting the fpga");
let (wr, _) = self.get_phy_v4()?;
let (mut wr, _) = self.get_phy_v4()?;
wr.set_pl_transmit_hot_rst(true);
self.write_config(0x0016, wr.0, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READWRITE)?;
std::thread::sleep(Duration::from_millis(250)); // TODO: poll pl_ltssm_state + timeout with failure
wr.set_pl_transmit_hot_rst(false);
self.write_config(0x0016, wr.0, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READWRITE)?;
Ok(())
}
@ -291,7 +315,7 @@ impl Device {
self.write_config_raw(addr, obj.as_bytes(), flags)
}
fn write_config_raw(&mut self, addr: u16, buf: &[u8], flags: u16) -> Result<()> {
fn write_config_build_request(addr: u16, buf: &[u8], flags: u16) -> Result<Vec<u8>> {
if buf.is_empty() || buf.len() > 0x200 || addr > size::kb(4) as u16 {
return Err(Error::Connector("invalid config address to write"));
}
@ -315,7 +339,12 @@ impl Device {
ptr += 8;
}
self.ft60.write_pipe(&buf)
Ok(outbuf[..ptr].to_vec())
}
fn write_config_raw(&mut self, addr: u16, buf: &[u8], flags: u16) -> Result<()> {
let outbuf = Self::write_config_build_request(addr, buf, flags)?;
self.ft60.write_pipe(&outbuf)
}
}
@ -485,4 +514,19 @@ mod tests {
.unwrap();
assert_eq!(rd, 0x1C0819);
}
#[test]
fn write_config_inactivity_timer() {
let inactivity_timer = 0x000186a0u32; // set inactivity timer to 1ms (0x0186a0 * 100MHz) [only later activated on UDP bitstreams]
let outbuf = Device::write_config_build_request(
0x0008,
inactivity_timer.as_bytes(),
FPGA_CONFIG_CORE | FPGA_CONFIG_SPACE_READWRITE,
)
.unwrap();
assert_eq!(
outbuf,
[160, 134, 255, 255, 128, 8, 35, 119, 1, 0, 255, 255, 128, 10, 35, 119]
);
}
}

@ -13,7 +13,17 @@ pub struct PciLeech {
impl PciLeech {
pub fn new() -> Result<Self> {
let mut device = fpga::Device::new()?;
device.get_version()?;
// TODO: validate version
//device.restart().ok();
// device = fpga::Device::new()?;
// TODO: validate device id
device.get_devid()?;
// https://github.com/ufrisk/LeechCore/blob/master/leechcore/device_fpga.c#L2133
Ok(Self { device })
}
}

Loading…
Cancel
Save