mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-22 04:25:21 +00:00
vm-virtio: Reset underlying device on driver request
If the driver triggers a reset by writing zero into the status register then reset the underlying device if supported. A device reset also requires resetting various aspects of the queue. In order to be able to do a subsequent reactivate it is required to reclaim certain resources (interrupt and queue EventFDs.) If a device reset is requested by the driver but the underlying device does not support it then generate an error as the driver would not be able to configure it anyway. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
040ea5432d
commit
3b2faa9f11
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user