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/* ---------------------------------------------------------------------------------------------- */