Refactor PCI access in OSTD

This commit is contained in:
Yuke Peng 2025-03-28 15:23:46 +08:00 committed by Tate, Hongliang Tian
parent 865003738a
commit 322fc4feff
6 changed files with 101 additions and 27 deletions

View File

@ -32,6 +32,7 @@ pub(crate) unsafe fn late_init_on_bsp() {
crate::boot::smp::boot_all_aps(); crate::boot::smp::boot_all_aps();
timer::init(); timer::init();
let _ = pci::init();
} }
pub(crate) unsafe fn init_on_ap() { pub(crate) unsafe fn init_on_ap() {

View File

@ -1,8 +1,67 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! PCI bus io port //! PCI bus access
use super::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; use spin::Once;
pub static PCI_ADDRESS_PORT: IoPort<u32, WriteOnlyAccess> = unsafe { IoPort::new(0x0) }; use super::boot::DEVICE_TREE;
pub static PCI_DATA_PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x0) }; use crate::{bus::pci::PciDeviceLocation, io::IoMem, mm::VmIoOnce, prelude::*, Error};
static PCI_BASE_ADDR: Once<IoMem> = Once::new();
pub(crate) fn write32(location: &PciDeviceLocation, offset: u32, value: u32) -> Result<()> {
PCI_BASE_ADDR.get().ok_or(Error::IoError)?.write_once(
(encode_as_address_offset(location) | (offset & 0xfc)) as usize,
&value,
)
}
pub(crate) fn read32(location: &PciDeviceLocation, offset: u32) -> Result<u32> {
PCI_BASE_ADDR
.get()
.ok_or(Error::IoError)?
.read_once((encode_as_address_offset(location) | (offset & 0xfc)) as usize)
}
pub(crate) fn has_pci_bus() -> bool {
PCI_BASE_ADDR.is_completed()
}
pub(crate) fn init() -> Result<()> {
let pci = DEVICE_TREE
.get()
.unwrap()
.find_node("/soc/pci")
.ok_or(Error::IoError)?;
let mut reg = pci.reg().ok_or(Error::IoError)?;
let Ok(region) = reg.next() else {
warn!("PCI node should have exactly one `reg` property, but found zero `reg`s");
return Err(Error::IoError);
};
if reg.next().is_some() {
warn!(
"PCI node should have exactly one `reg` property, but found {} `reg`s",
reg.count() + 2
);
return Err(Error::IoError);
}
PCI_BASE_ADDR.call_once(|| {
IoMem::acquire(
(region.starting_address as usize)
..(region.starting_address as usize + region.size.unwrap()),
)
.unwrap()
});
Ok(())
}
/// Encodes the bus, device, and function into an address offset in the PCI MMIO region.
fn encode_as_address_offset(location: &PciDeviceLocation) -> u32 {
((location.bus as u32) << 16)
| ((location.device as u32) << 11)
| ((location.function as u32) << 8)
}

View File

@ -1,8 +1,35 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! PCI bus io port //! PCI bus access
use super::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; use super::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
use crate::{bus::pci::PciDeviceLocation, prelude::*};
pub static PCI_ADDRESS_PORT: IoPort<u32, WriteOnlyAccess> = unsafe { IoPort::new(0x0CF8) }; static PCI_ADDRESS_PORT: IoPort<u32, WriteOnlyAccess> = unsafe { IoPort::new(0x0CF8) };
pub static PCI_DATA_PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x0CFC) }; static PCI_DATA_PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x0CFC) };
const BIT32_ALIGN_MASK: u32 = 0xFFFC;
pub(crate) fn write32(location: &PciDeviceLocation, offset: u32, value: u32) -> Result<()> {
PCI_ADDRESS_PORT.write(encode_as_port(location) | (offset & BIT32_ALIGN_MASK));
PCI_DATA_PORT.write(value.to_le());
Ok(())
}
pub(crate) fn read32(location: &PciDeviceLocation, offset: u32) -> Result<u32> {
PCI_ADDRESS_PORT.write(encode_as_port(location) | (offset & BIT32_ALIGN_MASK));
Ok(PCI_DATA_PORT.read().to_le())
}
pub(crate) fn has_pci_bus() -> bool {
true
}
/// Encodes the bus, device, and function into a port address for use with the PCI I/O port.
fn encode_as_port(location: &PciDeviceLocation) -> u32 {
// 1 << 31: Configuration enable
(1 << 31)
| ((location.bus as u32) << 16)
| (((location.device as u32) & 0b11111) << 11)
| (((location.function as u32) & 0b111) << 8)
}

