pci_core/
msi.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Traits for working with MSI interrupts.
5
6use inspect::Inspect;
7use parking_lot::Mutex;
8use std::sync::Arc;
9use std::sync::Weak;
10use vmcore::interrupt::Interrupt;
11
12/// Trait implemented by targets capable of receiving MSI interrupts.
13pub trait MsiInterruptTarget: Send + Sync {
14    /// Creates a new interrupt object.
15    fn new_interrupt(&self) -> Box<dyn MsiControl>;
16}
17
18/// Trait modelling an individual MSI interrupt.
19pub trait MsiControl: Send {
20    /// Enables the interrupt, so that signaling the interrupt delivers an MSI
21    /// to the specified address/data pair.
22    fn enable(&mut self, address: u64, data: u32);
23
24    /// Disables the interrupt, allowing the backing object to release resources
25    /// associated with this MSI.
26    fn disable(&mut self);
27
28    /// Signals the interrupt.
29    ///
30    /// The caller must ensure that the interrupt is enabled with the same
31    /// address/data pair before calling this method. The address/data is
32    /// provided here redundantly for the convenience of the implementation.
33    fn signal(&mut self, address: u64, data: u32);
34
35    // FUTURE: add mechanisms to use an OS event object for signal. This is
36    // necessary to support sending interrupts across processes.
37    //
38    // This is complicated by differing requirements for the different backends,
39    // e.g. KVM supports taking whatever eventfd you want, while WHP wants to be
40    // the one to provide the event object.
41}
42
43impl<T: Send + FnMut(u64, u32)> MsiControl for T {
44    fn enable(&mut self, _address: u64, _data: u32) {}
45
46    fn disable(&mut self) {}
47
48    fn signal(&mut self, address: u64, data: u32) {
49        (*self)(address, data)
50    }
51}
52
53/// A set of message-signaled interrupts that have yet to be connected to a
54/// backing interrupt controller.
55pub struct MsiInterruptSet {
56    interrupts: Vec<Weak<Mutex<MsiInterruptState>>>,
57}
58
59impl MsiInterruptSet {
60    /// Creates a new empty set of message signaled interrupts.
61    pub fn new() -> Self {
62        Self {
63            interrupts: Vec::new(),
64        }
65    }
66
67    /// Returns the number of interrupts in the set.
68    pub fn len(&self) -> usize {
69        self.interrupts.len()
70    }
71
72    /// Connects the interrupts created with `builder()` to the given target
73    /// interrupt controller.
74    pub fn connect(self, target: &dyn MsiInterruptTarget) {
75        for interrupt in self.interrupts.into_iter().filter_map(|i| i.upgrade()) {
76            let mut control = target.new_interrupt();
77            let mut state = interrupt.lock();
78            if let Some((address, data)) = state.address_data {
79                control.enable(address, data);
80                if state.pending {
81                    control.signal(address, data);
82                    state.pending = false;
83                }
84            }
85            state.control = Some(control);
86        }
87    }
88}
89
90/// Trait for registering message-signaled interrupts for a device.
91pub trait RegisterMsi: Send {
92    /// Returns a new message-signaled interrupt for this device.
93    fn new_msi(&mut self) -> MsiInterrupt;
94}
95
96impl RegisterMsi for MsiInterruptSet {
97    fn new_msi(&mut self) -> MsiInterrupt {
98        let state = Arc::new(Mutex::new(MsiInterruptState {
99            pending: false,
100            address_data: None,
101            control: None,
102        }));
103        self.interrupts.push(Arc::downgrade(&state));
104        MsiInterrupt { state }
105    }
106}
107
108/// A message-signaled interrupt.
109#[derive(Debug, Inspect)]
110pub struct MsiInterrupt {
111    state: Arc<Mutex<MsiInterruptState>>,
112}
113
114#[derive(Inspect)]
115struct MsiInterruptState {
116    pending: bool,
117    #[inspect(with = "inspect_address_data")]
118    address_data: Option<(u64, u32)>,
119    #[inspect(skip)]
120    control: Option<Box<dyn MsiControl>>,
121}
122
123fn inspect_address_data(address_data: &Option<(u64, u32)>) -> String {
124    match address_data {
125        Some((address, data)) => format!("address: {:#x}, data: {:#x}", address, data),
126        None => "None".to_string(),
127    }
128}
129
130impl std::fmt::Debug for MsiInterruptState {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        f.debug_struct("MsiInterruptState")
133            .field("pending", &self.pending)
134            .field("address_data", &self.address_data)
135            .field("control", &"<MsiControl>")
136            .finish()
137    }
138}
139
140impl MsiInterrupt {
141    /// Enables the interrupt.
142    ///
143    /// If `set_pending`, or if the internal pending state is set, then delivers
144    /// the interrupt immediately.
145    pub fn enable(&mut self, address: u64, data: u32, set_pending: bool) {
146        let mut state = self.state.lock();
147        let state = &mut *state;
148        state.pending |= set_pending;
149        state.address_data = Some((address, data));
150        if let Some(control) = &mut state.control {
151            control.enable(address, data);
152            if state.pending {
153                control.signal(address, data);
154                state.pending = false;
155            }
156        }
157    }
158
159    /// Disables the interrupt.
160    ///
161    /// Interrupt deliveries while the interrupt is disabled will set an
162    /// internal pending state.
163    pub fn disable(&mut self) {
164        let mut state = self.state.lock();
165        state.address_data = None;
166        if let Some(control) = &mut state.control {
167            control.disable();
168        }
169    }
170
171    /// Clears any internal pending state and returns it.
172    pub fn drain_pending(&mut self) -> bool {
173        let mut state = self.state.lock();
174        std::mem::take(&mut state.pending)
175    }
176
177    /// Returns an object that can be used to deliver the interrupt.
178    pub fn interrupt(&mut self) -> Interrupt {
179        let state = self.state.clone();
180        Interrupt::from_fn(move || {
181            let mut state = state.lock();
182            let state = &mut *state;
183            if let Some((control, (address, data))) = state.control.as_mut().zip(state.address_data)
184            {
185                control.signal(address, data);
186            } else {
187                state.pending = true;
188            }
189        })
190    }
191}