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}