use heterob::{bit_numbering::Lsb, endianness::Le, Seq, P2, P5, P6, P7, P9};
use super::{ExtendedCapabilityDataError, ExtendedCapabilityHeader};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PciExpressOverMphy {
pub mpcie_capabilities: MpcieCapabilities,
pub mpcie_control: MpcieControl,
pub mpcie_status: MpcieStatus,
pub mpcie_lane_error_status: u32,
pub mpcie_phy_control_address: MpciePhyControlAddress,
pub mpcie_phy_control_data: MpciePhyControlData,
}
impl PciExpressOverMphy {
pub const SIZE: usize = 0x1C;
}
impl TryFrom<&[u8]> for PciExpressOverMphy {
type Error = ExtendedCapabilityDataError;
fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
let slice = slice
.get(ExtendedCapabilityHeader::SIZE..)
.unwrap_or_default();
let Seq {
head:
Le((
mpcie_capabilities,
mpcie_control,
mpcie_status,
mpcie_lane_error_status,
mpcie_phy_control_address,
mpcie_phy_control_data,
)),
..
} = P6(slice)
.try_into()
.map_err(|_| ExtendedCapabilityDataError {
name: "M-PCIe",
size: Self::SIZE,
})?;
Ok(Self {
mpcie_capabilities: From::<u32>::from(mpcie_capabilities),
mpcie_control: From::<u32>::from(mpcie_control),
mpcie_status: From::<u32>::from(mpcie_status),
mpcie_lane_error_status,
mpcie_phy_control_address: From::<u32>::from(mpcie_phy_control_address),
mpcie_phy_control_data: From::<u32>::from(mpcie_phy_control_data),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MpcieCapabilities {
pub mpcie_link_speed_capability: MpcieLinkSpeed,
pub configuration_software_supported: bool,
pub maximum_tx_lane_width_capability: LaneWidthSupported,
pub maximum_rx_lane_width_capability: LaneWidthSupported,
}
impl From<u32> for MpcieCapabilities {
fn from(dword: u32) -> Self {
let Lsb((lsc, (), configuration_software_supported, tx, rx)) =
P5::<_, 2, 13, 1, 8, 8>(dword).into();
Self {
mpcie_link_speed_capability: From::<u8>::from(lsc),
configuration_software_supported,
maximum_tx_lane_width_capability: From::<u8>::from(tx),
maximum_rx_lane_width_capability: From::<u8>::from(rx),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MpcieControl {
pub mpcie_target_link_speed_control: MpcieLinkSpeed,
}
impl From<u32> for MpcieControl {
fn from(dword: u32) -> Self {
let Lsb((tlsc, ())) = P2::<_, 2, 30>(dword).into();
Self {
mpcie_target_link_speed_control: From::<u8>::from(tlsc),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MpcieStatus {
pub mpcie_current_link_speed_status: MpcieLinkSpeed,
pub mpcie_configuration_software_status: bool,
pub tx_lane_width_status: LaneWidthStatus,
pub rx_lane_width_status: LaneWidthStatus,
}
impl From<u32> for MpcieStatus {
fn from(dword: u32) -> Self {
let Lsb((clss, (), mpcie_configuration_software_status, tx, rx)) =
P5::<_, 2, 13, 1, 8, 8>(dword).into();
Self {
mpcie_current_link_speed_status: From::<u8>::from(clss),
mpcie_configuration_software_status,
tx_lane_width_status: From::<u8>::from(tx),
rx_lane_width_status: From::<u8>::from(rx),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MpciePhyControlAddress {
pub lower_addr: u8,
pub upper_addr: u8,
pub phy_location: PhyLocation,
pub read: bool,
pub config: bool,
}
impl From<u32> for MpciePhyControlAddress {
fn from(dword: u32) -> Self {
let Lsb((lower_addr, (), upper_addr, (), upper_addr_5, phy_location, (), read, config)) =
P9::<_, 8, 8, 5, 3, 1, 3, 2, 1, 1>(dword).into();
let _: (u8, u8) = (upper_addr, upper_addr_5);
Self {
lower_addr,
upper_addr: upper_addr | (upper_addr_5 << 5),
phy_location: From::<u8>::from(phy_location),
read,
config,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MpciePhyControlData {
pub phy_register_data: u8,
pub phy_control_error: bool,
pub rrap_abort_a: bool,
pub phy_control_pending: bool,
}
impl From<u32> for MpciePhyControlData {
fn from(dword: u32) -> Self {
let Lsb((phy_register_data, (), phy_control_error, rrap_abort_a, phy_control_pending)) =
P5::<_, 8, 21, 1, 1, 1>(dword).into();
Self {
phy_register_data,
phy_control_error,
rrap_abort_a,
phy_control_pending,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MpcieLinkSpeed {
pub hs_g1: bool,
pub hs_g2: bool,
}
impl From<u8> for MpcieLinkSpeed {
fn from(byte: u8) -> Self {
let Lsb((hs_g1, hs_g2)) = P2::<_, 1, 1>(byte).into();
Self { hs_g1, hs_g2 }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LaneWidthSupported {
pub x1: bool,
pub x2: bool,
pub x4: bool,
pub x8: bool,
pub x12: bool,
pub x16: bool,
pub x32: bool,
}
impl From<u8> for LaneWidthSupported {
fn from(byte: u8) -> Self {
let Lsb((x1, x2, x4, x8, x12, x16, x32)) = P7::<_, 1, 1, 1, 1, 1, 1, 1>(byte).into();
Self {
x1,
x2,
x4,
x8,
x12,
x16,
x32,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LaneWidthStatus {
X1,
X2,
X4,
X8,
X12,
X16,
X32,
Reserved(u8),
}
impl From<u8> for LaneWidthStatus {
fn from(byte: u8) -> Self {
match byte {
0b0000_0001 => Self::X1,
0b0000_0010 => Self::X2,
0b0000_0100 => Self::X4,
0b0000_1000 => Self::X8,
0b0000_1100 => Self::X12,
0b0001_0000 => Self::X16,
0b0010_0000 => Self::X32,
v => Self::Reserved(v),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PhyLocation {
LocalPhy,
RemotePhy,
Reserved(u8),
}
impl From<u8> for PhyLocation {
fn from(byte: u8) -> Self {
match byte {
0b000 => Self::LocalPhy,
0b001 => Self::RemotePhy,
v => Self::Reserved(v),
}
}
}