pci_x86/bdf.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5use core::fmt::{self, Display, Formatter};
6
7/// Unique identifier of a PCI device
8///
9/// BDF stands for bus, device, function, which is the standard way to identify
10/// and address individual PCI devices on a system.
11///
12/// Internally this is a newtype around a u32, with the BDF fields packed in such
13/// a way that the can be used to easily construct PCI configuration addresses.
14#[derive(Copy, Clone, Eq, PartialEq, Debug)]
15pub struct Bdf(u32);
16
17impl Bdf {
18 /// Constructs a new BDF value from individual components.
19 ///
20 /// The valid range for `bus` is 0..=255, for `device` is 0..=31, and for
21 /// `function` is 0..=7. This function will silently truncate any extra leading
22 /// bits from the `device` and `function` parameters before constructing the
23 /// final BDF value.
24 pub const fn new(bus: u8, device: u8, function: u8) -> Self {
25 let bdf = ((bus as u32) << 16)
26 | (((device as u32) & 0x1F) << 11)
27 | (((function as u32) & 0x07) << 8);
28 Bdf(bdf)
29 }
30
31 /// Returns the bus number component of this BDF.
32 #[inline]
33 pub const fn bus(&self) -> u8 {
34 ((self.0 >> 16) & 0xFF) as u8
35 }
36
37 /// Returns the device number component of this BDF.
38 #[inline]
39 pub const fn device(&self) -> u8 {
40 ((self.0 >> 11) & 0x1F) as u8
41 }
42
43 /// Returns the function number component of this BDF.
44 #[inline]
45 pub const fn function(&self) -> u8 {
46 ((self.0 >> 8) & 0x07) as u8
47 }
48
49 /// Constructs the 32-bit CONFIG_ADDRESS value for a given register offset.
50 ///
51 /// Sets the enable bit (bit 31), includes the BDF tag, and aligns the
52 /// register offset to a 32-bit boundary as required by PCI spec.
53 #[inline]
54 pub(crate) const fn cfg_addr(&self, offset: u16) -> u32 {
55 let reg = (offset as u32) & 0xFC;
56 0x8000_0000 | self.0 | reg
57 }
58}
59
60impl Display for Bdf {
61 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
62 write!(
63 f,
64 "{:02x}:{:02x}.{}",
65 self.bus(),
66 self.device(),
67 self.function()
68 )
69 }
70}