doc: add pci subsystem docs

This commit is contained in:
2021-10-11 19:10:07 +03:00
parent 4a2d646dc0
commit 7121e502df
4 changed files with 54 additions and 6 deletions
+29 -1
View File
@@ -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)
+14 -1
View File
@@ -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(),
+10 -4
View File
@@ -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)]
+1
View File
@@ -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() }