dbs_interrupt/
notifier.rs1use std::any::Any;
7use std::io::Error;
8use std::sync::Arc;
9
10use vmm_sys_util::eventfd::EventFd;
11
12use crate::{InterruptIndex, InterruptSourceGroup, InterruptStatusRegister32};
13
14#[cfg(feature = "legacy-irq")]
15pub use self::legacy::*;
16#[cfg(feature = "msi-irq")]
17pub use self::msi::*;
18
19pub trait InterruptNotifier: Send + Sync {
21 fn notify(&self) -> Result<(), Error>;
23
24 fn notifier(&self) -> Option<&EventFd>;
26
27 fn clone_boxed(&self) -> Box<dyn InterruptNotifier>;
29
30 fn as_any(&self) -> &dyn Any;
32}
33
34#[cfg(feature = "legacy-irq")]
35mod legacy {
36 use super::*;
37
38 #[derive(Clone)]
40 pub struct LegacyNotifier {
41 pub(crate) intr_group: Arc<Box<dyn InterruptSourceGroup>>,
42 pub(crate) intr_status: Arc<InterruptStatusRegister32>,
43 pub(crate) status_bits: u32,
44 }
45
46 impl LegacyNotifier {
47 pub fn new(
49 intr_group: Arc<Box<dyn InterruptSourceGroup>>,
50 intr_status: Arc<InterruptStatusRegister32>,
51 status_bits: u32,
52 ) -> Self {
53 Self {
54 intr_group,
55 intr_status,
56 status_bits,
57 }
58 }
59 }
60
61 impl InterruptNotifier for LegacyNotifier {
62 fn notify(&self) -> Result<(), Error> {
63 self.intr_status.set_bits(self.status_bits);
64 self.intr_group.trigger(0)
65 }
66
67 fn notifier(&self) -> Option<&EventFd> {
68 self.intr_group.notifier(0)
69 }
70
71 fn clone_boxed(&self) -> Box<dyn InterruptNotifier> {
72 Box::new(self.clone())
73 }
74
75 fn as_any(&self) -> &dyn Any {
76 self
77 }
78 }
79}
80
81#[cfg(feature = "msi-irq")]
82mod msi {
83 use super::*;
84
85 #[derive(Clone)]
87 pub struct MsiNotifier {
88 pub(crate) intr_group: Arc<Box<dyn InterruptSourceGroup>>,
89 pub(crate) intr_index: InterruptIndex,
90 }
91
92 impl MsiNotifier {
93 pub fn new(
95 intr_group: Arc<Box<dyn InterruptSourceGroup>>,
96 intr_index: InterruptIndex,
97 ) -> Self {
98 MsiNotifier {
99 intr_group,
100 intr_index,
101 }
102 }
103 }
104
105 impl InterruptNotifier for MsiNotifier {
106 fn notify(&self) -> Result<(), Error> {
107 self.intr_group.trigger(self.intr_index)
108 }
109
110 fn notifier(&self) -> Option<&EventFd> {
111 self.intr_group.notifier(self.intr_index)
112 }
113
114 fn clone_boxed(&self) -> Box<dyn InterruptNotifier> {
115 Box::new(self.clone())
116 }
117
118 fn as_any(&self) -> &dyn Any {
119 self
120 }
121 }
122}
123
124#[derive(Copy, Clone, Debug, Default)]
126pub struct NoopNotifier {}
127
128impl NoopNotifier {
129 pub fn new() -> Self {
131 NoopNotifier {}
132 }
133}
134
135impl InterruptNotifier for NoopNotifier {
136 fn notify(&self) -> Result<(), Error> {
137 Ok(())
138 }
139
140 fn notifier(&self) -> Option<&EventFd> {
141 None
142 }
143
144 fn clone_boxed(&self) -> Box<dyn InterruptNotifier> {
145 Box::new(*self)
146 }
147
148 fn as_any(&self) -> &dyn Any {
149 self
150 }
151}
152
153pub fn clone_notifier(notifier: &dyn InterruptNotifier) -> Box<dyn InterruptNotifier> {
155 notifier.clone_boxed()
156}
157
158#[cfg(test)]
159mod tests {
160 #![allow(unused_imports)]
161 #![allow(dead_code)]
162 use super::*;
163
164 use crate::{InterruptManager, InterruptSourceType};
165
166 const VIRTIO_INTR_VRING: u32 = 0x01;
167 const VIRTIO_INTR_CONFIG: u32 = 0x02;
168
169 #[test]
170 fn create_virtio_null_notifier() {
171 let notifier = NoopNotifier::new();
172
173 notifier.notify().unwrap();
174 assert!(notifier.notifier().is_none());
175 }
176
177 #[cfg(feature = "kvm-legacy-irq")]
178 #[test]
179 fn test_create_legacy_notifier() {
180 let (_vmfd, irq_manager) = crate::kvm::tests::create_kvm_irq_manager();
181 let group = irq_manager
182 .create_group(InterruptSourceType::LegacyIrq, 0, 1)
183 .unwrap();
184 let status = Arc::new(InterruptStatusRegister32::new());
185 assert_eq!(status.read(), 0);
186
187 let notifer = LegacyNotifier::new(group.clone(), status.clone(), VIRTIO_INTR_CONFIG);
188 notifer.notify().unwrap();
189 assert!(notifer.notifier().is_some());
190 assert_eq!(notifer.status_bits, VIRTIO_INTR_CONFIG);
191 assert_eq!(status.read_and_clear(), VIRTIO_INTR_CONFIG);
192 assert_eq!(status.read(), 0);
193
194 let notifier = LegacyNotifier::new(group.clone(), status.clone(), VIRTIO_INTR_VRING);
195 notifier.notify().unwrap();
196 assert!(notifier.notifier().is_some());
197 assert_eq!(status.read(), VIRTIO_INTR_VRING);
198 status.clear_bits(VIRTIO_INTR_VRING);
199 assert_eq!(status.read(), 0);
200 let eventfd = notifier.notifier().unwrap();
201 assert_eq!(eventfd.read().unwrap(), 2);
202
203 let clone = clone_notifier(¬ifier);
204 assert_eq!(clone.as_any().type_id(), notifier.as_any().type_id());
205 }
206
207 #[cfg(feature = "kvm-msi-irq")]
208 #[test]
209 fn test_virtio_msi_notifier() {
210 let (_vmfd, irq_manager) = crate::kvm::tests::create_kvm_irq_manager();
211 let group = irq_manager
212 .create_group(InterruptSourceType::MsiIrq, 0, 3)
213 .unwrap();
214 let notifier1 = MsiNotifier::new(group.clone(), 1);
215 let notifier2 = MsiNotifier::new(group.clone(), 2);
216 let notifier3 = MsiNotifier::new(group.clone(), 3);
217 assert!(notifier1.notifier().is_some());
218 assert!(notifier2.notifier().is_some());
219 assert!(notifier3.notifier().is_none());
220
221 notifier1.notify().unwrap();
222 notifier1.notify().unwrap();
223 notifier2.notify().unwrap();
224 assert_eq!(notifier1.notifier().unwrap().read().unwrap(), 2);
225 assert_eq!(notifier2.notifier().unwrap().read().unwrap(), 1);
226
227 let clone = clone_notifier(¬ifier1);
228 assert_eq!(clone.as_any().type_id(), notifier1.as_any().type_id());
229 }
230}