pcid: Move msi from pci to driver_interface
This commit is contained in:
@@ -8,7 +8,7 @@ use std::fs::{self, File};
|
||||
use std::io::{self, prelude::*};
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
use crate::pci::msi::MsiAddrAndData;
|
||||
use crate::driver_interface::msi::MsiAddrAndData;
|
||||
|
||||
/// Read the local APIC ID of the bootstrap processor.
|
||||
pub fn read_bsp_apic_id() -> io::Result<usize> {
|
||||
@@ -180,7 +180,7 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result<Option<(u8,
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndData, File) {
|
||||
use crate::pci::msi::x86 as x86_msix;
|
||||
use crate::driver_interface::msi::x86 as x86_msix;
|
||||
|
||||
// FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping
|
||||
let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8");
|
||||
|
||||
@@ -9,16 +9,16 @@ use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
pub use crate::pci::msi;
|
||||
pub use crate::pci::PciAddress;
|
||||
pub use bar::PciBar;
|
||||
pub use cap::VendorSpecificCapability;
|
||||
pub use id::FullDeviceId;
|
||||
pub use pci_types::PciAddress;
|
||||
|
||||
mod bar;
|
||||
pub mod cap;
|
||||
mod id;
|
||||
pub mod irq_helpers;
|
||||
pub mod msi;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct LegacyInterruptLine(pub(crate) u8);
|
||||
|
||||
@@ -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