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}