pcics 0.3.2

PCI configuration space access library
Documentation
/*!
# Function Readiness Status (FRS) Queuing

The Function Readiness Status (FRS) Queuing Extended Capability is required for Root Ports
and Root Complex Event Collectors that support the optional normative FRS Queuing
capability.

## Struct diagram
<pre>
<a href="struct.FrsQueuing.html">FrsQueuing</a>
 ├─ <a href="struct.FrsQueuingCapability.html">FrsQueuingCapability</a>
 ├─ <a href="struct.FrsQueuingStatus.html">FrsQueuingStatus</a>
 ├─ <a href="struct.FrsQueuingControl.html">FrsQueuingControl</a>
 └─ <a href="struct.FrsMessageQueue.html">FrsMessageQueue</a>
</pre>

## Examples
```rust
# use pcics::extended_capabilities::frs_queuing::*;
let data = [
    /* 00h */ 0x21, 0x00, 0x01, 0x00, // Capability header
    /* 04h */ 0x55, 0x00, 0x06, 0x00, // FRS Queuing Capability
    /* 08h */ 0x01, 0x00, // FRS Queuing Status
              0x00, 0x00, // FRS Queuing Control
    /* 0Ch */ 0x01, 0x80, 0x0C, 0x0C, // FRS Message Queue
];

let result: FrsQueuing = data.as_slice().try_into().unwrap();

let sample = FrsQueuing {
    frs_queuing_capability: FrsQueuingCapability {
        frs_queue_max_depth: 0x55,
        frs_interrupt_message_number: 6,
    },
    frs_queuing_status: FrsQueuingStatus {
        frs_message_received: true,
        frs_message_overflow: false,
    },
    frs_queuing_control: FrsQueuingControl {
        frs_interrupt_enable: false,
    },
    frs_message_queue: FrsMessageQueue {
        frs_message_queue_function_id: 0x8001,
        frs_message_queue_reason: 0xC,
        frs_message_queue_depth: 0xC0,
    },
};

assert_eq!(sample, result);
```
*/

use heterob::{bit_numbering::Lsb, endianness::Le, Seq, P2, P3, P4};

use super::{ExtendedCapabilityDataError, ExtendedCapabilityHeader};

/// FRS Queueing
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrsQueuing {
    pub frs_queuing_capability: FrsQueuingCapability,
    pub frs_queuing_status: FrsQueuingStatus,
    pub frs_queuing_control: FrsQueuingControl,
    pub frs_message_queue: FrsMessageQueue,
}

impl FrsQueuing {
    /// Size in bytes (with Extended Capability Header)
    pub const SIZE: usize = ExtendedCapabilityHeader::SIZE
        + FrsQueuingCapability::SIZE
        + FrsQueuingStatus::SIZE
        + FrsQueuingControl::SIZE
        + FrsMessageQueue::SIZE;
}

impl TryFrom<&[u8]> for FrsQueuing {
    type Error = ExtendedCapabilityDataError;

    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
        // Skip header
        let slice = slice
            .get(ExtendedCapabilityHeader::SIZE..)
            .unwrap_or_default();
        let Seq {
            head:
                Le((frs_queuing_capability, frs_queuing_status, frs_queuing_control, frs_message_queue)),
            ..
        } = P4(slice)
            .try_into()
            .map_err(|_| ExtendedCapabilityDataError {
                name: "FRS Queuing",
                size: Self::SIZE,
            })?;
        Ok(Self {
            frs_queuing_capability: From::<u32>::from(frs_queuing_capability),
            frs_queuing_status: From::<u16>::from(frs_queuing_status),
            frs_queuing_control: From::<u16>::from(frs_queuing_control),
            frs_message_queue: From::<u32>::from(frs_message_queue),
        })
    }
}

/// FRS Queuing Capability
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrsQueuingCapability {
    /// Indicates the implemented queue depth, with valid values ranging from
    /// 001h (queue depth of 1) to FFFh (queue depth of 4095)
    pub frs_queue_max_depth: u16,
    /// Indicates which MSI/MSI-X vector is used for the interrupt message
    /// generated in association with FRS Message Received or FRS Message Overflow
    pub frs_interrupt_message_number: u8,
}

impl FrsQueuingCapability {
    pub const SIZE: usize = 4;
}

impl From<u32> for FrsQueuingCapability {
    fn from(dword: u32) -> Self {
        let Lsb((frs_queue_max_depth, (), frs_interrupt_message_number, ())) =
            P4::<_, 12, 4, 5, 11>(dword).into();
        Self {
            frs_queue_max_depth,
            frs_interrupt_message_number,
        }
    }
}

/// FRS Queuing Status
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrsQueuingStatus {
    /// This bit is Set when a new FRS Message is Received or generated by this
    /// Root Port or Root Complex Event Collector
    pub frs_message_received: bool,
    /// This bit is set if the FRS Message queue is full and a new FRS Message
    /// is received or generated by this Root Port or Root Complex Event Collector
    pub frs_message_overflow: bool,
}

impl FrsQueuingStatus {
    pub const SIZE: usize = 2;
}

impl From<u16> for FrsQueuingStatus {
    fn from(word: u16) -> Self {
        let Lsb((frs_message_received, frs_message_overflow, ())) = P3::<_, 1, 1, 14>(word).into();
        Self {
            frs_message_received,
            frs_message_overflow,
        }
    }
}

/// FRS Queuing Control
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrsQueuingControl {
    /// When Set and MSI or MSI-X is enabled, the Port must issue an MSI/
    /// MSI-X interrupt to indicate the 0b to 1b transition of either the FRS Message
    /// Received or the FRS Message Overflow bits
    pub frs_interrupt_enable: bool,
}

impl FrsQueuingControl {
    pub const SIZE: usize = 2;
}

impl From<u16> for FrsQueuingControl {
    fn from(word: u16) -> Self {
        let Lsb((frs_interrupt_enable, ())) = P2::<_, 1, 15>(word).into();
        Self {
            frs_interrupt_enable,
        }
    }
}

/// FRS Message Queue
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrsMessageQueue {
    /// Recorded from the Requester ID of the oldest FRS Message received or
    /// generated by this Root Port or Root Complex Event Collector and still in the
    /// queue
    pub frs_message_queue_function_id: u16,
    /// Recorded from the FRS Reason of the oldest FRS Message received or
    /// generated by this Root Port or Root Complex Event Collector and still in the
    /// queue
    pub frs_message_queue_reason: u8,
    /// Indicates the current number of FRS Messages in the queue
    pub frs_message_queue_depth: u16,
}

impl FrsMessageQueue {
    pub const SIZE: usize = 4;
}

impl From<u32> for FrsMessageQueue {
    fn from(dword: u32) -> Self {
        let Lsb((frs_message_queue_function_id, frs_message_queue_reason, frs_message_queue_depth)) =
            P3::<_, 16, 4, 12>(dword).into();
        Self {
            frs_message_queue_function_id,
            frs_message_queue_reason,
            frs_message_queue_depth,
        }
    }
}