Lazily acquire MSI-X resources
This commit is contained in:
parent
de0f8d1e54
commit
97a77c2884
|
|
@ -279,6 +279,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"component",
|
||||
"fdt",
|
||||
"int-to-c-enum",
|
||||
"log",
|
||||
"ostd",
|
||||
"spin",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ align_ext.workspace = true
|
|||
bitflags.workspace = true
|
||||
cfg-if.workspace = true
|
||||
component.workspace = true
|
||||
int-to-c-enum.workspace = true
|
||||
log.workspace = true
|
||||
ostd.workspace = true
|
||||
spin.workspace = true
|
||||
|
|
|
|||
|
|
@ -5,80 +5,83 @@
|
|||
use alloc::vec::Vec;
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use int_to_c_enum::TryFromInt;
|
||||
use ostd::Result;
|
||||
|
||||
use self::{msix::CapabilityMsixData, vendor::CapabilityVndrData};
|
||||
use super::{cfg_space::Status, common_device::PciCommonDevice};
|
||||
use crate::cfg_space::PciGeneralDeviceCfgOffset;
|
||||
use self::{
|
||||
msix::{CapabilityMsixData, RawCapabilityMsix},
|
||||
vendor::{CapabilityVndrData, RawCapabilityVndr},
|
||||
};
|
||||
use crate::{
|
||||
PciDeviceLocation,
|
||||
cfg_space::{PciGeneralDeviceCfgOffset, Status},
|
||||
common_device::{BarManager, PciCommonDevice},
|
||||
};
|
||||
|
||||
pub mod msix;
|
||||
pub mod vendor;
|
||||
|
||||
/// PCI Capability
|
||||
#[derive(Debug)]
|
||||
pub struct Capability {
|
||||
cap_data: CapabilityData,
|
||||
/// Raw PCI Capabilities.
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct RawCapabilities {
|
||||
msix: Option<RawCapabilityMsix>,
|
||||
vndr: Vec<RawCapabilityVndr>,
|
||||
}
|
||||
|
||||
/// PCI Capability data.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CapabilityData {
|
||||
/// Id:0x01, Power Management
|
||||
Pm,
|
||||
/// Id:0x02, Accelerated Graphics Part
|
||||
Agp,
|
||||
/// Id:0x03, Vital Product Data
|
||||
Vpd,
|
||||
/// Id:0x04, Slot Identification
|
||||
SlotId,
|
||||
/// Id:0x05, Message Signalled Interrupts
|
||||
Msi,
|
||||
/// Id:0x06, CompactPCI HotSwap
|
||||
Chswp,
|
||||
/// Id:0x07, PCI-X
|
||||
PciX,
|
||||
/// Id:0x08, HyperTransport
|
||||
Hp,
|
||||
/// Id:0x09, Vendor-Specific
|
||||
Vndr(CapabilityVndrData),
|
||||
/// Id:0x0A, Debug port
|
||||
Dbg,
|
||||
/// Id:0x0B, CompactPCI Central Resource Control
|
||||
Ccrc,
|
||||
/// Id:0x0C, PCI Standard Hot-Plug Controller
|
||||
Shpc,
|
||||
/// Id:0x0D, Bridge subsystem vendor/device ID
|
||||
Ssvid,
|
||||
/// Id:0x0R, AGP Target PCI-PCI bridge
|
||||
Agp3,
|
||||
/// Id:0x0F, Secure Device
|
||||
Secdev,
|
||||
/// Id:0x10, PCI Express
|
||||
Exp,
|
||||
/// Id:0x11, MSI-X
|
||||
Msix(CapabilityMsixData),
|
||||
/// Id:0x12, SATA Data/Index Conf
|
||||
Sata,
|
||||
/// Id:0x13, PCI Advanced Features
|
||||
Af,
|
||||
/// Id:0x14, Enhanced Allocation
|
||||
Ea,
|
||||
/// Id:?, Unknown
|
||||
Unknown(u8),
|
||||
/// PCI capability types.
|
||||
#[derive(Debug, Clone, Copy, TryFromInt)]
|
||||
#[repr(u8)]
|
||||
enum CapabilityType {
|
||||
/// Power Management
|
||||
Pm = 0x01,
|
||||
/// Accelerated Graphics Part
|
||||
Agp = 0x02,
|
||||
/// Vital Product Data
|
||||
Vpd = 0x03,
|
||||
/// Slot Identification
|
||||
SlotId = 0x04,
|
||||
/// Message Signalled Interrupts
|
||||
Msi = 0x05,
|
||||
/// CompactPCI HotSwap
|
||||
Chswp = 0x06,
|
||||
/// PCI-X
|
||||
PciX = 0x07,
|
||||
/// HyperTransport
|
||||
Hp = 0x08,
|
||||
/// Vendor-Specific
|
||||
Vndr = 0x09,
|
||||
/// Debug port
|
||||
Dbg = 0x0A,
|
||||
/// CompactPCI Central Resource Control
|
||||
Ccrc = 0x0B,
|
||||
/// PCI Standard Hot-Plug Controller
|
||||
Shpc = 0x0C,
|
||||
/// Bridge subsystem vendor/device ID
|
||||
Ssvid = 0x0D,
|
||||
/// AGP Target PCI-PCI bridge
|
||||
Agp3 = 0x0E,
|
||||
/// Secure Device
|
||||
Secdev = 0x0F,
|
||||
/// PCI Express
|
||||
Exp = 0x10,
|
||||
/// MSI-X
|
||||
Msix = 0x11,
|
||||
/// SATA Data/Index Conf
|
||||
Sata = 0x12,
|
||||
/// PCI Advanced Features
|
||||
Af = 0x13,
|
||||
/// Enhanced Allocation
|
||||
Ea = 0x14,
|
||||
}
|
||||
|
||||
impl Capability {
|
||||
impl RawCapabilities {
|
||||
/// The top of the capability position.
|
||||
const CAPABILITY_TOP: u16 = 0xFC;
|
||||
|
||||
/// Gets the capability data
|
||||
pub fn capability_data(&self) -> &CapabilityData {
|
||||
&self.cap_data
|
||||
}
|
||||
|
||||
/// Gets the capabilities of one device
|
||||
pub(super) fn device_capabilities(dev: &mut PciCommonDevice) -> Vec<Self> {
|
||||
/// Parses the capabilities of the PCI device.
|
||||
pub(super) fn parse(dev: &PciCommonDevice) -> Self {
|
||||
if !dev.read_status().contains(Status::CAPABILITIES_LIST) {
|
||||
return Vec::new();
|
||||
return Self::default();
|
||||
}
|
||||
|
||||
// The offset of the first capability pointer is the same for PCI general devices and PCI
|
||||
|
|
@ -87,7 +90,6 @@ impl Capability {
|
|||
let mut cap_ptr =
|
||||
(dev.location().read8(CAP_OFFSET) as u16).align_down(align_of::<u32>() as _);
|
||||
let mut cap_ptr_vec = Vec::new();
|
||||
let mut capabilities = Vec::new();
|
||||
|
||||
// Read all capability pointers so that it is easy for us to get the length of each
|
||||
// capability.
|
||||
|
|
@ -100,39 +102,60 @@ impl Capability {
|
|||
// Push the top position so that we can calculate the length of the last capability.
|
||||
cap_ptr_vec.push(Self::CAPABILITY_TOP);
|
||||
|
||||
let mut caps = Self::default();
|
||||
|
||||
let length = cap_ptr_vec.len();
|
||||
for i in 0..length - 1 {
|
||||
let cap_ptr = cap_ptr_vec[i];
|
||||
let next_ptr = cap_ptr_vec[i + 1];
|
||||
let cap_type = dev.location().read8(cap_ptr);
|
||||
let data = match cap_type {
|
||||
0x01 => CapabilityData::Pm,
|
||||
0x02 => CapabilityData::Agp,
|
||||
0x03 => CapabilityData::Vpd,
|
||||
0x04 => CapabilityData::SlotId,
|
||||
0x05 => CapabilityData::Msi,
|
||||
0x06 => CapabilityData::Chswp,
|
||||
0x07 => CapabilityData::PciX,
|
||||
0x08 => CapabilityData::Hp,
|
||||
0x09 => {
|
||||
CapabilityData::Vndr(CapabilityVndrData::new(dev, cap_ptr, next_ptr - cap_ptr))
|
||||
}
|
||||
0x0A => CapabilityData::Dbg,
|
||||
0x0B => CapabilityData::Ccrc,
|
||||
0x0C => CapabilityData::Shpc,
|
||||
0x0D => CapabilityData::Ssvid,
|
||||
0x0E => CapabilityData::Agp3,
|
||||
0x0F => CapabilityData::Secdev,
|
||||
0x10 => CapabilityData::Exp,
|
||||
0x11 => CapabilityData::Msix(CapabilityMsixData::new(dev, cap_ptr)),
|
||||
0x12 => CapabilityData::Sata,
|
||||
0x13 => CapabilityData::Af,
|
||||
0x14 => CapabilityData::Ea,
|
||||
_ => CapabilityData::Unknown(cap_type),
|
||||
let raw_cap_type = dev.location().read8(cap_ptr);
|
||||
|
||||
let Ok(cap_type) = CapabilityType::try_from(raw_cap_type) else {
|
||||
continue;
|
||||
};
|
||||
capabilities.push(Self { cap_data: data });
|
||||
match cap_type {
|
||||
CapabilityType::Msix => {
|
||||
// "More than one MSI-X Capability structure per Function is prohibited."
|
||||
if caps.msix.is_some() {
|
||||
log::warn!(
|
||||
"superfluous MSI-X Capability structures at {:?} are ignored",
|
||||
dev.location()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
caps.msix = Some(RawCapabilityMsix::parse(dev, cap_ptr));
|
||||
}
|
||||
CapabilityType::Vndr => {
|
||||
caps.vndr
|
||||
.push(RawCapabilityVndr::new(cap_ptr, next_ptr - cap_ptr));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
capabilities
|
||||
caps
|
||||
}
|
||||
|
||||
/// Acquires a new [`CapabilityMsixData`] instance.
|
||||
pub(super) fn acquire_msix_data(
|
||||
&self,
|
||||
loc: &PciDeviceLocation,
|
||||
bar_manager: &mut BarManager,
|
||||
) -> Result<Option<CapabilityMsixData>> {
|
||||
let Some(raw_msix) = self.msix.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
Ok(Some(CapabilityMsixData::new(loc, bar_manager, raw_msix)?))
|
||||
}
|
||||
|
||||
/// Iterates over [`CapabilityVndrData`] instances.
|
||||
pub(super) fn iter_vndr_data(
|
||||
&self,
|
||||
loc: &PciDeviceLocation,
|
||||
) -> impl Iterator<Item = CapabilityVndrData> {
|
||||
self.vndr
|
||||
.iter()
|
||||
.map(|raw_vndr| CapabilityVndrData::new(loc, raw_vndr))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,42 @@
|
|||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use ostd::{io::IoMem, irq::IrqLine, mm::VmIoOnce};
|
||||
use ostd::{Error, Result, io::IoMem, irq::IrqLine, mm::VmIoOnce};
|
||||
|
||||
use crate::{
|
||||
PciDeviceLocation,
|
||||
arch::{MSIX_DEFAULT_MSG_ADDR, construct_remappable_msix_address},
|
||||
cfg_space::{BarAccess, Command},
|
||||
common_device::PciCommonDevice,
|
||||
cfg_space::{BarAccess, Command, PciCommonCfgOffset},
|
||||
common_device::{BarManager, PciCommonDevice},
|
||||
};
|
||||
|
||||
/// MSI-X capability. It will set the BAR space it uses to be hidden.
|
||||
/// Raw information about MSI-X capability.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct RawCapabilityMsix {
|
||||
cap_ptr: u16,
|
||||
msg_ctrl: u16,
|
||||
table_info: u32,
|
||||
pba_info: u32,
|
||||
}
|
||||
|
||||
impl RawCapabilityMsix {
|
||||
pub(super) fn parse(dev: &PciCommonDevice, cap_ptr: u16) -> Self {
|
||||
let msg_ctrl = dev.location().read16(cap_ptr + 2);
|
||||
let table_info = dev.location().read32(cap_ptr + 4);
|
||||
let pba_info = dev.location().read32(cap_ptr + 8);
|
||||
|
||||
Self {
|
||||
cap_ptr,
|
||||
msg_ctrl,
|
||||
table_info,
|
||||
pba_info,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// MSI-X capability.
|
||||
///
|
||||
/// It will acquire the access to the BAR space it uses.
|
||||
#[derive(Debug)]
|
||||
pub struct CapabilityMsixData {
|
||||
loc: PciDeviceLocation,
|
||||
|
|
@ -23,69 +49,41 @@ pub struct CapabilityMsixData {
|
|||
/// | Vector Control: u32 | Msg Data: u32 | Msg Upper Addr: u32 | Msg Addr: u32 |
|
||||
table_bar: IoMem,
|
||||
/// Pending bits table.
|
||||
#[expect(dead_code)]
|
||||
pending_table_bar: IoMem,
|
||||
table_offset: usize,
|
||||
#[expect(dead_code)]
|
||||
pending_table_offset: usize,
|
||||
irqs: Vec<Option<IrqLine>>,
|
||||
}
|
||||
|
||||
impl Clone for CapabilityMsixData {
|
||||
fn clone(&self) -> Self {
|
||||
let new_vec = self.irqs.clone().to_vec();
|
||||
Self {
|
||||
loc: self.loc,
|
||||
ptr: self.ptr,
|
||||
table_size: self.table_size,
|
||||
table_bar: self.table_bar.clone(),
|
||||
pending_table_bar: self.pending_table_bar.clone(),
|
||||
irqs: new_vec,
|
||||
table_offset: self.table_offset,
|
||||
pending_table_offset: self.pending_table_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CapabilityMsixData {
|
||||
pub(super) fn new(dev: &mut PciCommonDevice, cap_ptr: u16) -> Self {
|
||||
// Get Table and PBA offset, provide functions to modify them
|
||||
let table_info = dev.location().read32(cap_ptr + 4);
|
||||
let pba_info = dev.location().read32(cap_ptr + 8);
|
||||
|
||||
let table_bar;
|
||||
let pba_bar;
|
||||
|
||||
let bar_manager = dev.bar_manager_mut();
|
||||
match bar_manager
|
||||
.bar_mut((pba_info & 0b111) as u8)
|
||||
.expect("MSIX cfg:pba BAR is none")
|
||||
.acquire()
|
||||
.expect("MSIX cfg:pba BAR is unavailable")
|
||||
pub(super) fn new(
|
||||
loc: &PciDeviceLocation,
|
||||
bar_manager: &mut BarManager,
|
||||
raw_cap: &RawCapabilityMsix,
|
||||
) -> Result<Self> {
|
||||
let pba_bar = match bar_manager
|
||||
.bar_mut((raw_cap.pba_info & 0b111) as u8)
|
||||
.ok_or(Error::InvalidArgs)?
|
||||
.acquire()?
|
||||
{
|
||||
BarAccess::Memory(io_mem) => {
|
||||
pba_bar = io_mem.clone();
|
||||
}
|
||||
BarAccess::Io => {
|
||||
panic!("MSIX cfg:pba BAR is IO type")
|
||||
}
|
||||
BarAccess::Memory(io_mem) => io_mem,
|
||||
BarAccess::Io => return Err(Error::InvalidArgs),
|
||||
};
|
||||
match bar_manager
|
||||
.bar_mut((table_info & 0b111) as u8)
|
||||
.expect("MSIX cfg:table BAR is none")
|
||||
.acquire()
|
||||
.expect("MSIX cfg:table BAR is unavailable")
|
||||
let pba_offset = (raw_cap.pba_info & !(0b111u32)) as usize;
|
||||
|
||||
let table_bar = match bar_manager
|
||||
.bar_mut((raw_cap.table_info & 0b111) as u8)
|
||||
.ok_or(Error::InvalidArgs)?
|
||||
.acquire()?
|
||||
{
|
||||
BarAccess::Memory(io_mem) => {
|
||||
table_bar = io_mem.clone();
|
||||
}
|
||||
BarAccess::Io => {
|
||||
panic!("MSIX cfg:table BAR is IO type")
|
||||
}
|
||||
}
|
||||
BarAccess::Memory(io_mem) => io_mem,
|
||||
BarAccess::Io => return Err(Error::InvalidArgs),
|
||||
};
|
||||
let table_offset = (raw_cap.table_info & !(0b111u32)) as usize;
|
||||
|
||||
let pba_offset = (pba_info & !(0b111u32)) as usize;
|
||||
let table_offset = (table_info & !(0b111u32)) as usize;
|
||||
|
||||
let table_size = (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1;
|
||||
let table_size = (raw_cap.msg_ctrl & 0b11_1111_1111) + 1;
|
||||
|
||||
// Set the message address and disable all MSI-X vectors.
|
||||
let message_address = MSIX_DEFAULT_MSG_ADDR;
|
||||
|
|
@ -103,32 +101,37 @@ impl CapabilityMsixData {
|
|||
}
|
||||
|
||||
// Enable MSI-X (bit 15: MSI-X Enable).
|
||||
dev.location()
|
||||
.write16(cap_ptr + 2, dev.location().read16(cap_ptr + 2) | 0x8000);
|
||||
loc.write16(
|
||||
raw_cap.cap_ptr + 2,
|
||||
loc.read16(raw_cap.cap_ptr + 2) | 0x8000,
|
||||
);
|
||||
// Disable INTx. Enable bus master.
|
||||
dev.write_command(dev.read_command() | Command::INTERRUPT_DISABLE | Command::BUS_MASTER);
|
||||
loc.write16(
|
||||
PciCommonCfgOffset::Command as u16,
|
||||
loc.read16(PciCommonCfgOffset::Command as u16)
|
||||
| (Command::INTERRUPT_DISABLE | Command::BUS_MASTER).bits(),
|
||||
);
|
||||
|
||||
let mut irqs = Vec::with_capacity(table_size as usize);
|
||||
for _ in 0..table_size {
|
||||
irqs.push(None);
|
||||
}
|
||||
|
||||
Self {
|
||||
loc: *dev.location(),
|
||||
ptr: cap_ptr,
|
||||
table_size: (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1,
|
||||
Ok(Self {
|
||||
loc: *loc,
|
||||
ptr: raw_cap.cap_ptr,
|
||||
table_size,
|
||||
table_bar,
|
||||
pending_table_bar: pba_bar,
|
||||
irqs,
|
||||
table_offset,
|
||||
pending_table_offset: pba_offset,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the size of the MSI-X Table.
|
||||
pub fn table_size(&self) -> u16 {
|
||||
// bit 10:0 table size
|
||||
(self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1
|
||||
self.table_size
|
||||
}
|
||||
|
||||
/// Enables an interrupt line.
|
||||
|
|
|
|||
|
|
@ -4,10 +4,24 @@
|
|||
|
||||
use ostd::{Error, Result};
|
||||
|
||||
use crate::{PciDeviceLocation, common_device::PciCommonDevice};
|
||||
use crate::PciDeviceLocation;
|
||||
|
||||
/// Vendor specific capability. Users can access this capability area at will,
|
||||
/// except for the PCI configuration space which cannot be accessed at will through this structure.
|
||||
/// Raw information about vendor-specific capability.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct RawCapabilityVndr {
|
||||
cap_ptr: u16,
|
||||
length: u16,
|
||||
}
|
||||
|
||||
impl RawCapabilityVndr {
|
||||
pub(super) fn new(cap_ptr: u16, length: u16) -> Self {
|
||||
Self { cap_ptr, length }
|
||||
}
|
||||
}
|
||||
|
||||
/// Vendor-specific capability.
|
||||
///
|
||||
/// Users can access this capability area at will.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct CapabilityVndrData {
|
||||
location: PciDeviceLocation,
|
||||
|
|
@ -16,11 +30,11 @@ pub struct CapabilityVndrData {
|
|||
}
|
||||
|
||||
impl CapabilityVndrData {
|
||||
pub(super) fn new(dev: &PciCommonDevice, cap_ptr: u16, length: u16) -> Self {
|
||||
pub(super) fn new(loc: &PciDeviceLocation, raw_cap: &RawCapabilityVndr) -> Self {
|
||||
Self {
|
||||
location: *dev.location(),
|
||||
cap_ptr,
|
||||
length,
|
||||
location: *loc,
|
||||
cap_ptr: raw_cap.cap_ptr,
|
||||
length: raw_cap.length,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,16 +2,12 @@
|
|||
|
||||
//! PCI device common definitions or functions.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use ostd::Result;
|
||||
|
||||
use super::{
|
||||
capability::Capability,
|
||||
cfg_space::{AddrLen, Bar, Command, Status},
|
||||
device_info::PciDeviceId,
|
||||
};
|
||||
use crate::{
|
||||
cfg_space::{PciBridgeCfgOffset, PciCommonCfgOffset},
|
||||
device_info::PciDeviceLocation,
|
||||
capability::{RawCapabilities, msix::CapabilityMsixData, vendor::CapabilityVndrData},
|
||||
cfg_space::{AddrLen, Bar, Command, PciBridgeCfgOffset, PciCommonCfgOffset, Status},
|
||||
device_info::{PciDeviceId, PciDeviceLocation},
|
||||
};
|
||||
|
||||
/// PCI common device.
|
||||
|
|
@ -23,7 +19,7 @@ pub struct PciCommonDevice {
|
|||
location: PciDeviceLocation,
|
||||
header_type: PciHeaderType,
|
||||
bar_manager: BarManager,
|
||||
capabilities: Vec<Capability>,
|
||||
capabilities: RawCapabilities,
|
||||
}
|
||||
|
||||
impl PciCommonDevice {
|
||||
|
|
@ -47,16 +43,6 @@ impl PciCommonDevice {
|
|||
&mut self.bar_manager
|
||||
}
|
||||
|
||||
/// Returns the PCI capabilities.
|
||||
pub fn capabilities(&self) -> &Vec<Capability> {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
/// Returns the PCI capabilities and a mutable reference to the BAR manager.
|
||||
pub fn capabilities_and_bar_manager_mut(&mut self) -> (&Vec<Capability>, &mut BarManager) {
|
||||
(&self.capabilities, &mut self.bar_manager)
|
||||
}
|
||||
|
||||
/// Returns the PCI device type.
|
||||
pub fn device_type(&self) -> PciDeviceType {
|
||||
self.header_type.device_type()
|
||||
|
|
@ -83,20 +69,41 @@ impl PciCommonDevice {
|
|||
Status::from_bits_truncate(self.location.read16(PciCommonCfgOffset::Status as u16))
|
||||
}
|
||||
|
||||
/// Acquires necessary resources to build the MSI-X capability data, if the capability exists.
|
||||
///
|
||||
/// Note that the MSI-X capability data occupies some memory BARs. Therefore, it will fail if
|
||||
/// the necessary resources are not available.
|
||||
pub fn acquire_msix_capability(&mut self) -> Result<Option<CapabilityMsixData>> {
|
||||
self.capabilities
|
||||
.acquire_msix_data(&self.location, &mut self.bar_manager)
|
||||
}
|
||||
|
||||
/// Gets access to the vendor-specific capability data.
|
||||
pub fn iter_vndr_capability(&self) -> impl Iterator<Item = CapabilityVndrData> {
|
||||
self.capabilities.iter_vndr_data(&self.location)
|
||||
}
|
||||
|
||||
/// Gets access to the vendor-specific capability data with a mutable reference to the BAR
|
||||
/// manager.
|
||||
pub fn iter_vndr_capability_with_bar_manager(
|
||||
&mut self,
|
||||
) -> (impl Iterator<Item = CapabilityVndrData>, &mut BarManager) {
|
||||
(
|
||||
self.capabilities.iter_vndr_data(&self.location),
|
||||
&mut self.bar_manager,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn new(location: PciDeviceLocation) -> Option<Self> {
|
||||
if location.read16(0) == 0xFFFF {
|
||||
// No device.
|
||||
return None;
|
||||
}
|
||||
|
||||
let capabilities = Vec::new();
|
||||
let device_id = PciDeviceId::new(location);
|
||||
let bar_manager = BarManager {
|
||||
bars: [const { None }; 6],
|
||||
};
|
||||
|
||||
let mut header_type =
|
||||
PciHeaderType::try_from_raw(location.read8(PciCommonCfgOffset::HeaderType as u16))?;
|
||||
|
||||
if let PciDeviceType::PciToPciBridge(primary_bus, secondary_bus, subordinate_bus) =
|
||||
&mut header_type.device_type
|
||||
{
|
||||
|
|
@ -105,6 +112,11 @@ impl PciCommonDevice {
|
|||
*subordinate_bus = location.read8(PciBridgeCfgOffset::SubordinateBusNumber as u16);
|
||||
}
|
||||
|
||||
let bar_manager = BarManager {
|
||||
bars: [const { None }; 6],
|
||||
};
|
||||
let capabilities = RawCapabilities::default();
|
||||
|
||||
let mut device = Self {
|
||||
device_id,
|
||||
location,
|
||||
|
|
@ -121,7 +133,7 @@ impl PciCommonDevice {
|
|||
device.bar_manager = BarManager::new(device.header_type.device_type(), location);
|
||||
device.write_command(command_val | (Command::MEMORY_SPACE | Command::IO_SPACE));
|
||||
|
||||
device.capabilities = Capability::device_capabilities(&mut device);
|
||||
device.capabilities = RawCapabilities::parse(&device);
|
||||
|
||||
Some(device)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ use alloc::{boxed::Box, sync::Arc};
|
|||
use core::fmt::Debug;
|
||||
|
||||
use aster_pci::{
|
||||
PciDeviceId, bus::PciDevice, capability::CapabilityData, cfg_space::BarAccess,
|
||||
common_device::PciCommonDevice,
|
||||
PciDeviceId, bus::PciDevice, cfg_space::BarAccess, common_device::PciCommonDevice,
|
||||
};
|
||||
use aster_util::{field_ptr, safe_ptr::SafePtr};
|
||||
use log::{info, warn};
|
||||
|
|
@ -284,15 +283,12 @@ impl VirtioPciModernTransport {
|
|||
|
||||
info!("[Virtio]: Found device:{:?}", device_type);
|
||||
|
||||
let mut msix = None;
|
||||
let mut notify = None;
|
||||
let mut common_cfg = None;
|
||||
let mut device_cfg = None;
|
||||
let (caps, bar_manager) = common_device.capabilities_and_bar_manager_mut();
|
||||
for cap in caps {
|
||||
match cap.capability_data() {
|
||||
CapabilityData::Vndr(vendor) => {
|
||||
let data = VirtioPciCapabilityData::new(bar_manager, *vendor);
|
||||
let (vndr_caps, bar_manager) = common_device.iter_vndr_capability_with_bar_manager();
|
||||
for vndr_cap in vndr_caps {
|
||||
let data = VirtioPciCapabilityData::new(bar_manager, vndr_cap);
|
||||
match data.typ() {
|
||||
VirtioPciCpabilityType::CommonCfg => {
|
||||
common_cfg = Some(VirtioPciCommonCfg::new(&data));
|
||||
|
|
@ -311,23 +307,14 @@ impl VirtioPciModernTransport {
|
|||
VirtioPciCpabilityType::PciCfg => {}
|
||||
}
|
||||
}
|
||||
CapabilityData::Msix(data) => {
|
||||
msix = Some(data.clone());
|
||||
}
|
||||
CapabilityData::Unknown(id) => {
|
||||
panic!("unknown capability: {}", id)
|
||||
}
|
||||
_ => {
|
||||
panic!("PCI Virtio device should not have other type of capability")
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Support interrupt without MSI-X
|
||||
let msix = msix.unwrap();
|
||||
let notify = notify.unwrap();
|
||||
let common_cfg = common_cfg.unwrap();
|
||||
let device_cfg = device_cfg.unwrap();
|
||||
|
||||
// TODO: Support interrupt without MSI-X.
|
||||
let msix = common_device.acquire_msix_capability().unwrap().unwrap();
|
||||
let msix_manager = VirtioMsixManager::new(msix);
|
||||
|
||||
Ok(Self {
|
||||
common_device,
|
||||
common_cfg,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use alloc::{boxed::Box, collections::vec_deque::VecDeque, sync::Arc};
|
|||
|
||||
use aster_pci::{
|
||||
bus::{PciDevice, PciDriver},
|
||||
capability::CapabilityData,
|
||||
common_device::PciCommonDevice,
|
||||
};
|
||||
use ostd::{bus::BusProbeError, sync::SpinLock};
|
||||
|
|
@ -42,10 +41,7 @@ impl PciDriver for VirtioPciDriver {
|
|||
return Err((BusProbeError::DeviceNotMatch, device));
|
||||
}
|
||||
|
||||
let has_vendor_cap = device
|
||||
.capabilities()
|
||||
.iter()
|
||||
.any(|cap| matches!(cap.capability_data(), CapabilityData::Vndr(_)));
|
||||
let has_vendor_cap = device.iter_vndr_capability().next().is_some();
|
||||
let device_id = *device.device_id();
|
||||
let transport: Box<dyn VirtioTransport> = match device_id.device_id {
|
||||
0x1000..0x1040 if (device.device_id().revision_id == 0) => {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use alloc::{boxed::Box, sync::Arc};
|
||||
use core::fmt::Debug;
|
||||
|
||||
use aster_pci::{capability::CapabilityData, cfg_space::BarAccess, common_device::PciCommonDevice};
|
||||
use aster_pci::{cfg_space::BarAccess, common_device::PciCommonDevice};
|
||||
use aster_util::safe_ptr::SafePtr;
|
||||
use log::{info, warn};
|
||||
use ostd::{
|
||||
|
|
@ -112,17 +112,8 @@ impl VirtioPciLegacyTransport {
|
|||
num_queues += 1;
|
||||
}
|
||||
|
||||
// TODO: Support interrupt without MSI-X
|
||||
let mut msix = None;
|
||||
for cap in common_device.capabilities().iter() {
|
||||
match cap.capability_data() {
|
||||
CapabilityData::Msix(data) => {
|
||||
msix = Some(data.clone());
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
let Some(msix) = msix else {
|
||||
// TODO: Support interrupt without MSI-X.
|
||||
let Ok(Some(msix)) = common_device.acquire_msix_capability() else {
|
||||
return Err((BusProbeError::ConfigurationSpaceError, common_device));
|
||||
};
|
||||
let msix_manager = VirtioMsixManager::new(msix);
|
||||
|
|
|
|||
Loading…
Reference in New Issue