mycelium_pci/register.rs
1//! A PCI device's [`Status`] and [`Command`] registers.
2use mycelium_bitfield::{bitfield, FromBits};
3
4bitfield! {
5 /// A PCI device's `Status` register.
6 ///
7 /// See <https://wiki.osdev.org/Pci#Status_Register>
8 #[derive(Eq, PartialEq)]
9 pub struct Status<u16> {
10 const _RES0 = 2;
11 /// Interrupt Status.
12 ///
13 /// Represents the state of the device's `INTx#` signal. If set to 1 and
14 /// bit 10 of the [`Command`] register ([`INTERRUPT_DISABLE`]) is set to
15 /// 0, the signal will be asserted; otherwise, the signal will be ignored.
16 ///
17 /// [`INTERUPT_DISABLE`]: Command::INTERRUPT_DISABLE
18 pub const INTERRUPT_STATUS: bool;
19
20 /// Capabilities List
21 ///
22 /// If set to 1, the device implements the pointer for a New Capabilities
23 /// linked list at offset `0x34`; otherwise, the linked list is not available.
24 pub const CAPABILITIES_LIST: bool;
25
26 /// 66 MHz Capable
27 ///
28 /// If set to 1 the device is capable of running at 66 MHz; otherwise,
29 /// the device runs at 33 MHz.
30 pub const IS_66MHZ_CAPABLE: bool;
31
32 /// As of revision 3.0 of the PCI Local Bus specification this bit is
33 /// reserved. In revision 2.1 of the specification this bit was used to
34 /// indicate whether or not a device supported User Definable Features
35 const _RES1 = 1;
36
37 /// Fast Back-To-Back Capable
38 ///
39 /// If set to 1 the device can accept fast back-to-back transactions
40 /// that are not from the same agent; otherwise, transactions can only
41 /// be accepted from the same agent.
42 pub const FAST_BACK_TO_BACK_CAPABLE: bool;
43
44 /// Master Data Parity Error
45 ///
46 /// This bit is only set when the following conditions are met. The bus
47 /// agent asserted `PERR#` on a read or observed an assertion of `PERR#`
48 /// on a write, the agent setting the bit acted as the bus master for
49 /// the operation in which the error occurred, and bit 6 of the
50 /// [`Command`] register ([`PARITY_ERROR_RESPONSE`] bit) is set to 1.
51 ///
52 /// [`PARITY_ERROR_RESPONSE`]: Command::PARITY_ERROR_RESPONSE
53 pub const MASTER_DATA_PARITY_ERROR: bool;
54
55 /// `DEVSEL#` Timing
56 ///
57 /// Read-only bits that represent the slowest time that a device will
58 /// assert `DEVSEL#` for any bus command except Configuration Space read
59 /// and writes. A value of 0x0 represents fast timing, a value of
60 /// 0x1 represents medium timing, and a value of 0x2 represents slow
61 /// timing.
62 pub const DEVSEL_TIMING: DevselTiming;
63
64 /// Signalled Target Abort
65 ///
66 /// This bit will be set to 1 whenever a target device terminates a
67 /// transaction with Target-Abort.
68 pub const SIGNALLED_TARGET_ABORT: bool;
69
70 /// Received Target Abort
71 ///
72 /// This bit will be set to 1, by a master device, whenever its
73 /// transaction is terminated with Target-Abort.
74 pub const RECEIVED_TARGET_ABORT: bool;
75
76 /// Received Master Abort
77 ///
78 /// This bit will be set to 1, by a master device, whenever its
79 /// transaction (except for Special Cycle transactions) is terminated
80 /// with Master-Abort.
81 pub const RECEIVED_MASTER_ABORT: bool;
82
83 /// Signalled System Error
84 ///
85 /// This bit will be set to 1 whenever the device asserts `SERR#`.
86 pub const SIGNALLED_SYSTEM_ERROR: bool;
87
88 /// Detected Parity Error
89 ///
90 /// This bit will be set to 1 whenever the device detects a parity
91 /// error, even if parity error handling is disabled.
92 pub const DETECTED_PARITY_ERROR: bool;
93 }
94}
95
96bitfield! {
97
98 /// A PCI device's `Command` register.
99 ///
100 /// See <https://wiki.osdev.org/Pci#Command_Register>
101 #[derive(Eq, PartialEq)]
102 pub struct Command<u16> {
103 /// I/O Space Enabled
104 ///
105 /// If set to 1 the device can respond to I/O Space accesses; otherwise,
106 /// the device's response is disabled.
107 pub const IO_SPACE_ENABLED: bool;
108
109 /// Memory Space Enabled
110 ///
111 /// If set to 1 the device can respond to Memory Space accesses;
112 /// otherwise, the device's response is disabled.
113 pub const MEMORY_SPACE_ENABLED: bool;
114
115 /// Bus Master
116 ///
117 /// If set to 1, the device can behave as a bus master; otherwise, the
118 /// device can not generate PCI accesses.
119 pub const BUS_MASTER: bool;
120
121 /// Special Cycle Enabled
122 ///
123 /// If set to 1 the device can monitor Special Cycle operations;
124 /// otherwise, the device will ignore them.
125 pub const SPECIAL_CYCLE_ENABLE: bool;
126
127 /// Memory Write and Invalidate Enabled
128 ///
129 /// If set to 1 the device can generate the Memory Write and Invalidate
130 /// command; otherwise, the Memory Write command must be used.
131 pub const MEMORY_WRITE_AND_INVALIDATE_ENABLED: bool;
132
133 /// VGA Palette Snoop
134 ///
135 /// If set to 1 the device does not respond to palette register writes
136 /// and will snoop the data; otherwise, the device will treat palette
137 /// write accesses like all other accesses.
138 pub const VGA_PALETTE_SNOOP: bool;
139
140 /// Parity Error Response enabled
141 ///
142 /// If set to 1 the device will take its normal action when a parity
143 /// error is detected; otherwise, when an error is detected, the device
144 /// will set bit 15 of the [`Status`] register
145 /// ([`DETECTED_PARITY_ERROR`]), but will not assert the PERR# (Parity
146 /// Error) pin and will continue operation as normal.
147 ///
148 /// [`DETECTED_PARITY_ERROR`]: Status::DETECTED_PARITY_ERROR
149 pub const PARITY_ERROR_RESPONSE_ENABLED: bool;
150
151 /// As of revision 3.0 of the PCI local bus specification this bit is
152 /// hardwired to 0. In earlier versions of the specification this bit
153 /// was used by devices and may have been hardwired to 0, 1, or
154 /// implemented as a read/write bit.
155 const _RES0 = 1;
156
157 /// `SERR#` Enabled
158 ///
159 /// If set to 1 the `SERR#` driver is enabled; otherwise, the driver is disabled.
160 pub const SERR_ENABLED: bool;
161
162 /// Fast Back-To-Back Enabled
163 ///
164 /// If set to 1, indicates a device is allowed to generate fast
165 /// back-to-back transactions; otherwise, fast back-to-back
166 /// transactions are only allowed to the same agent.
167 pub const FAST_BACK_TO_BACK_ENABLED: bool;
168
169 /// Interrupt Disable
170 ///
171 /// If set to 1, the assertion of the devices `INTx#` signal is
172 /// disabled; otherwise, assertion of the signal is enabled.
173 pub const INTERRUPT_DISABLE: bool;
174 }
175}
176
177bitfield! {
178 /// Built-In Self Test (BIST) register.
179 #[derive(Eq, PartialEq)]
180 pub struct Bist<u8> {
181 /// The completion code set by running a built-in self test.
182 ///
183 /// If the test completed successfully, this should be 0.
184 pub const COMPLETION_CODE = 3;
185
186 /// Reserved
187 const _RES = 2;
188
189 /// Start BIST
190 ///
191 /// Set to 1 by the OS to start a BIST. This bit is reset when BIST
192 /// completes. If BIST does not complete after 2 seconds the device
193 /// should be failed by system software.
194 pub const START_BIST: bool;
195 /// BIST Capable
196 ///
197 /// If this is 1, the device supports BIST. If it is 0, this device does
198 /// not support a built-in self test.
199 pub const BIST_CAPABLE: bool;
200 }
201}
202
203impl Bist {
204 /// Returns the device's BIST completion code, if a BIST has completed.
205 ///
206 /// If the BIST is still in progress, this method returns `None`.
207 pub fn completion_code(self) -> Option<u8> {
208 if self.get(Self::START_BIST) {
209 return None;
210 }
211
212 Some(self.get(Self::COMPLETION_CODE))
213 }
214}
215
216/// Slowest time that a device will assert `DEVSEL#` for any bus command except
217/// Configuration Space reads/writes.
218#[derive(Clone, Debug, Eq, PartialEq)]
219#[repr(u8)]
220pub enum DevselTiming {
221 Fast = 0x0,
222 Medium = 0x1,
223 Slow = 0x2,
224}
225
226bitfield! {
227 pub(crate) struct RegisterWord<u32> {
228 pub(crate) const COMMAND: Command;
229 pub(crate) const STATUS: Status;
230 }
231}
232
233// === impl Status ===
234
235impl Status {
236 /// Returns `true` if this device received an abort (either a Master Abort
237 /// or Target Abort).
238 ///
239 /// This returns `true` if the [`Status::RECEIVED_MASTER_ABORT`] or
240 /// [`Status::RECEIVED_TARGET_ABORT`] bits are set.
241 pub fn received_abort(self) -> bool {
242 self.get(Self::RECEIVED_MASTER_ABORT) || self.get(Self::RECEIVED_TARGET_ABORT)
243 }
244}
245
246impl FromBits<u32> for Status {
247 const BITS: u32 = 16;
248 type Error = core::convert::Infallible;
249
250 fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
251 Ok(Self::from_bits((bits >> 16) as u16))
252 }
253
254 fn into_bits(self) -> u32 {
255 (self.bits() as u32) << 16
256 }
257}
258
259// === impl Command ===
260
261impl FromBits<u32> for Command {
262 const BITS: u32 = 16;
263 type Error = core::convert::Infallible;
264
265 fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
266 Ok(Self::from_bits(bits as u16))
267 }
268
269 fn into_bits(self) -> u32 {
270 self.bits() as u32
271 }
272}
273
274// === impl DevselTiming ===
275
276impl FromBits<u16> for DevselTiming {
277 const BITS: u32 = 2;
278 type Error = crate::error::UnexpectedValue<u16>;
279
280 fn try_from_bits(bits: u16) -> Result<Self, Self::Error> {
281 match bits as u8 {
282 bits if bits == Self::Fast as u8 => Ok(Self::Fast),
283 bits if bits == Self::Medium as u8 => Ok(Self::Medium),
284 bits if bits == Self::Slow as u8 => Ok(Self::Slow),
285 _ => Err(crate::error::unexpected(bits).named("DEVSEL timing")),
286 }
287 }
288
289 fn into_bits(self) -> u16 {
290 self as u16
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn status_is_valid() {
300 Status::assert_valid();
301 }
302
303 #[test]
304 fn command_is_valid() {
305 Status::assert_valid();
306 }
307
308 #[test]
309 fn register_word_is_valid() {
310 RegisterWord::assert_valid();
311 }
312}