Extract `PciDeviceLocation` in ostd into PCI component

This commit is contained in:
Yuke Peng 2025-08-13 04:30:31 +03:00 committed by Tate, Hongliang Tian
parent bb4c532b4e
commit bb15d4591a
8 changed files with 124 additions and 151 deletions

View File

@ -6,13 +6,12 @@
use alloc::vec::Vec;
use ostd::bus::pci::PciDeviceLocation;
use self::{msix::CapabilityMsixData, vendor::CapabilityVndrData};
use super::{
cfg_space::{PciDeviceCommonCfgOffset, Status},
common_device::PciCommonDevice,
};
use crate::PciDeviceLocation;
pub mod msix;
pub mod vendor;

View File

@ -7,12 +7,13 @@
use alloc::{sync::Arc, vec::Vec};
use ostd::{bus::pci::PciDeviceLocation, irq::IrqLine, mm::VmIoOnce};
use ostd::{irq::IrqLine, mm::VmIoOnce};
use crate::{
arch::{construct_remappable_msix_address, MSIX_DEFAULT_MSG_ADDR},
cfg_space::{Bar, Command, MemoryBar},
common_device::PciCommonDevice,
PciDeviceLocation,
};
/// MSI-X capability. It will set the BAR space it uses to be hidden.

View File

