asterinas/kernel/comps/pci/src/lib.rs

124 lines
3.6 KiB
Rust

// SPDX-License-Identifier: MPL-2.0
//! The PCI bus of Asterinas.
//!
//! Users can implement the bus under the `PciDriver` to register devices to
//! the PCI bus. When the physical device and the driver match successfully, it
//! will be provided through the driver's `construct` function to construct a
//! structure that implements the `PciDevice` trait. And in the end, the PCI
//! bus will store a reference to the structure and finally call the driver's
//! probe function to remind the driver of a new device access.
//!
//! Use case:
//!
//! ```rust no_run
//! #[derive(Debug)]
//! pub struct PciDeviceA {
//! common_device: PciCommonDevice,
//! }
//!
//! impl PciDevice for PciDeviceA {
//! fn device_id(&self) -> PciDeviceId {
//! self.common_device.device_id().clone()
//! }
//! }
//!
//! #[derive(Debug)]
//! pub struct PciDriverA {
//! devices: Mutex<Vec<Arc<PciDeviceA>>>,
//! }
//!
//! impl PciDriver for PciDriverA {
//! fn probe(
//! &self,
//! device: PciCommonDevice,
//! ) -> Result<Arc<dyn PciDevice>, (PciDriverProbeError, PciCommonDevice)> {
//! if device.device_id().vendor_id != 0x1234 {
//! return Err((PciDriverProbeError::DeviceNotMatch, device));
//! }
//! let device = Arc::new(PciDeviceA {
//! common_device: device,
//! });
//! self.devices.lock().push(device.clone());
//! Ok(device)
//! }
//! }
//!
//! pub fn driver_a_init() {
//! let driver_a = Arc::new(PciDriverA {
//! devices: Mutex::new(Vec::new()),
//! });
//! PCI_BUS.lock().register_driver(driver_a);
//! }
//! ```
#![no_std]
#![deny(unsafe_code)]
#[cfg_attr(target_arch = "x86_64", path = "arch/x86/mod.rs")]
#[cfg_attr(target_arch = "riscv64", path = "arch/riscv/mod.rs")]
#[cfg_attr(target_arch = "loongarch64", path = "arch/loongarch/mod.rs")]
mod arch;
pub mod bus;
pub mod capability;
pub mod cfg_space;
pub mod common_device;
mod device_info;
extern crate alloc;
use component::{ComponentInitError, init_component};
pub use device_info::{PciDeviceId, PciDeviceLocation};
use ostd::sync::Mutex;
use self::{bus::PciBus, common_device::PciCommonDevice};
#[init_component]
fn pci_init() -> Result<(), ComponentInitError> {
init();
Ok(())
}
/// The PCI bus instance.
pub static PCI_BUS: Mutex<PciBus> = Mutex::new(PciBus::new());
fn init() {
let Some(all_bus) = arch::init() else {
log::info!("no PCI bus was found");
return;
};
log::info!("initializing the PCI bus with bus numbers `{:?}`", all_bus);
let mut lock = PCI_BUS.lock();
let all_dev = PciDeviceLocation::MIN_DEVICE..=PciDeviceLocation::MAX_DEVICE;
let all_func = PciDeviceLocation::MIN_FUNCTION..=PciDeviceLocation::MAX_FUNCTION;
for bus in all_bus {
for device in all_dev.clone() {
let mut device_location = PciDeviceLocation {
bus,
device,
function: PciDeviceLocation::MIN_FUNCTION,
};
let Some(first_function_device) = PciCommonDevice::new(device_location) else {
continue;
};
let has_multi_function = first_function_device.has_multi_funcs();
// Register function 0 in advance
lock.register_common_device(first_function_device);
if has_multi_function {
for function in all_func.clone().skip(1) {
device_location.function = function;
if let Some(common_device) = PciCommonDevice::new(device_location) {
lock.register_common_device(common_device);
}
}
}
}
}
}