|
| 1 | +use std::sync::{atomic::AtomicBool, atomic::Ordering, Arc}; |
| 2 | +use vm_device::interrupt::trigger::{eventfd::EventFdTrigger, Trigger}; |
| 3 | +use vm_device::interrupt::{Interrupt, InterruptSourceGroup, Result}; |
| 4 | +use vmm_sys_util::eventfd::EventFd; |
| 5 | +extern crate libc; |
| 6 | + |
| 7 | +/// Defines an implementation for a VMM speciffic interrupt type |
| 8 | +pub struct CustomInterrupt { |
| 9 | + trigger: EventFdTrigger, |
| 10 | + enabled: AtomicBool, |
| 11 | +} |
| 12 | + |
| 13 | +impl Interrupt for CustomInterrupt { |
| 14 | + type TriggerType = EventFdTrigger; |
| 15 | + |
| 16 | + fn trigger(&self) -> std::result::Result<(), <Self::TriggerType as Trigger>::E> { |
| 17 | + if self.enabled.load(Ordering::Acquire) { |
| 18 | + self.trigger.trigger() |
| 19 | + } else { |
| 20 | + Err(std::io::Error::from_raw_os_error(libc::EINVAL)) |
| 21 | + } |
| 22 | + } |
| 23 | + |
| 24 | + /// Return the underlying trigger |
| 25 | + fn notifier(&self) -> Option<Self::TriggerType> { |
| 26 | + Some(self.trigger.try_clone().unwrap()) |
| 27 | + } |
| 28 | + |
| 29 | + /// Enable generation of interrupts from this interrupt source. |
| 30 | + fn enable(&self) -> Result<()> { |
| 31 | + // Change the state of the interrupt to enabled. |
| 32 | + // In other implementation, here is the place that the event |
| 33 | + // may be registered with listeners (e.g. register irqfd with KVM) |
| 34 | + // For interrupt tha should be enabled as a group and not idividually |
| 35 | + // e.g. MSI interrupts, this method should return OperationNotSupported. |
| 36 | + self.enabled.store(true, Ordering::Release); |
| 37 | + Ok(()) |
| 38 | + } |
| 39 | + |
| 40 | + /// Disable generation of interrupts from this interrupt source. |
| 41 | + fn disable(&self) -> Result<()> { |
| 42 | + // Change the state of the interrupt to disabled. |
| 43 | + self.enabled.store(false, Ordering::Release); |
| 44 | + Ok(()) |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +/// The custom interrupt group that all the interrupts for the device |
| 49 | +pub struct CustomInterruptGroup { |
| 50 | + interrupts: Vec<Arc<CustomInterrupt>>, |
| 51 | +} |
| 52 | + |
| 53 | +impl CustomInterruptGroup { |
| 54 | + pub fn new() -> Self { |
| 55 | + CustomInterruptGroup { |
| 56 | + interrupts: Vec::new(), |
| 57 | + } |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +impl InterruptSourceGroup for CustomInterruptGroup { |
| 62 | + /// Type of the interrupts contained in this group. |
| 63 | + type InterruptType = CustomInterrupt; |
| 64 | + /// Interrupts are wrapped in an Arc to allow for easy access when triggering. |
| 65 | + type InterruptWrapper = Arc<CustomInterrupt>; |
| 66 | + |
| 67 | + fn is_empty(&self) -> bool { |
| 68 | + self.interrupts.is_empty() |
| 69 | + } |
| 70 | + |
| 71 | + fn len(&self) -> usize { |
| 72 | + self.interrupts.len() |
| 73 | + } |
| 74 | + |
| 75 | + fn enable(&self) -> Result<()> { |
| 76 | + // For interrupts that should be enabled as a group (e.g. MSI), this method |
| 77 | + // should coordinate enabling of all interrupts using methods from |
| 78 | + // CustomInterrupt instead of the Interrupt trait. |
| 79 | + Ok(for i in &self.interrupts { |
| 80 | + i.enable().unwrap() |
| 81 | + }) |
| 82 | + } |
| 83 | + |
| 84 | + fn disable(&self) -> Result<()> { |
| 85 | + Ok(for i in &self.interrupts { |
| 86 | + i.disable().unwrap() |
| 87 | + }) |
| 88 | + } |
| 89 | + |
| 90 | + fn get(&self, index: usize) -> Option<Self::InterruptWrapper> { |
| 91 | + match self.interrupts.get(index) { |
| 92 | + Some(interrupt) => Some(interrupt.clone()), |
| 93 | + None => None, |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + /// Request new interrupts within this group. |
| 98 | + fn allocate_interrupts(&mut self, size: usize) -> Result<()> { |
| 99 | + for _ in 0..size { |
| 100 | + let irq_fd = EventFd::new(libc::EFD_NONBLOCK)?; |
| 101 | + let interrupt = CustomInterrupt { |
| 102 | + trigger: EventFdTrigger::new(irq_fd), |
| 103 | + enabled: AtomicBool::new(false), |
| 104 | + }; |
| 105 | + self.interrupts.push(Arc::new(interrupt)); |
| 106 | + } |
| 107 | + Ok(()) |
| 108 | + } |
| 109 | + |
| 110 | + /// Release all interrupts within this group. |
| 111 | + fn free_interrupts(&mut self) -> Result<()> { |
| 112 | + self.interrupts.clear(); |
| 113 | + Ok(()) |
| 114 | + } |
| 115 | +} |
0 commit comments