@ -2,9 +2,9 @@
//! Vendor-specific capability support.
use ostd::{bus::pci::PciDeviceLocation, Error, Result};
use ostd::{Error, Result};
use crate::common_device::PciCommonDevice;
use crate::{common_device::PciCommonDevice, 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.

View File

@ -6,13 +6,12 @@
use alloc::vec::Vec;
use ostd::bus::pci::PciDeviceLocation;
use super::{
capability::Capability,
cfg_space::{AddrLen, Bar, Command, PciDeviceCommonCfgOffset, Status},
device_info::PciDeviceId,
};
use crate::device_info::PciDeviceLocation;
/// PCI common device, Contains a range of information and functions common to PCI devices.
#[derive(Debug)]

View File

@ -1,10 +1,121 @@
// SPDX-License-Identifier: MPL-2.0
//! PCI device Information
use ostd::bus::pci::PciDeviceLocation;
use core::iter;
use super::cfg_space::PciDeviceCommonCfgOffset;
/// PCI device Location
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PciDeviceLocation {
/// Bus number
pub bus: u8,
/// Device number with max 31
pub device: u8,
/// Device number with max 7
pub function: u8,
}
impl PciDeviceLocation {
// TODO: Find a proper way to obtain the bus range. For example, if the PCI bus is identified
// from a device tree, this information can be obtained from the `bus-range` field (e.g.,
// `bus-range = <0x00 0x7f>`).
const MIN_BUS: u8 = 0;
#[cfg(not(target_arch = "loongarch64"))]
const MAX_BUS: u8 = 255;
#[cfg(target_arch = "loongarch64")]
const MAX_BUS: u8 = 127;
const MIN_DEVICE: u8 = 0;
const MAX_DEVICE: u8 = 31;
const MIN_FUNCTION: u8 = 0;
const MAX_FUNCTION: u8 = 7;
/// Returns an iterator that enumerates all possible PCI device locations.
pub fn all() -> impl Iterator<Item = PciDeviceLocation> {
iter::from_coroutine(
#[coroutine]
|| {
for bus in Self::MIN_BUS..=Self::MAX_BUS {
for device in Self::MIN_DEVICE..=Self::MAX_DEVICE {
for function in Self::MIN_FUNCTION..=Self::MAX_FUNCTION {
let loc = PciDeviceLocation {
bus,
device,
function,
};
yield loc;
}
}
}
},
)
}
}
impl PciDeviceLocation {
const BIT32_ALIGN_MASK: u16 = 0xFFFC;
/// Aligns the given pointer to a 32-bit boundary.
pub const fn align_ptr(ptr: u16) -> u16 {
ptr & Self::BIT32_ALIGN_MASK
}
/// Reads an 8-bit value from the PCI configuration space at the specified offset.
pub fn read8(&self, offset: u16) -> u8 {
let val = self.read32(offset & Self::BIT32_ALIGN_MASK);
((val >> ((offset as usize & 0b11) << 3)) & 0xFF) as u8
}
/// Reads a 16-bit value from the PCI configuration space at the specified offset.
pub fn read16(&self, offset: u16) -> u16 {
let val = self.read32(offset & Self::BIT32_ALIGN_MASK);
((val >> ((offset as usize & 0b10) << 3)) & 0xFFFF) as u16
}
/// Reads a 32-bit value from the PCI configuration space at the specified offset.
pub fn read32(&self, offset: u16) -> u32 {
debug_assert!(
(offset & 0b11) == 0,
"misaligned PCI configuration dword u32 read"
);
crate::arch::read32(self, offset as u32).unwrap()
}
/// Writes an 8-bit value to the PCI configuration space at the specified offset.
pub fn write8(&self, offset: u16, val: u8) {
let old = self.read32(offset & Self::BIT32_ALIGN_MASK);
let dest = (offset as usize & 0b11) << 3;
let mask = (0xFF << dest) as u32;
self.write32(
offset & Self::BIT32_ALIGN_MASK,
(((val as u32) << dest) | (old & !mask)).to_le(),
);
}
/// Writes a 16-bit value to the PCI configuration space at the specified offset.
pub fn write16(&self, offset: u16, val: u16) {
let old = self.read32(offset & Self::BIT32_ALIGN_MASK);
let dest = (offset as usize & 0b10) << 3;
let mask = (0xFFFF << dest) as u32;
self.write32(
offset & Self::BIT32_ALIGN_MASK,
(((val as u32) << dest) | (old & !mask)).to_le(),
);
}
/// Writes a 32-bit value to the PCI configuration space at the specified offset.
pub fn write32(&self, offset: u16, val: u32) {
debug_assert!(
(offset & 0b11) == 0,
"misaligned PCI configuration dword u32 write"
);
crate::arch::write32(self, offset as u32, val).unwrap()
}
}
/// PCI device ID
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct PciDeviceId {

View File

@ -54,6 +54,8 @@
#![no_std]
#![deny(unsafe_code)]
#![feature(iter_from_coroutine)]
#![feature(coroutines)]
#[cfg(target_arch = "x86_64")]
#[path = "arch/x86/mod.rs"]
@ -74,11 +76,8 @@ mod device_info;
extern crate alloc;
use component::{init_component, ComponentInitError};
pub use device_info::PciDeviceId;
use ostd::{
bus::pci::{has_pci_bus, PciDeviceLocation},
sync::Mutex,
};
pub use device_info::{PciDeviceId, PciDeviceLocation};
use ostd::sync::Mutex;
use self::{bus::PciBus, common_device::PciCommonDevice};

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
//! Bus operations
//! Bus probe error
pub mod pci;
// TODO: Implement a bus component and move the `BusProbeError` into the module.
/// An error that occurs during bus probing.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]

View File

@ -1,136 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
//! Helper functions or structures for PCI devices.
use core::iter;
/// Checks if the system has a PCI bus.
pub fn has_pci_bus() -> bool {
crate::arch::pci::has_pci_bus()
}
#[cfg(target_arch = "loongarch64")]
/// Allocates an MMIO address range using the global allocator.
pub fn alloc_mmio(layout: core::alloc::Layout) -> Option<crate::prelude::Paddr> {
crate::arch::pci::alloc_mmio(layout)
}
/// PCI device Location
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PciDeviceLocation {
/// Bus number
pub bus: u8,
/// Device number with max 31
pub device: u8,
/// Device number with max 7
pub function: u8,
}
impl PciDeviceLocation {
// TODO: Find a proper way to obtain the bus range. For example, if the PCI bus is identified
// from a device tree, this information can be obtained from the `bus-range` field (e.g.,
// `bus-range = <0x00 0x7f>`).
const MIN_BUS: u8 = 0;
#[cfg(not(target_arch = "loongarch64"))]
const MAX_BUS: u8 = 255;
#[cfg(target_arch = "loongarch64")]
const MAX_BUS: u8 = 127;
const MIN_DEVICE: u8 = 0;
const MAX_DEVICE: u8 = 31;
const MIN_FUNCTION: u8 = 0;
const MAX_FUNCTION: u8 = 7;
/// Returns an iterator that enumerates all possible PCI device locations.
pub fn all() -> impl Iterator<Item = PciDeviceLocation> {
iter::from_coroutine(
#[coroutine]
|| {
for bus in Self::MIN_BUS..=Self::MAX_BUS {
for device in Self::MIN_DEVICE..=Self::MAX_DEVICE {
for function in Self::MIN_FUNCTION..=Self::MAX_FUNCTION {
let loc = PciDeviceLocation {
bus,
device,
function,
};
yield loc;
}
}
}
},
)
}
/// The page table of all devices is the same. So we can use any device ID.
/// FIXME: distinguish different device id.
pub fn zero() -> Self {
Self {
bus: 0,
device: 0,
function: 0,
}
}
}
impl PciDeviceLocation {
const BIT32_ALIGN_MASK: u16 = 0xFFFC;
/// Aligns the given pointer to a 32-bit boundary.
pub const fn align_ptr(ptr: u16) -> u16 {
ptr & Self::BIT32_ALIGN_MASK
}
/// Reads a 8-bit value from the PCI configuration space at the specified offset.
pub fn read8(&self, offset: u16) -> u8 {
let val = self.read32(offset & Self::BIT32_ALIGN_MASK);
((val >> ((offset as usize & 0b11) << 3)) & 0xFF) as u8
}
/// Reads a 16-bit value from the PCI configuration space at the specified offset.
pub fn read16(&self, offset: u16) -> u16 {
let val = self.read32(offset & Self::BIT32_ALIGN_MASK);
((val >> ((offset as usize & 0b10) << 3)) & 0xFFFF) as u16
}
/// Reads a 32-bit value from the PCI configuration space at the specified offset.
pub fn read32(&self, offset: u16) -> u32 {
debug_assert!(
(offset & 0b11) == 0,
"misaligned PCI configuration dword u32 read"
);
crate::arch::pci::read32(self, offset as u32).unwrap()
}
/// Writes an 8-bit value to the PCI configuration space at the specified offset.
pub fn write8(&self, offset: u16, val: u8) {
let old = self.read32(offset & Self::BIT32_ALIGN_MASK);
let dest = (offset as usize & 0b11) << 3;
let mask = (0xFF << dest) as u32;
self.write32(
offset & Self::BIT32_ALIGN_MASK,
(((val as u32) << dest) | (old & !mask)).to_le(),
);
}
/// Writes an 16-bit value to the PCI configuration space at the specified offset.
pub fn write16(&self, offset: u16, val: u16) {
let old = self.read32(offset & Self::BIT32_ALIGN_MASK);
let dest = (offset as usize & 0b10) << 3;
let mask = (0xFFFF << dest) as u32;
self.write32(
offset & Self::BIT32_ALIGN_MASK,
(((val as u32) << dest) | (old & !mask)).to_le(),
);
}
/// Writes an 32-bit value to the PCI configuration space at the specified offset.
pub fn write32(&self, offset: u16, val: u32) {
debug_assert!(
(offset & 0b11) == 0,
"misaligned PCI configuration dword u32 write"
);
crate::arch::pci::write32(self, offset as u32, val).unwrap()
}
}