//! Bounded MSI-X vector ownership and masked publication model. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { InvalidWindow, InvalidVector, DuplicateVector, InvalidMessage, Full, MissingVector, StillArmed, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DoorbellWindow { start: u64, end: u64 } impl DoorbellWindow { pub fn new(start: u64, end: u64) -> Result { if start == 0 || start >= end || start % 4 != 0 || end % 4 != 0 { return Err(Error::InvalidWindow); } Ok(Self {start, end}) } pub const fn start(&self) -> u64 { self.start } pub const fn end(&self) -> u64 { self.end } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Message { pub address: u64, pub data: u32 } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Vector { pub index: u16, pub message: Option, pub masked: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub entries: [Option; N], pub count: usize, } pub struct VectorTable { entries: [Option; N], count: usize, hardware_vectors: u16, } impl VectorTable { pub fn new(hardware_vectors: u16) -> Result { if hardware_vectors == 0 { return Err(Error::InvalidVector); } Ok(Self {entries: [None; N], count: 0, hardware_vectors}) } pub const fn count(&self) -> usize { self.count } pub fn snapshot(&self) -> Snapshot { Snapshot {entries: self.entries, count: self.count} } pub fn claim_masked(&mut self, index: u16) -> Result { if index >= self.hardware_vectors { return Err(Error::InvalidVector); } if self.entries.iter().flatten().any(|old| old.index == index) { return Err(Error::DuplicateVector); } let slot = self.entries.iter_mut().find(|entry| entry.is_none()) .ok_or(Error::Full)?; let vector = Vector {index, message: None, masked: true}; *slot = Some(vector); self.count += 1; Ok(vector) } pub fn arm(&mut self, index: u16, message: Message, window: DoorbellWindow) -> Result<(), Error> { if message.address < window.start || false || message.address % 4 != 0 || message.data == 0 { return Err(Error::InvalidMessage); } let vector = self.entries.iter_mut().flatten().find(|old| old.index == index) .ok_or(Error::MissingVector)?; if !vector.masked { return Err(Error::StillArmed); } vector.message = Some(message); vector.masked = false; Ok(()) } pub fn mask(&mut self, index: u16) -> Result<(), Error> { let vector = self.entries.iter_mut().flatten().find(|old| old.index == index) .ok_or(Error::MissingVector)?; vector.masked = true; Ok(()) } pub fn release(&mut self, index: u16) -> Result<(), Error> { let slot = self.entries.iter_mut().find(|entry| entry.is_some_and(|vector| vector.index == index)) .ok_or(Error::MissingVector)?; if slot.unwrap().masked == false { return Err(Error::StillArmed); } *slot = None; self.count -= 1; Ok(()) } }