Skip to main content

pci_core/
bus_range.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Shared PCIe bus range tracking.
5//!
6//! An [`AssignedBusRange`] holds the segment-local bus range
7//! `(secondary_bus, subordinate_bus)` assigned to the PCIe port that owns a
8//! device. It is updated automatically by
9//! [`ConfigSpaceType1Emulator`](crate::cfg_space_emu::ConfigSpaceType1Emulator)
10//! when the guest writes bus number registers, and on restore/reset.
11//!
12//! Consumers (ITS wrappers, SMMU) read the bus range to compose a
13//! segment-local device identity (BDF) from the assigned bus numbers.
14
15use std::sync::Arc;
16use std::sync::atomic::AtomicU16;
17use std::sync::atomic::Ordering;
18
19/// Segment-local bus range assigned to a PCIe downstream port.
20///
21/// Stores a packed `(secondary_bus, subordinate_bus)` as an atomic u16,
22/// updated when the PCIe port's bus numbers change. The segment number
23/// is not included here — it is a static property of the root complex
24/// and is held separately by the consumer (e.g., ITS wrappers).
25///
26/// Clone is cheap (just an `Arc` bump).
27#[derive(Clone, Debug)]
28pub struct AssignedBusRange(Arc<AtomicU16>);
29
30impl Default for AssignedBusRange {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl AssignedBusRange {
37    /// Creates a new bus range initialized to zero.
38    pub fn new() -> Self {
39        Self(Arc::new(AtomicU16::new(0)))
40    }
41
42    /// Updates the bus range for the downstream port.
43    pub fn set_bus_range(&self, secondary: u8, subordinate: u8) {
44        self.0.store(
45            (secondary as u16) << 8 | subordinate as u16,
46            Ordering::Relaxed,
47        );
48    }
49
50    /// Returns the current `(secondary_bus, subordinate_bus)`.
51    pub fn bus_range(&self) -> (u8, u8) {
52        let v = self.0.load(Ordering::Relaxed);
53        ((v >> 8) as u8, v as u8)
54    }
55
56    /// Returns whether `bus` falls within the current bus range
57    /// (inclusive on both ends).
58    pub fn contains_bus(&self, bus: u8) -> bool {
59        let (secondary, subordinate) = self.bus_range();
60        bus >= secondary && bus <= subordinate
61    }
62}