Lazily acquire MSI-X resources

This commit is contained in:
Ruihan Li 2026-01-14 21:19:52 +08:00
parent de0f8d1e54
commit 97a77c2884
9 changed files with 266 additions and 238 deletions

1
Cargo.lock generated
View File

@ -279,6 +279,7 @@ dependencies = [
"cfg-if", "cfg-if",
"component", "component",
"fdt", "fdt",
"int-to-c-enum",
"log", "log",
"ostd", "ostd",
"spin", "spin",

View File

@ -10,6 +10,7 @@ align_ext.workspace = true
bitflags.workspace = true bitflags.workspace = true
cfg-if.workspace = true cfg-if.workspace = true
component.workspace = true component.workspace = true
int-to-c-enum.workspace = true
log.workspace = true log.workspace = true
ostd.workspace = true ostd.workspace = true
spin.workspace = true spin.workspace = true

View File

@ -5,80 +5,83 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use align_ext::AlignExt; use align_ext::AlignExt;
use int_to_c_enum::TryFromInt;
use ostd::Result;
use self::{msix::CapabilityMsixData, vendor::CapabilityVndrData}; use self::{
use super::{cfg_space::Status, common_device::PciCommonDevice}; msix::{CapabilityMsixData, RawCapabilityMsix},
use crate::cfg_space::PciGeneralDeviceCfgOffset; vendor::{CapabilityVndrData, RawCapabilityVndr},
};
use crate::{
PciDeviceLocation,
cfg_space::{PciGeneralDeviceCfgOffset, Status},
common_device::{BarManager, PciCommonDevice},
};
pub mod msix; pub mod msix;
pub mod vendor; pub mod vendor;
/// PCI Capability /// Raw PCI Capabilities.
#[derive(Debug)] #[derive(Debug, Default)]
pub struct Capability { pub(super) struct RawCapabilities {
cap_data: CapabilityData, msix: Option<RawCapabilityMsix>,
vndr: Vec<RawCapabilityVndr>,
} }
/// PCI Capability data. /// PCI capability types.
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy, TryFromInt)]
pub enum CapabilityData { #[repr(u8)]
/// Id:0x01, Power Management enum CapabilityType {
Pm, /// Power Management
/// Id:0x02, Accelerated Graphics Part Pm = 0x01,
Agp, /// Accelerated Graphics Part
/// Id:0x03, Vital Product Data Agp = 0x02,
Vpd, /// Vital Product Data
/// Id:0x04, Slot Identification Vpd = 0x03,
SlotId, /// Slot Identification
/// Id:0x05, Message Signalled Interrupts SlotId = 0x04,
Msi, /// Message Signalled Interrupts
/// Id:0x06, CompactPCI HotSwap Msi = 0x05,
Chswp, /// CompactPCI HotSwap
/// Id:0x07, PCI-X Chswp = 0x06,
PciX, /// PCI-X
/// Id:0x08, HyperTransport PciX = 0x07,
Hp, /// HyperTransport
/// Id:0x09, Vendor-Specific Hp = 0x08,
Vndr(CapabilityVndrData), /// Vendor-Specific
/// Id:0x0A, Debug port Vndr = 0x09,
Dbg, /// Debug port
/// Id:0x0B, CompactPCI Central Resource Control Dbg = 0x0A,
Ccrc, /// CompactPCI Central Resource Control
/// Id:0x0C, PCI Standard Hot-Plug Controller Ccrc = 0x0B,
Shpc, /// PCI Standard Hot-Plug Controller
/// Id:0x0D, Bridge subsystem vendor/device ID Shpc = 0x0C,
Ssvid, /// Bridge subsystem vendor/device ID
/// Id:0x0R, AGP Target PCI-PCI bridge Ssvid = 0x0D,
Agp3, /// AGP Target PCI-PCI bridge
/// Id:0x0F, Secure Device Agp3 = 0x0E,
Secdev, /// Secure Device
/// Id:0x10, PCI Express Secdev = 0x0F,
Exp, /// PCI Express
/// Id:0x11, MSI-X Exp = 0x10,
Msix(CapabilityMsixData), /// MSI-X
/// Id:0x12, SATA Data/Index Conf Msix = 0x11,
Sata, /// SATA Data/Index Conf
/// Id:0x13, PCI Advanced Features Sata = 0x12,
Af, /// PCI Advanced Features
/// Id:0x14, Enhanced Allocation Af = 0x13,
Ea, /// Enhanced Allocation
/// Id:?, Unknown Ea = 0x14,
Unknown(u8),
} }
impl Capability { impl RawCapabilities {
/// The top of the capability position. /// The top of the capability position.
const CAPABILITY_TOP: u16 = 0xFC; const CAPABILITY_TOP: u16 = 0xFC;
/// Gets the capability data /// Parses the capabilities of the PCI device.
pub fn capability_data(&self) -> &CapabilityData { pub(super) fn parse(dev: &PciCommonDevice) -> Self {
&self.cap_data
}
/// Gets the capabilities of one device
pub(super) fn device_capabilities(dev: &mut PciCommonDevice) -> Vec<Self> {
if !dev.read_status().contains(Status::CAPABILITIES_LIST) { 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 // 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 = let mut cap_ptr =
(dev.location().read8(CAP_OFFSET) as u16).align_down(align_of::<u32>() as _); (dev.location().read8(CAP_OFFSET) as u16).align_down(align_of::<u32>() as _);
let mut cap_ptr_vec = Vec::new(); 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 // Read all capability pointers so that it is easy for us to get the length of each
// capability. // capability.
@ -100,39 +102,60 @@ impl Capability {
// Push the top position so that we can calculate the length of the last capability. // Push the top position so that we can calculate the length of the last capability.
cap_ptr_vec.push(Self::CAPABILITY_TOP); cap_ptr_vec.push(Self::CAPABILITY_TOP);
let mut caps = Self::default();
let length = cap_ptr_vec.len(); let length = cap_ptr_vec.len();
for i in 0..length - 1 { for i in 0..length - 1 {
let cap_ptr = cap_ptr_vec[i]; let cap_ptr = cap_ptr_vec[i];
let next_ptr = cap_ptr_vec[i + 1]; let next_ptr = cap_ptr_vec[i + 1];
let cap_type = dev.location().read8(cap_ptr); let raw_cap_type = dev.location().read8(cap_ptr);
let data = match cap_type {
0x01 => CapabilityData::Pm, let Ok(cap_type) = CapabilityType::try_from(raw_cap_type) else {
0x02 => CapabilityData::Agp, continue;
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),
}; };
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))
} }
} }

View File

@ -4,16 +4,42 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use ostd::{io::IoMem, irq::IrqLine, mm::VmIoOnce}; use ostd::{Error, Result, io::IoMem, irq::IrqLine, mm::VmIoOnce};
use crate::{ use crate::{
PciDeviceLocation, PciDeviceLocation,
arch::{MSIX_DEFAULT_MSG_ADDR, construct_remappable_msix_address}, arch::{MSIX_DEFAULT_MSG_ADDR, construct_remappable_msix_address},
cfg_space::{BarAccess, Command}, cfg_space::{BarAccess, Command, PciCommonCfgOffset},
common_device::PciCommonDevice, 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)] #[derive(Debug)]
pub struct CapabilityMsixData { pub struct CapabilityMsixData {
loc: PciDeviceLocation, loc: PciDeviceLocation,
@ -23,69 +49,41 @@ pub struct CapabilityMsixData {
/// | Vector Control: u32 | Msg Data: u32 | Msg Upper Addr: u32 | Msg Addr: u32 | /// | Vector Control: u32 | Msg Data: u32 | Msg Upper Addr: u32 | Msg Addr: u32 |
table_bar: IoMem, table_bar: IoMem,
/// Pending bits table. /// Pending bits table.
#[expect(dead_code)]
pending_table_bar: IoMem, pending_table_bar: IoMem,
table_offset: usize, table_offset: usize,
#[expect(dead_code)]
pending_table_offset: usize, pending_table_offset: usize,
irqs: Vec<Option<IrqLine>>, 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 { impl CapabilityMsixData {
pub(super) fn new(dev: &mut PciCommonDevice, cap_ptr: u16) -> Self { pub(super) fn new(
// Get Table and PBA offset, provide functions to modify them loc: &PciDeviceLocation,
let table_info = dev.location().read32(cap_ptr + 4); bar_manager: &mut BarManager,
let pba_info = dev.location().read32(cap_ptr + 8); raw_cap: &RawCapabilityMsix,
) -> Result<Self> {
let table_bar; let pba_bar = match bar_manager
let pba_bar; .bar_mut((raw_cap.pba_info & 0b111) as u8)
.ok_or(Error::InvalidArgs)?
let bar_manager = dev.bar_manager_mut(); .acquire()?
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")
{ {
BarAccess::Memory(io_mem) => { BarAccess::Memory(io_mem) => io_mem,
pba_bar = io_mem.clone(); BarAccess::Io => return Err(Error::InvalidArgs),
}
BarAccess::Io => {
panic!("MSIX cfg:pba BAR is IO type")
}
}; };
match bar_manager let pba_offset = (raw_cap.pba_info & !(0b111u32)) as usize;
.bar_mut((table_info & 0b111) as u8)
.expect("MSIX cfg:table BAR is none") let table_bar = match bar_manager
.acquire() .bar_mut((raw_cap.table_info & 0b111) as u8)
.expect("MSIX cfg:table BAR is unavailable") .ok_or(Error::InvalidArgs)?
.acquire()?
{ {
BarAccess::Memory(io_mem) => { BarAccess::Memory(io_mem) => io_mem,
table_bar = io_mem.clone(); BarAccess::Io => return Err(Error::InvalidArgs),
} };
BarAccess::Io => { let table_offset = (raw_cap.table_info & !(0b111u32)) as usize;
panic!("MSIX cfg:table BAR is IO type")
}
}
let pba_offset = (pba_info & !(0b111u32)) as usize; let table_size = (raw_cap.msg_ctrl & 0b11_1111_1111) + 1;
let table_offset = (table_info & !(0b111u32)) as usize;
let table_size = (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1;
// Set the message address and disable all MSI-X vectors. // Set the message address and disable all MSI-X vectors.
let message_address = MSIX_DEFAULT_MSG_ADDR; let message_address = MSIX_DEFAULT_MSG_ADDR;
@ -103,32 +101,37 @@ impl CapabilityMsixData {
} }
// Enable MSI-X (bit 15: MSI-X Enable). // Enable MSI-X (bit 15: MSI-X Enable).
dev.location() loc.write16(
.write16(cap_ptr + 2, dev.location().read16(cap_ptr + 2) | 0x8000); raw_cap.cap_ptr + 2,
loc.read16(raw_cap.cap_ptr + 2) | 0x8000,
);
// Disable INTx. Enable bus master. // 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); let mut irqs = Vec::with_capacity(table_size as usize);
for _ in 0..table_size { for _ in 0..table_size {
irqs.push(None); irqs.push(None);
} }
Self { Ok(Self {
loc: *dev.location(), loc: *loc,
ptr: cap_ptr, ptr: raw_cap.cap_ptr,
table_size: (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1, table_size,
table_bar, table_bar,
pending_table_bar: pba_bar, pending_table_bar: pba_bar,
irqs, irqs,
table_offset, table_offset,
pending_table_offset: pba_offset, pending_table_offset: pba_offset,
} })
} }
/// Returns the size of the MSI-X Table. /// Returns the size of the MSI-X Table.
pub fn table_size(&self) -> u16 { pub fn table_size(&self) -> u16 {
// bit 10:0 table size self.table_size
(self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1
} }
/// Enables an interrupt line. /// Enables an interrupt line.

View File

@ -4,10 +4,24 @@
use ostd::{Error, Result}; use ostd::{Error, Result};
use crate::{PciDeviceLocation, common_device::PciCommonDevice}; use crate::PciDeviceLocation;
/// Vendor specific capability. Users can access this capability area at will, /// Raw information about vendor-specific capability.
/// except for the PCI configuration space which cannot be accessed at will through this structure. #[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)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CapabilityVndrData { pub struct CapabilityVndrData {
location: PciDeviceLocation, location: PciDeviceLocation,
@ -16,11 +30,11 @@ pub struct CapabilityVndrData {
} }
impl 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 { Self {
location: *dev.location(), location: *loc,
cap_ptr, cap_ptr: raw_cap.cap_ptr,
length, length: raw_cap.length,
} }
} }

View File

@ -2,16 +2,12 @@
//! PCI device common definitions or functions. //! 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::{ use crate::{
cfg_space::{PciBridgeCfgOffset, PciCommonCfgOffset}, capability::{RawCapabilities, msix::CapabilityMsixData, vendor::CapabilityVndrData},
device_info::PciDeviceLocation, cfg_space::{AddrLen, Bar, Command, PciBridgeCfgOffset, PciCommonCfgOffset, Status},
device_info::{PciDeviceId, PciDeviceLocation},
}; };
/// PCI common device. /// PCI common device.
@ -23,7 +19,7 @@ pub struct PciCommonDevice {
location: PciDeviceLocation, location: PciDeviceLocation,
header_type: PciHeaderType, header_type: PciHeaderType,
bar_manager: BarManager, bar_manager: BarManager,
capabilities: Vec<Capability>, capabilities: RawCapabilities,
} }
impl PciCommonDevice { impl PciCommonDevice {
@ -47,16 +43,6 @@ impl PciCommonDevice {
&mut self.bar_manager &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. /// Returns the PCI device type.
pub fn device_type(&self) -> PciDeviceType { pub fn device_type(&self) -> PciDeviceType {
self.header_type.device_type() self.header_type.device_type()
@ -83,20 +69,41 @@ impl PciCommonDevice {
Status::from_bits_truncate(self.location.read16(PciCommonCfgOffset::Status as u16)) 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> { pub(super) fn new(location: PciDeviceLocation) -> Option<Self> {
if location.read16(0) == 0xFFFF { if location.read16(0) == 0xFFFF {
// No device. // No device.
return None; return None;
} }
let capabilities = Vec::new();
let device_id = PciDeviceId::new(location); let device_id = PciDeviceId::new(location);
let bar_manager = BarManager {
bars: [const { None }; 6],
};
let mut header_type = let mut header_type =
PciHeaderType::try_from_raw(location.read8(PciCommonCfgOffset::HeaderType as u16))?; PciHeaderType::try_from_raw(location.read8(PciCommonCfgOffset::HeaderType as u16))?;
if let PciDeviceType::PciToPciBridge(primary_bus, secondary_bus, subordinate_bus) = if let PciDeviceType::PciToPciBridge(primary_bus, secondary_bus, subordinate_bus) =
&mut header_type.device_type &mut header_type.device_type
{ {
@ -105,6 +112,11 @@ impl PciCommonDevice {
*subordinate_bus = location.read8(PciBridgeCfgOffset::SubordinateBusNumber as u16); *subordinate_bus = location.read8(PciBridgeCfgOffset::SubordinateBusNumber as u16);
} }
let bar_manager = BarManager {
bars: [const { None }; 6],
};
let capabilities = RawCapabilities::default();
let mut device = Self { let mut device = Self {
device_id, device_id,
location, location,
@ -121,7 +133,7 @@ impl PciCommonDevice {
device.bar_manager = BarManager::new(device.header_type.device_type(), location); device.bar_manager = BarManager::new(device.header_type.device_type(), location);
device.write_command(command_val | (Command::MEMORY_SPACE | Command::IO_SPACE)); 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) Some(device)
} }

View File

@ -4,8 +4,7 @@ use alloc::{boxed::Box, sync::Arc};
use core::fmt::Debug; use core::fmt::Debug;
use aster_pci::{ use aster_pci::{
PciDeviceId, bus::PciDevice, capability::CapabilityData, cfg_space::BarAccess, PciDeviceId, bus::PciDevice, cfg_space::BarAccess, common_device::PciCommonDevice,
common_device::PciCommonDevice,
}; };
use aster_util::{field_ptr, safe_ptr::SafePtr}; use aster_util::{field_ptr, safe_ptr::SafePtr};
use log::{info, warn}; use log::{info, warn};
@ -284,50 +283,38 @@ impl VirtioPciModernTransport {
info!("[Virtio]: Found device:{:?}", device_type); info!("[Virtio]: Found device:{:?}", device_type);
let mut msix = None;
let mut notify = None; let mut notify = None;
let mut common_cfg = None; let mut common_cfg = None;
let mut device_cfg = None; let mut device_cfg = None;
let (caps, bar_manager) = common_device.capabilities_and_bar_manager_mut(); let (vndr_caps, bar_manager) = common_device.iter_vndr_capability_with_bar_manager();
for cap in caps { for vndr_cap in vndr_caps {
match cap.capability_data() { let data = VirtioPciCapabilityData::new(bar_manager, vndr_cap);
CapabilityData::Vndr(vendor) => { match data.typ() {
let data = VirtioPciCapabilityData::new(bar_manager, *vendor); VirtioPciCpabilityType::CommonCfg => {
match data.typ() { common_cfg = Some(VirtioPciCommonCfg::new(&data));
VirtioPciCpabilityType::CommonCfg => {
common_cfg = Some(VirtioPciCommonCfg::new(&data));
}
VirtioPciCpabilityType::NotifyCfg => {
notify = Some(VirtioPciNotify {
offset_multiplier: data.option_value().unwrap(),
offset: data.offset(),
io_memory: data.memory_bar().unwrap().clone(),
});
}
VirtioPciCpabilityType::IsrCfg => {}
VirtioPciCpabilityType::DeviceCfg => {
device_cfg = Some(data);
}
VirtioPciCpabilityType::PciCfg => {}
}
} }
CapabilityData::Msix(data) => { VirtioPciCpabilityType::NotifyCfg => {
msix = Some(data.clone()); notify = Some(VirtioPciNotify {
offset_multiplier: data.option_value().unwrap(),
offset: data.offset(),
io_memory: data.memory_bar().unwrap().clone(),
});
} }
CapabilityData::Unknown(id) => { VirtioPciCpabilityType::IsrCfg => {}
panic!("unknown capability: {}", id) VirtioPciCpabilityType::DeviceCfg => {
} device_cfg = Some(data);
_ => {
panic!("PCI Virtio device should not have other type of capability")
} }
VirtioPciCpabilityType::PciCfg => {}
} }
} }
// TODO: Support interrupt without MSI-X
let msix = msix.unwrap();
let notify = notify.unwrap(); let notify = notify.unwrap();
let common_cfg = common_cfg.unwrap(); let common_cfg = common_cfg.unwrap();
let device_cfg = device_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); let msix_manager = VirtioMsixManager::new(msix);
Ok(Self { Ok(Self {
common_device, common_device,
common_cfg, common_cfg,

View File

@ -4,7 +4,6 @@ use alloc::{boxed::Box, collections::vec_deque::VecDeque, sync::Arc};
use aster_pci::{ use aster_pci::{
bus::{PciDevice, PciDriver}, bus::{PciDevice, PciDriver},
capability::CapabilityData,
common_device::PciCommonDevice, common_device::PciCommonDevice,
}; };
use ostd::{bus::BusProbeError, sync::SpinLock}; use ostd::{bus::BusProbeError, sync::SpinLock};
@ -42,10 +41,7 @@ impl PciDriver for VirtioPciDriver {
return Err((BusProbeError::DeviceNotMatch, device)); return Err((BusProbeError::DeviceNotMatch, device));
} }
let has_vendor_cap = device let has_vendor_cap = device.iter_vndr_capability().next().is_some();
.capabilities()
.iter()
.any(|cap| matches!(cap.capability_data(), CapabilityData::Vndr(_)));
let device_id = *device.device_id(); let device_id = *device.device_id();
let transport: Box<dyn VirtioTransport> = match device_id.device_id { let transport: Box<dyn VirtioTransport> = match device_id.device_id {
0x1000..0x1040 if (device.device_id().revision_id == 0) => { 0x1000..0x1040 if (device.device_id().revision_id == 0) => {

View File

@ -3,7 +3,7 @@
use alloc::{boxed::Box, sync::Arc}; use alloc::{boxed::Box, sync::Arc};
use core::fmt::Debug; 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 aster_util::safe_ptr::SafePtr;
use log::{info, warn}; use log::{info, warn};
use ostd::{ use ostd::{
@ -112,17 +112,8 @@ impl VirtioPciLegacyTransport {
num_queues += 1; num_queues += 1;
} }
// TODO: Support interrupt without MSI-X // TODO: Support interrupt without MSI-X.
let mut msix = None; let Ok(Some(msix)) = common_device.acquire_msix_capability() else {
for cap in common_device.capabilities().iter() {
match cap.capability_data() {
CapabilityData::Msix(data) => {
msix = Some(data.clone());
}
_ => continue,
}
}
let Some(msix) = msix else {
return Err((BusProbeError::ConfigurationSpaceError, common_device)); return Err((BusProbeError::ConfigurationSpaceError, common_device));
}; };
let msix_manager = VirtioMsixManager::new(msix); let msix_manager = VirtioMsixManager::new(msix);