diff --git a/vm-virtio/src/lib.rs b/vm-virtio/src/lib.rs index fadb3616b..b039f53f6 100644 --- a/vm-virtio/src/lib.rs +++ b/vm-virtio/src/lib.rs @@ -30,7 +30,6 @@ pub use self::block::*; pub use self::device::*; pub use self::queue::*; -#[allow(dead_code)] const DEVICE_INIT: u32 = 0x00; const DEVICE_ACKNOWLEDGE: u32 = 0x01; const DEVICE_DRIVER: u32 = 0x02; diff --git a/vm-virtio/src/queue.rs b/vm-virtio/src/queue.rs index 79bae7b20..9deab2ae3 100644 --- a/vm-virtio/src/queue.rs +++ b/vm-virtio/src/queue.rs @@ -256,6 +256,12 @@ impl Queue { min(self.size, self.max_size) } + /// Reset the queue to a state that is acceptable for a device reset + pub fn reset(&mut self) { + self.ready = false; + self.size = self.max_size; + } + pub fn is_valid(&self, mem: &GuestMemoryMmap) -> bool { let queue_size = self.actual_size() as usize; let desc_table = self.desc_table; diff --git a/vm-virtio/src/transport/pci_device.rs b/vm-virtio/src/transport/pci_device.rs index 08e0f9e68..21cac3f5a 100755 --- a/vm-virtio/src/transport/pci_device.rs +++ b/vm-virtio/src/transport/pci_device.rs @@ -29,7 +29,7 @@ use vmm_sys_util::{EventFd, Result}; use super::VirtioPciCommonConfig; use crate::{ Queue, VirtioDevice, DEVICE_ACKNOWLEDGE, DEVICE_DRIVER, DEVICE_DRIVER_OK, DEVICE_FAILED, - DEVICE_FEATURES_OK, + DEVICE_FEATURES_OK, DEVICE_INIT, }; #[allow(clippy::enum_variant_names)] @@ -241,6 +241,11 @@ impl VirtioPciDevice { && self.common_config.driver_status & DEVICE_FAILED as u8 == 0 } + /// Determines if the driver has requested the device (re)init / reset itself + fn is_driver_init(&self) -> bool { + self.common_config.driver_status == DEVICE_INIT as u8 + } + fn are_queues_valid(&self) -> bool { if let Some(mem) = self.memory.as_ref() { self.queues.iter().all(|q| q.is_valid(mem)) @@ -441,7 +446,8 @@ impl PciDevice for VirtioPciDevice { if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() { if let Some(interrupt_evt) = self.interrupt_evt.take() { - if let Some(mem) = self.memory.take() { + if self.memory.is_some() { + let mem = self.memory.as_ref().unwrap().clone(); self.device .activate( mem, @@ -455,6 +461,25 @@ impl PciDevice for VirtioPciDevice { } } } + + // Device has been reset by the driver + if self.device_activated && self.is_driver_init() { + if let Some((interrupt_evt, mut queue_evts)) = self.device.reset() { + // Upon reset the device returns its interrupt EventFD and it's queue EventFDs + self.interrupt_evt = Some(interrupt_evt); + self.queue_evts.append(&mut queue_evts); + + self.device_activated = false; + + // Reset queue readiness (changes queue_enable), queue sizes + // and selected_queue as per spec for reset + self.queues.iter_mut().for_each(Queue::reset); + self.common_config.queue_select = 0; + } else { + error!("Attempt to reset device when not implemented in underlying device"); + self.common_config.driver_status = crate::DEVICE_FAILED as u8; + } + } } }