diff --git a/kernel/src/dev/pci/mod.rs b/kernel/src/dev/pci/mod.rs index 4b24d94..3469bd8 100644 --- a/kernel/src/dev/pci/mod.rs +++ b/kernel/src/dev/pci/mod.rs @@ -1,4 +1,4 @@ -#![allow(missing_docs)] +//! PCI bus host and device interfaces use crate::dev::Device; use core::fmt; @@ -8,18 +8,21 @@ pub mod pcie; macro_rules! ecam_field { ($getter:ident, $off:expr, u16) => { + #[allow(missing_docs)] #[inline(always)] fn $getter(&self) -> u16 { self.readw($off) } }; ($getter:ident, $off:expr, u8) => { + #[allow(missing_docs)] #[inline(always)] fn $getter(&self) -> u8 { self.readb($off) } }; ($getter:ident, $setter:ident, $off:expr, u16) => { + #[allow(missing_docs)] #[inline(always)] unsafe fn $setter(&self, v: u16) { self.writew($off, v) @@ -29,22 +32,37 @@ macro_rules! ecam_field { }; } +/// PCI endpoint address struct, combining bus:dev:func parts #[derive(Clone, Copy)] #[repr(transparent)] pub struct PciAddress { value: u32, } +/// Generic PCI device configuration space interface pub trait PciCfgSpace { + // TODO change readl to readl_unchecked() and perform checks at trait level + /// Reads an [u32] from device config space. + /// `off` must be aligned at a 4-byte boundary. fn readl(&self, off: usize) -> u32; + + /// Writes an [u32] to device config space. + /// `off` must be aligned at a 4-byte boundary. + /// + /// # Safety + /// + /// Unsafe: allows arbitrary value writes to PCI config space. unsafe fn writel(&self, off: usize, val: u32); + /// Reads an [u16] from device config space. + /// `off` must be aligned at a 2-byte boundary. #[inline(always)] fn readw(&self, off: usize) -> u16 { assert!(off & 0x1 == 0); (self.readl(off & !0x3) >> ((off & 0x3) * 8)) as u16 } + /// Reads an [u8] from device config space #[inline(always)] fn readb(&self, off: usize) -> u8 { (self.readl(off & !0x3) >> ((off & 0x3) * 8)) as u8 @@ -54,17 +72,22 @@ pub trait PciCfgSpace { ecam_field! { device_id, 0x02, u16 } ecam_field! { header_type, 0x0E, u8 } + /// Returns `true` if device this config describes is + /// present on the bus #[inline(always)] fn is_valid(&self) -> bool { self.readl(0) != 0xFFFFFFFF } } +/// PCI host controller interface pub trait PciHostDevice: Device { + /// Initializes and enables devices attached to the bus fn map(&self) -> Result<(), Errno>; } impl PciAddress { + /// Constructs a [PCIAddress] instance from its components #[inline(always)] pub const fn new(bus: u8, dev: u8, func: u8) -> Self { Self { @@ -72,21 +95,26 @@ impl PciAddress { } } + /// Returns `bus` field of [PCIAddress] #[inline(always)] pub const fn bus(self) -> u8 { (self.value >> 8) as u8 } + /// Returns `dev` field of [PCIAddress] #[inline(always)] pub const fn dev(self) -> u8 { ((self.value >> 3) as u8) & 0x1F } + /// Returns `func` field of [PCIAddress] #[inline(always)] pub const fn func(self) -> u8 { (self.value as u8) & 0x7 } + /// Returns a new [PCIAddress], constructed from `self`, but with + /// specified `func` number #[inline(always)] pub const fn with_func(self, func: u8) -> Self { Self::new(self.bus(), self.dev(), func) diff --git a/kernel/src/dev/pci/pcie/gpex.rs b/kernel/src/dev/pci/pcie/gpex.rs index 9cdb3eb..2d721d4 100644 --- a/kernel/src/dev/pci/pcie/gpex.rs +++ b/kernel/src/dev/pci/pcie/gpex.rs @@ -1,3 +1,5 @@ +//! Generic PCIe host driver + use crate::dev::{ pci::{pcie::EcamCfgSpace, PciAddress, PciCfgSpace, PciHostDevice}, Device, @@ -6,6 +8,7 @@ use crate::mem::virt::DeviceMemory; use crate::util::InitOnce; use error::Errno; +/// GPEX host controller struct pub struct GenericPcieHost { ecam_base: usize, ecam: InitOnce, @@ -47,7 +50,12 @@ impl GenericPcieHost { } fn map_function(&self, addr: PciAddress, cfg: EcamCfgSpace) -> Result<(), Errno> { - debugln!("{:?}: {:04x}:{:04x}", addr, cfg.vendor_id(), cfg.device_id()); + debugln!( + "{:?}: {:04x}:{:04x}", + addr, + cfg.vendor_id(), + cfg.device_id() + ); Ok(()) } @@ -82,6 +90,11 @@ impl GenericPcieHost { Ok(()) } + /// Constructs an instance of GPEX device. + /// + /// # Safety + /// + /// Does not perform `ecam_base` validation. pub const unsafe fn new(ecam_base: usize, bus_count: u8) -> Self { Self { ecam: InitOnce::new(), diff --git a/kernel/src/dev/pci/pcie/mod.rs b/kernel/src/dev/pci/pcie/mod.rs index 3690bff..0ae013c 100644 --- a/kernel/src/dev/pci/pcie/mod.rs +++ b/kernel/src/dev/pci/pcie/mod.rs @@ -1,7 +1,10 @@ +//! PCI Express access interfaces and drivers + use crate::dev::pci::{PciAddress, PciCfgSpace}; pub mod gpex; +/// Enhanced configuration space from PCI Express #[derive(Clone, Copy)] #[repr(transparent)] pub struct EcamCfgSpace { @@ -9,9 +12,14 @@ pub struct EcamCfgSpace { } impl EcamCfgSpace { + /// Constructs an instance of ECAM struct describing PCI endpoint `addr`. + /// + /// # Safety + /// + /// `ecam_base` is not validated. pub const unsafe fn new(ecam_base: usize, addr: PciAddress) -> Self { Self { - base: ecam_base + (addr.value as usize) * 4096 + base: ecam_base + (addr.value as usize) * 4096, } } } @@ -20,9 +28,7 @@ impl PciCfgSpace for EcamCfgSpace { #[inline(always)] fn readl(&self, off: usize) -> u32 { assert!(off & 0x3 == 0); - unsafe { - core::ptr::read_volatile((self.base + off) as *const u32) - } + unsafe { core::ptr::read_volatile((self.base + off) as *const u32) } } #[inline(always)] diff --git a/kernel/src/util.rs b/kernel/src/util.rs index 7e1cf8f..8596b87 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -22,6 +22,7 @@ impl InitOnce { self.state.load(Ordering::Acquire) } + #[allow(clippy::mut_from_ref)] pub fn get(&self) -> &mut T { assert!(self.is_initialized(), "Access to uninitialized InitOnce"); unsafe { (*self.inner.get()).assume_init_mut() }