virtio-devices: Handle virtio queues interrupts from transport layer

Instead of relying on the virtio-queue crate to store the information
about the MSI-X vectors for each queue, we handle this directly from the
PCI transport layer.

This is the first step in getting closer to the upstream version of
virtio-queue so that we can eventually move fully to the upstream
version.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2022-01-24 15:30:42 +01:00
parent d3081ff50c
commit de3e003e3e
17 changed files with 73 additions and 107 deletions

View File

@ -139,8 +139,7 @@ pub struct NoopVirtioInterrupt {}
impl VirtioInterrupt for NoopVirtioInterrupt { impl VirtioInterrupt for NoopVirtioInterrupt {
fn trigger( fn trigger(
&self, &self,
_int_type: &VirtioInterruptType, _int_type: VirtioInterruptType,
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> std::result::Result<(), std::io::Error> { ) -> std::result::Result<(), std::io::Error> {
Ok(()) Ok(())
} }

View File

@ -165,12 +165,8 @@ struct BalloonEpollHandler {
} }
impl BalloonEpollHandler { impl BalloonEpollHandler {
fn signal( fn signal(&self, int_type: VirtioInterruptType) -> result::Result<(), Error> {
&self, self.interrupt_cb.trigger(int_type).map_err(|e| {
int_type: &VirtioInterruptType,
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> result::Result<(), Error> {
self.interrupt_cb.trigger(int_type, queue).map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
Error::FailedSignal(e) Error::FailedSignal(e)
}) })
@ -268,7 +264,7 @@ impl BalloonEpollHandler {
.map_err(Error::QueueAddUsed)?; .map_err(Error::QueueAddUsed)?;
} }
if used_count > 0 { if used_count > 0 {
self.signal(&VirtioInterruptType::Queue, Some(&self.queues[queue_index]))?; self.signal(VirtioInterruptType::Queue(queue_index as u16))?;
} }
Ok(()) Ok(())
@ -303,7 +299,7 @@ impl EpollHelperHandler for BalloonEpollHandler {
let mut config = self.config.lock().unwrap(); let mut config = self.config.lock().unwrap();
config.num_pages = config.num_pages =
(self.resize_receiver.get_size() >> VIRTIO_BALLOON_PFN_SHIFT) as u32; (self.resize_receiver.get_size() >> VIRTIO_BALLOON_PFN_SHIFT) as u32;
if let Err(e) = self.signal(&VirtioInterruptType::Config, None) { if let Err(e) = self.signal(VirtioInterruptType::Config) {
signal_error = true; signal_error = true;
Err(e) Err(e)
} else { } else {

View File

@ -82,6 +82,7 @@ pub struct BlockCounters {
} }
struct BlockEpollHandler { struct BlockEpollHandler {
queue_index: u16,
queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>, queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
disk_image: Box<dyn AsyncIo>, disk_image: Box<dyn AsyncIo>,
@ -258,7 +259,7 @@ impl BlockEpollHandler {
fn signal_used_queue(&self) -> result::Result<(), DeviceError> { fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(&self.queue)) .trigger(VirtioInterruptType::Queue(self.queue_index))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)
@ -605,6 +606,7 @@ impl VirtioDevice for Block {
.map_err(ActivateError::CreateRateLimiter)?; .map_err(ActivateError::CreateRateLimiter)?;
let mut handler = BlockEpollHandler { let mut handler = BlockEpollHandler {
queue_index: i as u16,
queue, queue,
mem: mem.clone(), mem: mem.clone(),
disk_image: self disk_image: self

View File

@ -199,9 +199,9 @@ impl ConsoleEpollHandler {
used_count > 0 used_count > 0
} }
fn signal_used_queue(&self) -> result::Result<(), DeviceError> { fn signal_used_queue(&self, queue_index: u16) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(&self.queues[0])) .trigger(VirtioInterruptType::Queue(queue_index))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)
@ -239,7 +239,7 @@ impl EpollHelperHandler for ConsoleEpollHandler {
error!("Failed to get queue event: {:?}", e); error!("Failed to get queue event: {:?}", e);
return true; return true;
} else if self.process_input_queue() { } else if self.process_input_queue() {
if let Err(e) = self.signal_used_queue() { if let Err(e) = self.signal_used_queue(0) {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
return true; return true;
} }
@ -249,8 +249,11 @@ impl EpollHelperHandler for ConsoleEpollHandler {
if let Err(e) = self.output_queue_evt.read() { if let Err(e) = self.output_queue_evt.read() {
error!("Failed to get queue event: {:?}", e); error!("Failed to get queue event: {:?}", e);
return true; return true;
} else { } else if self.process_output_queue() {
self.process_output_queue(); if let Err(e) = self.signal_used_queue(1) {
error!("Failed to signal used queue: {:?}", e);
return true;
}
} }
} }
INPUT_EVENT => { INPUT_EVENT => {
@ -258,7 +261,7 @@ impl EpollHelperHandler for ConsoleEpollHandler {
error!("Failed to get input event: {:?}", e); error!("Failed to get input event: {:?}", e);
return true; return true;
} else if self.process_input_queue() { } else if self.process_input_queue() {
if let Err(e) = self.signal_used_queue() { if let Err(e) = self.signal_used_queue(0) {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
return true; return true;
} }
@ -268,10 +271,7 @@ impl EpollHelperHandler for ConsoleEpollHandler {
if let Err(e) = self.config_evt.read() { if let Err(e) = self.config_evt.read() {
error!("Failed to get config event: {:?}", e); error!("Failed to get config event: {:?}", e);
return true; return true;
} else if let Err(e) = self } else if let Err(e) = self.interrupt_cb.trigger(VirtioInterruptType::Config) {
.interrupt_cb
.trigger(&VirtioInterruptType::Config, None)
{
error!("Failed to signal console driver: {:?}", e); error!("Failed to signal console driver: {:?}", e);
return true; return true;
} }
@ -293,7 +293,7 @@ impl EpollHelperHandler for ConsoleEpollHandler {
} }
if self.process_input_queue() { if self.process_input_queue() {
if let Err(e) = self.signal_used_queue() { if let Err(e) = self.signal_used_queue(0) {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
return true; return true;
} }
@ -492,7 +492,7 @@ impl VirtioDevice for Console {
.store(self.common.acked_features, Ordering::Relaxed); .store(self.common.acked_features, Ordering::Relaxed);
if self.common.feature_acked(VIRTIO_CONSOLE_F_SIZE) { if self.common.feature_acked(VIRTIO_CONSOLE_F_SIZE) {
if let Err(e) = interrupt_cb.trigger(&VirtioInterruptType::Config, None) { if let Err(e) = interrupt_cb.trigger(VirtioInterruptType::Config) {
error!("Failed to signal console driver: {:?}", e); error!("Failed to signal console driver: {:?}", e);
} }
} }

View File

@ -25,20 +25,12 @@ use vmm_sys_util::eventfd::EventFd;
pub enum VirtioInterruptType { pub enum VirtioInterruptType {
Config, Config,
Queue, Queue(u16),
} }
pub trait VirtioInterrupt: Send + Sync { pub trait VirtioInterrupt: Send + Sync {
fn trigger( fn trigger(&self, int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error>;
&self, fn notifier(&self, _int_type: VirtioInterruptType) -> Option<EventFd> {
int_type: &VirtioInterruptType,
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> std::result::Result<(), std::io::Error>;
fn notifier(
&self,
_int_type: &VirtioInterruptType,
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> Option<EventFd> {
None None
} }
} }

View File

@ -609,12 +609,9 @@ impl IommuEpollHandler {
false false
} }
fn signal_used_queue( fn signal_used_queue(&self, queue_index: u16) -> result::Result<(), DeviceError> {
&self,
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(queue)) .trigger(VirtioInterruptType::Queue(queue_index))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)
@ -644,7 +641,7 @@ impl EpollHelperHandler for IommuEpollHandler {
error!("Failed to get queue event: {:?}", e); error!("Failed to get queue event: {:?}", e);
return true; return true;
} else if self.request_queue() { } else if self.request_queue() {
if let Err(e) = self.signal_used_queue(&self.queues[0]) { if let Err(e) = self.signal_used_queue(0) {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
return true; return true;
} }
@ -655,7 +652,7 @@ impl EpollHelperHandler for IommuEpollHandler {
error!("Failed to get queue event: {:?}", e); error!("Failed to get queue event: {:?}", e);
return true; return true;
} else if self.event_queue() { } else if self.event_queue() {
if let Err(e) = self.signal_used_queue(&self.queues[1]) { if let Err(e) = self.signal_used_queue(1) {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
return true; return true;
} }

View File

@ -644,13 +644,11 @@ impl MemEpollHandler {
(resp_type, resp_state) (resp_type, resp_state)
} }
fn signal(&self, int_type: &VirtioInterruptType) -> result::Result<(), DeviceError> { fn signal(&self, int_type: VirtioInterruptType) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb.trigger(int_type).map_err(|e| {
.trigger(int_type, Some(&self.queue)) error!("Failed to signal used queue: {:?}", e);
.map_err(|e| { DeviceError::FailedSignalingUsedQueue(e)
error!("Failed to signal used queue: {:?}", e); })
DeviceError::FailedSignalingUsedQueue(e)
})
} }
fn process_queue(&mut self) -> bool { fn process_queue(&mut self) -> bool {
@ -734,7 +732,7 @@ impl EpollHelperHandler for MemEpollHandler {
let mut r = config.resize(size); let mut r = config.resize(size);
r = match r { r = match r {
Err(e) => Err(e), Err(e) => Err(e),
_ => match self.signal(&VirtioInterruptType::Config) { _ => match self.signal(VirtioInterruptType::Config) {
Err(e) => { Err(e) => {
signal_error = true; signal_error = true;
Err(Error::ResizeTriggerFail(e)) Err(Error::ResizeTriggerFail(e))
@ -756,7 +754,7 @@ impl EpollHelperHandler for MemEpollHandler {
error!("Failed to get queue event: {:?}", e); error!("Failed to get queue event: {:?}", e);
return true; return true;
} else if self.process_queue() { } else if self.process_queue() {
if let Err(e) = self.signal(&VirtioInterruptType::Queue) { if let Err(e) = self.signal(VirtioInterruptType::Queue(0)) {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
return true; return true;
} }

View File

@ -124,6 +124,7 @@ struct NetEpollHandler {
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
kill_evt: EventFd, kill_evt: EventFd,
pause_evt: EventFd, pause_evt: EventFd,
queue_index_base: u16,
queue_pair: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queue_pair: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
queue_evt_pair: Vec<EventFd>, queue_evt_pair: Vec<EventFd>,
// Always generate interrupts until the driver has signalled to the device. // Always generate interrupts until the driver has signalled to the device.
@ -134,12 +135,9 @@ struct NetEpollHandler {
} }
impl NetEpollHandler { impl NetEpollHandler {
fn signal_used_queue( fn signal_used_queue(&self, queue_index: u16) -> result::Result<(), DeviceError> {
&self,
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(queue)) .trigger(VirtioInterruptType::Queue(queue_index))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)
@ -182,7 +180,7 @@ impl NetEpollHandler {
.map_err(DeviceError::NetQueuePair)? .map_err(DeviceError::NetQueuePair)?
|| !self.driver_awake || !self.driver_awake
{ {
self.signal_used_queue(&self.queue_pair[1])?; self.signal_used_queue(self.queue_index_base + 1)?;
debug!("Signalling TX queue"); debug!("Signalling TX queue");
} else { } else {
debug!("Not signalling TX queue"); debug!("Not signalling TX queue");
@ -211,7 +209,7 @@ impl NetEpollHandler {
.map_err(DeviceError::NetQueuePair)? .map_err(DeviceError::NetQueuePair)?
|| !self.driver_awake || !self.driver_awake
{ {
self.signal_used_queue(&self.queue_pair[0])?; self.signal_used_queue(self.queue_index_base)?;
debug!("Signalling RX queue"); debug!("Signalling RX queue");
} else { } else {
debug!("Not signalling RX queue"); debug!("Not signalling RX queue");
@ -651,6 +649,7 @@ impl VirtioDevice for Net {
rx_rate_limiter, rx_rate_limiter,
tx_rate_limiter, tx_rate_limiter,
}, },
queue_index_base: (i * 2) as u16,
queue_pair, queue_pair,
queue_evt_pair, queue_evt_pair,
interrupt_cb: interrupt_cb.clone(), interrupt_cb: interrupt_cb.clone(),

View File

@ -213,7 +213,7 @@ impl PmemEpollHandler {
fn signal_used_queue(&self) -> result::Result<(), DeviceError> { fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(&self.queue)) .trigger(VirtioInterruptType::Queue(0))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)

View File

@ -76,7 +76,7 @@ impl RngEpollHandler {
fn signal_used_queue(&self) -> result::Result<(), DeviceError> { fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(&self.queues[0])) .trigger(VirtioInterruptType::Queue(0))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)

View File

@ -24,6 +24,7 @@ pub struct VirtioPciCommonConfigState {
pub driver_feature_select: u32, pub driver_feature_select: u32,
pub queue_select: u16, pub queue_select: u16,
pub msix_config: u16, pub msix_config: u16,
pub msix_queues: Vec<u16>,
} }
impl VersionMapped for VirtioPciCommonConfigState {} impl VersionMapped for VirtioPciCommonConfigState {}
@ -57,6 +58,7 @@ pub struct VirtioPciCommonConfig {
pub driver_feature_select: u32, pub driver_feature_select: u32,
pub queue_select: u16, pub queue_select: u16,
pub msix_config: Arc<AtomicU16>, pub msix_config: Arc<AtomicU16>,
pub msix_queues: Arc<Mutex<Vec<u16>>>,
} }
impl VirtioPciCommonConfig { impl VirtioPciCommonConfig {
@ -68,6 +70,7 @@ impl VirtioPciCommonConfig {
driver_feature_select: self.driver_feature_select, driver_feature_select: self.driver_feature_select,
queue_select: self.queue_select, queue_select: self.queue_select,
msix_config: self.msix_config.load(Ordering::Acquire), msix_config: self.msix_config.load(Ordering::Acquire),
msix_queues: self.msix_queues.lock().unwrap().clone(),
} }
} }
@ -78,6 +81,7 @@ impl VirtioPciCommonConfig {
self.driver_feature_select = state.driver_feature_select; self.driver_feature_select = state.driver_feature_select;
self.queue_select = state.queue_select; self.queue_select = state.queue_select;
self.msix_config.store(state.msix_config, Ordering::Release); self.msix_config.store(state.msix_config, Ordering::Release);
*(self.msix_queues.lock().unwrap()) = state.msix_queues.clone();
} }
pub fn read( pub fn read(
@ -164,7 +168,7 @@ impl VirtioPciCommonConfig {
0x12 => queues.len() as u16, // num_queues 0x12 => queues.len() as u16, // num_queues
0x16 => self.queue_select, 0x16 => self.queue_select,
0x18 => self.with_queue(queues, |q| q.state.size).unwrap_or(0), 0x18 => self.with_queue(queues, |q| q.state.size).unwrap_or(0),
0x1a => self.with_queue(queues, |q| q.state.vector).unwrap_or(0), 0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize],
0x1c => { 0x1c => {
if self.with_queue(queues, |q| q.state.ready).unwrap_or(false) { if self.with_queue(queues, |q| q.state.ready).unwrap_or(false) {
1 1
@ -191,7 +195,7 @@ impl VirtioPciCommonConfig {
0x10 => self.msix_config.store(value, Ordering::Release), 0x10 => self.msix_config.store(value, Ordering::Release),
0x16 => self.queue_select = value, 0x16 => self.queue_select = value,
0x18 => self.with_queue_mut(queues, |q| q.state.size = value), 0x18 => self.with_queue_mut(queues, |q| q.state.size = value),
0x1a => self.with_queue_mut(queues, |q| q.state.vector = value), 0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize] = value,
0x1c => self.with_queue_mut(queues, |q| q.enable(value == 1)), 0x1c => self.with_queue_mut(queues, |q| q.enable(value == 1)),
_ => { _ => {
warn!("invalid virtio register word write: 0x{:x}", offset); warn!("invalid virtio register word write: 0x{:x}", offset);
@ -376,6 +380,7 @@ mod tests {
driver_feature_select: 0x0, driver_feature_select: 0x0,
queue_select: 0xff, queue_select: 0xff,
msix_config: Arc::new(AtomicU16::new(0)), msix_config: Arc::new(AtomicU16::new(0)),
msix_queues: Arc::new(Mutex::new(vec![0; 3])),
}; };
let dev = Arc::new(Mutex::new(DummyDevice(0))); let dev = Arc::new(Mutex::new(DummyDevice(0)));

View File

@ -267,7 +267,6 @@ struct QueueState {
max_size: u16, max_size: u16,
size: u16, size: u16,
ready: bool, ready: bool,
vector: u16,
desc_table: u64, desc_table: u64,
avail_ring: u64, avail_ring: u64,
used_ring: u64, used_ring: u64,
@ -358,6 +357,7 @@ impl VirtioPciDevice {
for _ in locked_device.queue_max_sizes().iter() { for _ in locked_device.queue_max_sizes().iter() {
queue_evts.push(EventFd::new(EFD_NONBLOCK)?) queue_evts.push(EventFd::new(EFD_NONBLOCK)?)
} }
let num_queues = locked_device.queue_max_sizes().len();
let queues = locked_device let queues = locked_device
.queue_max_sizes() .queue_max_sizes()
.iter() .iter()
@ -429,6 +429,7 @@ impl VirtioPciDevice {
driver_feature_select: 0, driver_feature_select: 0,
queue_select: 0, queue_select: 0,
msix_config: Arc::new(AtomicU16::new(VIRTQ_MSI_NO_VECTOR)), msix_config: Arc::new(AtomicU16::new(VIRTQ_MSI_NO_VECTOR)),
msix_queues: Arc::new(Mutex::new(vec![VIRTQ_MSI_NO_VECTOR; num_queues])),
}, },
msix_config, msix_config,
msix_num, msix_num,
@ -453,6 +454,7 @@ impl VirtioPciDevice {
virtio_pci_device.virtio_interrupt = Some(Arc::new(VirtioInterruptMsix::new( virtio_pci_device.virtio_interrupt = Some(Arc::new(VirtioInterruptMsix::new(
msix_config.clone(), msix_config.clone(),
virtio_pci_device.common_config.msix_config.clone(), virtio_pci_device.common_config.msix_config.clone(),
virtio_pci_device.common_config.msix_queues.clone(),
virtio_pci_device.interrupt_source_group.clone(), virtio_pci_device.interrupt_source_group.clone(),
))); )));
} }
@ -471,7 +473,6 @@ impl VirtioPciDevice {
max_size: q.max_size(), max_size: q.max_size(),
size: q.state.size, size: q.state.size,
ready: q.state.ready, ready: q.state.ready,
vector: q.state.vector,
desc_table: q.state.desc_table.0, desc_table: q.state.desc_table.0,
avail_ring: q.state.avail_ring.0, avail_ring: q.state.avail_ring.0,
used_ring: q.state.used_ring.0, used_ring: q.state.used_ring.0,
@ -490,7 +491,6 @@ impl VirtioPciDevice {
for (i, queue) in self.queues.iter_mut().enumerate() { for (i, queue) in self.queues.iter_mut().enumerate() {
queue.state.size = state.queues[i].size; queue.state.size = state.queues[i].size;
queue.state.ready = state.queues[i].ready; queue.state.ready = state.queues[i].ready;
queue.state.vector = state.queues[i].vector;
queue.state.desc_table = GuestAddress(state.queues[i].desc_table); queue.state.desc_table = GuestAddress(state.queues[i].desc_table);
queue.state.avail_ring = GuestAddress(state.queues[i].avail_ring); queue.state.avail_ring = GuestAddress(state.queues[i].avail_ring);
queue.state.used_ring = GuestAddress(state.queues[i].used_ring); queue.state.used_ring = GuestAddress(state.queues[i].used_ring);
@ -716,6 +716,7 @@ impl VirtioTransport for VirtioPciDevice {
pub struct VirtioInterruptMsix { pub struct VirtioInterruptMsix {
msix_config: Arc<Mutex<MsixConfig>>, msix_config: Arc<Mutex<MsixConfig>>,
config_vector: Arc<AtomicU16>, config_vector: Arc<AtomicU16>,
queues_vectors: Arc<Mutex<Vec<u16>>>,
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
} }
@ -723,30 +724,24 @@ impl VirtioInterruptMsix {
pub fn new( pub fn new(
msix_config: Arc<Mutex<MsixConfig>>, msix_config: Arc<Mutex<MsixConfig>>,
config_vector: Arc<AtomicU16>, config_vector: Arc<AtomicU16>,
queues_vectors: Arc<Mutex<Vec<u16>>>,
interrupt_source_group: Arc<dyn InterruptSourceGroup>, interrupt_source_group: Arc<dyn InterruptSourceGroup>,
) -> Self { ) -> Self {
VirtioInterruptMsix { VirtioInterruptMsix {
msix_config, msix_config,
config_vector, config_vector,
queues_vectors,
interrupt_source_group, interrupt_source_group,
} }
} }
} }
impl VirtioInterrupt for VirtioInterruptMsix { impl VirtioInterrupt for VirtioInterruptMsix {
fn trigger( fn trigger(&self, int_type: VirtioInterruptType) -> std::result::Result<(), std::io::Error> {
&self,
int_type: &VirtioInterruptType,
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> std::result::Result<(), std::io::Error> {
let vector = match int_type { let vector = match int_type {
VirtioInterruptType::Config => self.config_vector.load(Ordering::Acquire), VirtioInterruptType::Config => self.config_vector.load(Ordering::Acquire),
VirtioInterruptType::Queue => { VirtioInterruptType::Queue(queue_index) => {
if let Some(q) = queue { self.queues_vectors.lock().unwrap()[queue_index as usize]
q.state.vector
} else {
0
}
} }
}; };
@ -770,19 +765,11 @@ impl VirtioInterrupt for VirtioInterruptMsix {
.trigger(vector as InterruptIndex) .trigger(vector as InterruptIndex)
} }
fn notifier( fn notifier(&self, int_type: VirtioInterruptType) -> Option<EventFd> {
&self,
int_type: &VirtioInterruptType,
queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> Option<EventFd> {
let vector = match int_type { let vector = match int_type {
VirtioInterruptType::Config => self.config_vector.load(Ordering::Acquire), VirtioInterruptType::Config => self.config_vector.load(Ordering::Acquire),
VirtioInterruptType::Queue => { VirtioInterruptType::Queue(queue_index) => {
if let Some(q) = queue { self.queues_vectors.lock().unwrap()[queue_index as usize]
q.state.vector
} else {
0
}
} }
}; };

View File

@ -253,7 +253,7 @@ impl VhostUserHandle {
.map_err(Error::VhostUserSetVringBase)?; .map_err(Error::VhostUserSetVringBase)?;
if let Some(eventfd) = if let Some(eventfd) =
virtio_interrupt.notifier(&VirtioInterruptType::Queue, Some(&queue)) virtio_interrupt.notifier(VirtioInterruptType::Queue(queue_index as u16))
{ {
self.vu self.vu
.set_vring_call(queue_index, &eventfd) .set_vring_call(queue_index, &eventfd)

View File

@ -102,14 +102,11 @@ where
/// Signal the guest driver that we've used some virtio buffers that it had previously made /// Signal the guest driver that we've used some virtio buffers that it had previously made
/// available. /// available.
/// ///
fn signal_used_queue( fn signal_used_queue(&self, queue_index: u16) -> result::Result<(), DeviceError> {
&self,
queue: &Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
) -> result::Result<(), DeviceError> {
debug!("vsock: raising IRQ"); debug!("vsock: raising IRQ");
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(queue)) .trigger(VirtioInterruptType::Queue(queue_index))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)
@ -155,7 +152,7 @@ where
} }
if used_count > 0 { if used_count > 0 {
self.signal_used_queue(&self.queues[0]) self.signal_used_queue(0)
} else { } else {
Ok(()) Ok(())
} }
@ -198,7 +195,7 @@ where
} }
if used_count > 0 { if used_count > 0 {
self.signal_used_queue(&self.queues[1]) self.signal_used_queue(1)
} else { } else {
Ok(()) Ok(())
} }
@ -617,8 +614,8 @@ mod tests {
let ctx = test_ctx.create_epoll_handler_context(); let ctx = test_ctx.create_epoll_handler_context();
let memory = GuestMemoryAtomic::new(test_ctx.mem.clone()); let memory = GuestMemoryAtomic::new(test_ctx.mem.clone());
let queue = Queue::new(memory, 256); let _queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>> = Queue::new(memory, 256);
assert!(ctx.handler.signal_used_queue(&queue).is_ok()); assert!(ctx.handler.signal_used_queue(0).is_ok());
} }
} }

View File

@ -170,7 +170,7 @@ mod tests {
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use virtio_queue::{defs::VIRTQ_DESC_F_NEXT, defs::VIRTQ_DESC_F_WRITE, Queue}; use virtio_queue::{defs::VIRTQ_DESC_F_NEXT, defs::VIRTQ_DESC_F_WRITE};
use vm_memory::{GuestAddress, GuestMemoryAtomic}; use vm_memory::{GuestAddress, GuestMemoryAtomic};
use vm_virtio::queue::testing::VirtQueue as GuestQ; use vm_virtio::queue::testing::VirtQueue as GuestQ;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@ -180,8 +180,7 @@ mod tests {
impl VirtioInterrupt for NoopVirtioInterrupt { impl VirtioInterrupt for NoopVirtioInterrupt {
fn trigger( fn trigger(
&self, &self,
_int_type: &VirtioInterruptType, _int_type: VirtioInterruptType,
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
) -> std::result::Result<(), std::io::Error> { ) -> std::result::Result<(), std::io::Error> {
Ok(()) Ok(())
} }

View File

@ -96,7 +96,7 @@ impl WatchdogEpollHandler {
fn signal_used_queue(&self) -> result::Result<(), DeviceError> { fn signal_used_queue(&self) -> result::Result<(), DeviceError> {
self.interrupt_cb self.interrupt_cb
.trigger(&VirtioInterruptType::Queue, Some(&self.queues[0])) .trigger(VirtioInterruptType::Queue(0))
.map_err(|e| { .map_err(|e| {
error!("Failed to signal used queue: {:?}", e); error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e) DeviceError::FailedSignalingUsedQueue(e)

View File

@ -17,8 +17,8 @@ use vm_memory::{Address, Bytes, GuestAddress, GuestMemory};
use crate::defs::{ use crate::defs::{
DEFAULT_AVAIL_RING_ADDR, DEFAULT_DESC_TABLE_ADDR, DEFAULT_USED_RING_ADDR, DEFAULT_AVAIL_RING_ADDR, DEFAULT_DESC_TABLE_ADDR, DEFAULT_USED_RING_ADDR,
VIRTQ_AVAIL_ELEMENT_SIZE, VIRTQ_AVAIL_RING_HEADER_SIZE, VIRTQ_AVAIL_RING_META_SIZE, VIRTQ_AVAIL_ELEMENT_SIZE, VIRTQ_AVAIL_RING_HEADER_SIZE, VIRTQ_AVAIL_RING_META_SIZE,
VIRTQ_MSI_NO_VECTOR, VIRTQ_USED_ELEMENT_SIZE, VIRTQ_USED_F_NO_NOTIFY, VIRTQ_USED_ELEMENT_SIZE, VIRTQ_USED_F_NO_NOTIFY, VIRTQ_USED_RING_HEADER_SIZE,
VIRTQ_USED_RING_HEADER_SIZE, VIRTQ_USED_RING_META_SIZE, VIRTQ_USED_RING_META_SIZE,
}; };
use crate::{ use crate::{
error, AccessPlatform, AvailIter, Descriptor, Error, QueueStateGuard, QueueStateT, error, AccessPlatform, AvailIter, Descriptor, Error, QueueStateGuard, QueueStateT,
@ -58,9 +58,6 @@ pub struct QueueState {
/// Guest physical address of the used ring. /// Guest physical address of the used ring.
pub used_ring: GuestAddress, pub used_ring: GuestAddress,
/// Interrupt vector
pub vector: u16,
/// Access platform handler /// Access platform handler
pub access_platform: Option<Arc<dyn AccessPlatform>>, pub access_platform: Option<Arc<dyn AccessPlatform>>,
} }
@ -200,7 +197,6 @@ impl QueueStateT for QueueState {
next_used: Wrapping(0), next_used: Wrapping(0),
event_idx_enabled: false, event_idx_enabled: false,
signalled_used: None, signalled_used: None,
vector: VIRTQ_MSI_NO_VECTOR,
access_platform: None, access_platform: None,
} }
} }
@ -266,7 +262,6 @@ impl QueueStateT for QueueState {
self.next_used = Wrapping(0); self.next_used = Wrapping(0);
self.signalled_used = None; self.signalled_used = None;
self.event_idx_enabled = false; self.event_idx_enabled = false;
self.vector = VIRTQ_MSI_NO_VECTOR;
} }
fn lock(&mut self) -> <Self as QueueStateGuard>::G { fn lock(&mut self) -> <Self as QueueStateGuard>::G {