Extract `PciDeviceLocation` in ostd into PCI component
This commit is contained in:
parent
bb4c532b4e
commit
bb15d4591a
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue