doc: add pci subsystem docs
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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<DeviceMemory>,
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -22,6 +22,7 @@ impl<T> InitOnce<T> {
|
||||
self.state.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub fn get(&self) -> &mut T {
|
||||
assert!(self.is_initialized(), "Access to uninitialized InitOnce<T>");
|
||||
unsafe { (*self.inner.get()).assume_init_mut() }
|
||||
|
||||
Reference in New Issue
Block a user