View File

@ -16,8 +16,6 @@ pub enum BusProbeError {
/// Initializes the bus /// Initializes the bus
pub(crate) fn init() { pub(crate) fn init() {
#[cfg(target_arch = "x86_64")]
pci::init(); pci::init();
mmio::init(); mmio::init();
} }

View File

@ -5,7 +5,6 @@
use core::iter; use core::iter;
use super::cfg_space::PciDeviceCommonCfgOffset; use super::cfg_space::PciDeviceCommonCfgOffset;
use crate::arch::pci::{PCI_ADDRESS_PORT, PCI_DATA_PORT};
/// PCI device ID /// PCI device ID
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -70,15 +69,6 @@ impl PciDeviceLocation {
const MAX_DEVICE: u8 = 31; const MAX_DEVICE: u8 = 31;
const MIN_FUNCTION: u8 = 0; const MIN_FUNCTION: u8 = 0;
const MAX_FUNCTION: u8 = 7; const MAX_FUNCTION: u8 = 7;
/// By encoding bus, device, and function into u32, user can access a PCI device in x86 by passing in this value.
#[inline(always)]
pub fn encode_as_x86_address_value(self) -> u32 {
// 1 << 31: Configuration enable
(1 << 31)
| ((self.bus as u32) << 16)
| (((self.device as u32) & 0b11111) << 11)
| (((self.function as u32) & 0b111) << 8)
}
/// Returns an iterator that enumerates all possible PCI device locations. /// Returns an iterator that enumerates all possible PCI device locations.
pub fn all() -> impl Iterator<Item = PciDeviceLocation> { pub fn all() -> impl Iterator<Item = PciDeviceLocation> {
@ -130,9 +120,7 @@ impl PciDeviceLocation {
(offset & 0b11) == 0, (offset & 0b11) == 0,
"misaligned PCI configuration dword u32 read" "misaligned PCI configuration dword u32 read"
); );
PCI_ADDRESS_PORT crate::arch::pci::read32(self, offset as u32).unwrap()
.write(self.encode_as_x86_address_value() | (offset & Self::BIT32_ALIGN_MASK) as u32);
PCI_DATA_PORT.read().to_le()
} }
pub(super) fn write8(&self, offset: u16, val: u8) { pub(super) fn write8(&self, offset: u16, val: u8) {
@ -160,9 +148,6 @@ impl PciDeviceLocation {
(offset & 0b11) == 0, (offset & 0b11) == 0,
"misaligned PCI configuration dword u32 write" "misaligned PCI configuration dword u32 write"
); );
crate::arch::pci::write32(self, offset as u32, val).unwrap()
PCI_ADDRESS_PORT
.write(self.encode_as_x86_address_value() | (offset & Self::BIT32_ALIGN_MASK) as u32);
PCI_DATA_PORT.write(val.to_le())
} }
} }

View File

@ -59,12 +59,16 @@ mod device_info;
pub use device_info::{PciDeviceId, PciDeviceLocation}; pub use device_info::{PciDeviceId, PciDeviceLocation};
use self::{bus::PciBus, common_device::PciCommonDevice}; use self::{bus::PciBus, common_device::PciCommonDevice};
use crate::sync::Mutex; use crate::{arch::pci::has_pci_bus, sync::Mutex};
/// PCI bus instance /// PCI bus instance
pub static PCI_BUS: Mutex<PciBus> = Mutex::new(PciBus::new()); pub static PCI_BUS: Mutex<PciBus> = Mutex::new(PciBus::new());
pub(crate) fn init() { pub(crate) fn init() {
if !has_pci_bus() {
return;
}
let mut lock = PCI_BUS.lock(); let mut lock = PCI_BUS.lock();
for location in PciDeviceLocation::all() { for location in PciDeviceLocation::all() {
let Some(device) = PciCommonDevice::new(location) else { let Some(device) = PciCommonDevice::new(location) else {