1use inspect::Inspect;
7use parking_lot::RwLock;
8use std::sync::Arc;
9
10pub trait SignalMsi: Send + Sync {
12 fn signal_msi(&self, rid: u32, address: u64, data: u32);
16}
17
18struct DisconnectedMsiTarget;
19
20impl SignalMsi for DisconnectedMsiTarget {
21 fn signal_msi(&self, _rid: u32, _address: u64, _data: u32) {
22 tracelimit::warn_ratelimited!("dropped MSI interrupt to disconnected target");
23 }
24}
25
26#[derive(Debug)]
28pub struct MsiConnection {
29 target: MsiTarget,
30}
31
32#[derive(Inspect, Debug, Clone)]
34#[inspect(skip)]
35pub struct MsiTarget {
36 inner: Arc<RwLock<MsiTargetInner>>,
37}
38
39struct MsiTargetInner {
40 signal_msi: Arc<dyn SignalMsi>,
41}
42
43impl std::fmt::Debug for MsiTargetInner {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 let Self { signal_msi: _ } = self;
46 f.debug_struct("MsiTargetInner").finish()
47 }
48}
49
50impl MsiConnection {
51 pub fn new() -> Self {
53 Self {
54 target: MsiTarget {
55 inner: Arc::new(RwLock::new(MsiTargetInner {
56 signal_msi: Arc::new(DisconnectedMsiTarget),
57 })),
58 },
59 }
60 }
61
62 pub fn connect(&self, signal_msi: Arc<dyn SignalMsi>) {
64 let mut inner = self.target.inner.write();
65 inner.signal_msi = signal_msi;
66 }
67
68 pub fn target(&self) -> &MsiTarget {
70 &self.target
71 }
72}
73
74impl MsiTarget {
75 pub fn signal_msi(&self, rid: u32, address: u64, data: u32) {
79 let inner = self.inner.read();
80 inner.signal_msi.signal_msi(rid, address, data);
81 }
82}