pcid: Move msi from pci to driver_interface
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::driver_interface::PciBar;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use syscall::{Io, Mmio};
|
||||
|
||||
/// The address and data to use for MSI and MSI-X.
|
||||
///
|
||||
/// For MSI using this only works when you need a single interrupt vector.
|
||||
/// For MSI-X you can have a single [MsiEntry] for each interrupt vector.
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct MsiAddrAndData {
|
||||
pub(crate) addr: u64,
|
||||
pub(crate) data: u32,
|
||||
}
|
||||
|
||||
impl MsiAddrAndData {
|
||||
pub fn new(addr: u64, data: u32) -> Self {
|
||||
MsiAddrAndData { addr, data }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct MsiInfo {
|
||||
pub log2_multiple_message_capable: u8,
|
||||
pub is_64bit: bool,
|
||||
pub has_per_vector_masking: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct MsixInfo {
|
||||
pub table_bar: u8,
|
||||
pub table_offset: u32,
|
||||
pub table_size: u16,
|
||||
pub pba_bar: u8,
|
||||
pub pba_offset: u32,
|
||||
}
|
||||
|
||||
impl MsixInfo {
|
||||
pub fn validate(&self, bars: [PciBar; 6]) {
|
||||
if self.table_bar > 5 {
|
||||
panic!(
|
||||
"MSI-X Table BIR contained a reserved enum value: {}",
|
||||
self.table_bar
|
||||
);
|
||||
}
|
||||
if self.pba_bar > 5 {
|
||||
panic!(
|
||||
"MSI-X PBA BIR contained a reserved enum value: {}",
|
||||
self.pba_bar
|
||||
);
|
||||
}
|
||||
|
||||
let table_size = self.table_size;
|
||||
let table_offset = self.table_offset as usize;
|
||||
let table_min_length = table_size * 16;
|
||||
|
||||
let pba_offset = self.pba_offset as usize;
|
||||
let pba_min_length = table_size.div_ceil(8);
|
||||
|
||||
let (_, table_bar_size) = bars[self.table_bar as usize].expect_mem();
|
||||
let (_, pba_bar_size) = bars[self.pba_bar as usize].expect_mem();
|
||||
|
||||
// Ensure that the table and PBA are within the BAR.
|
||||
|
||||
if !(0..table_bar_size as u64).contains(&(table_offset as u64 + table_min_length as u64)) {
|
||||
panic!(
|
||||
"Table {:#x}:{:#x} outside of BAR with length {:#x}",
|
||||
table_offset,
|
||||
table_offset + table_min_length as usize,
|
||||
table_bar_size
|
||||
);
|
||||
}
|
||||
|
||||
if !(0..pba_bar_size as u64).contains(&(pba_offset as u64 + pba_min_length as u64)) {
|
||||
panic!(
|
||||
"PBA {:#x}:{:#x} outside of BAR with length {:#x}",
|
||||
pba_offset,
|
||||
pba_offset + pba_min_length as usize,
|
||||
pba_bar_size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct MsixTableEntry {
|
||||
pub addr_lo: Mmio<u32>,
|
||||
pub addr_hi: Mmio<u32>,
|
||||
pub msg_data: Mmio<u32>,
|
||||
pub vec_ctl: Mmio<u32>,
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub mod x86 {
|
||||
#[repr(u8)]
|
||||
pub enum TriggerMode {
|
||||
Edge = 0,
|
||||
Level = 1,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum LevelTriggerMode {
|
||||
Deassert = 0,
|
||||
Assert = 1,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DeliveryMode {
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001,
|
||||
Smi = 0b010,
|
||||
// 0b011 is reserved
|
||||
Nmi = 0b100,
|
||||
Init = 0b101,
|
||||
// 0b110 is reserved
|
||||
ExtInit = 0b111,
|
||||
}
|
||||
|
||||
// TODO: should the reserved field be preserved?
|
||||
pub const fn message_address(
|
||||
destination_id: u8,
|
||||
redirect_hint: bool,
|
||||
dest_mode_logical: bool,
|
||||
) -> u64 {
|
||||
0x0000_0000_FEE0_0000u64
|
||||
| ((destination_id as u64) << 12)
|
||||
| ((redirect_hint as u64) << 3)
|
||||
| ((dest_mode_logical as u64) << 2)
|
||||
}
|
||||
pub const fn message_data(
|
||||
trigger_mode: TriggerMode,
|
||||
level_trigger_mode: LevelTriggerMode,
|
||||
delivery_mode: DeliveryMode,
|
||||
vector: u8,
|
||||
) -> u32 {
|
||||
((trigger_mode as u32) << 15)
|
||||
| ((level_trigger_mode as u32) << 14)
|
||||
| ((delivery_mode as u32) << 8)
|
||||
| vector as u32
|
||||
}
|
||||
pub const fn message_data_level_triggered(
|
||||
level_trigger_mode: LevelTriggerMode,
|
||||
delivery_mode: DeliveryMode,
|
||||
vector: u8,
|
||||
) -> u32 {
|
||||
message_data(
|
||||
TriggerMode::Level,
|
||||
level_trigger_mode,
|
||||
delivery_mode,
|
||||
vector,
|
||||
)
|
||||
}
|
||||
pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 {
|
||||
message_data(
|
||||
TriggerMode::Edge,
|
||||
LevelTriggerMode::Deassert,
|
||||
delivery_mode,
|
||||
vector,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl MsixTableEntry {
|
||||
pub fn addr_lo(&self) -> u32 {
|
||||
self.addr_lo.read()
|
||||
}
|
||||
pub fn addr_hi(&self) -> u32 {
|
||||
self.addr_hi.read()
|
||||
}
|
||||
pub fn set_addr_lo(&mut self, value: u32) {
|
||||
self.addr_lo.write(value);
|
||||
}
|
||||
pub fn set_addr_hi(&mut self, value: u32) {
|
||||
self.addr_hi.write(value);
|
||||
}
|
||||
pub fn msg_data(&self) -> u32 {
|
||||
self.msg_data.read()
|
||||
}
|
||||
pub fn vec_ctl(&self) -> u32 {
|
||||
self.vec_ctl.read()
|
||||
}
|
||||
pub fn set_msg_data(&mut self, value: u32) {
|
||||
self.msg_data.write(value);
|
||||
}
|
||||
pub fn addr(&self) -> u64 {
|
||||
u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32)
|
||||
}
|
||||
pub const VEC_CTL_MASK_BIT: u32 = 1;
|
||||
|
||||
pub fn set_masked(&mut self, masked: bool) {
|
||||
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, masked)
|
||||
}
|
||||
pub fn mask(&mut self) {
|
||||
self.set_masked(true);
|
||||
}
|
||||
pub fn unmask(&mut self) {
|
||||
self.set_masked(false);
|
||||
}
|
||||
|
||||
pub fn write_addr_and_data(&mut self, entry: MsiAddrAndData) {
|
||||
self.set_addr_lo(entry.addr as u32);
|
||||
self.set_addr_hi((entry.addr >> 32) as u32);
|
||||
self.set_msg_data(entry.data);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MsixTableEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("MsixTableEntry")
|
||||
.field("addr", &self.addr())
|
||||
.field("msg_data", &self.msg_data())
|
||||
.field("vec_ctl", &self.vec_ctl())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user