pci_driver/
device.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/* ---------------------------------------------------------------------------------------------- */
4
5use std::fmt::Debug;
6use std::io;
7use std::os::unix::io::RawFd;
8
9use crate::config::PciConfig;
10use crate::interrupts::{PciInterruptKind, PciInterrupts};
11use crate::iommu::PciIommu;
12use crate::regions::{OwningPciRegion, Permissions, RegionIdentifier};
13
14/* ---------------------------------------------------------------------------------------------- */
15
16pub(crate) use private::Sealed;
17mod private {
18    /// Private trait that can be used as a supertrait to make other traits non-implementable from
19    /// outside this crate: https://jack.wrenn.fyi/blog/private-trait-methods/
20    pub trait Sealed {}
21}
22
23/// Represents a PCI __function__.
24///
25/// This trait is _sealed_ for forward-compatibility reasons, and thus cannot be implemented by
26/// users of the crate.
27pub trait PciDevice: Debug + Send + Sync + Sealed {
28    /// Returns a thing that lets you access the PCI configuration space.
29    ///
30    /// The returned value borrows the `PciDevice`.
31    fn config(&self) -> PciConfig;
32
33    /// Returns a region that corresponds to the Base Address Register (BAR) with the given index,
34    /// or `None` if there is no such BAR or it is unused by the device.
35    ///
36    /// Unused BARs appear as [`None`]. Also, if you want to refer to a 64-bit BAR, use the lower
37    /// index (of the underlying, consecutive 32-bit BARs); the higher index is [`None`] in that
38    /// case.
39    ///
40    /// Note that PCI allows used BARs to be interspersed with unused BARs. Also, 64-bit BARs don't
41    /// need to be "aligned". For instance, it is possible for a device to use BAR 0 as a 32-bit
42    /// BAR, leave BARs 1 and 2 unused, used 3 and 4 for a 64-bit BAR, and use BAR 5 for another
43    /// 32-bit BAR.
44    ///
45    /// The returned value does _not_ borrow the `PciDevice`, instead sharing ownership of its
46    /// internal resources, so take care to drop it when you want to fully let go of the device.
47    fn bar(&self, index: usize) -> Option<OwningPciRegion>;
48
49    /// Returns a region that is the PCI Expansion ROM, or `None` if the device doesn't have one.
50    ///
51    /// The returned value does _not_ borrow the `PciDevice`, instead sharing ownership of its
52    /// internal resources, so take care to drop it when you want to fully let go of the device.
53    fn rom(&self) -> Option<OwningPciRegion>;
54
55    // TODO: Also expose VGA space?
56
57    /// Returns a thing that lets you manage IOMMU mappings for DMA.
58    ///
59    /// NOTE: Depending on the backend and on how the `PciDevice` was instantiated, this may also
60    /// affect IOMMU mappings for other PCI functions.
61    ///
62    /// The returned value borrows the `PciDevice`.
63    fn iommu(&self) -> PciIommu;
64
65    /// Returns a thing that lets you manage interrupts.
66    ///
67    /// The returned value borrows the `PciDevice`.
68    fn interrupts(&self) -> PciInterrupts;
69
70    /// Reset this function, and only it.
71    ///
72    /// This will fail if it would be necessary to reset other functions or devices as well to get
73    /// this one to be reset (probably can only happen with multi-function devices that don't
74    /// support Function-Level Reset).
75    ///
76    /// This can also fail for other unspecified reasons.
77    ///
78    /// TODO: Should probably advertise whether this granularity of reset is supported, so the user
79    /// doesn't have to try resetting to find out.
80    fn reset(&self) -> io::Result<()>;
81}
82
83/* ---------------------------------------------------------------------------------------------- */
84
85pub(crate) trait PciDeviceInternal: Debug + Send + Sync {
86    // BARs / ROM
87
88    fn region_map(
89        &self,
90        identifier: RegionIdentifier,
91        offset: u64,
92        len: usize,
93        permissions: Permissions,
94    ) -> io::Result<*mut u8>;
95
96    unsafe fn region_unmap(&self, identifier: RegionIdentifier, address: *mut u8, length: usize);
97
98    // Interrupts
99
100    fn interrupts_max(&self, kind: PciInterruptKind) -> usize;
101    fn interrupts_enable(&self, kind: PciInterruptKind, eventfds: &[RawFd]) -> io::Result<()>;
102    fn interrupts_disable(&self, kind: PciInterruptKind) -> io::Result<()>;
103}
104
105/* ---------------------------------------------------------------------------------------------- */