mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-04 04:25:45 +00:00
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:
parent
d3081ff50c
commit
de3e003e3e
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -644,10 +644,8 @@ 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))
|
|
||||||
.map_err(|e| {
|
|
||||||
error!("Failed to signal used queue: {:?}", e);
|
error!("Failed to signal used queue: {:?}", e);
|
||||||
DeviceError::FailedSignalingUsedQueue(e)
|
DeviceError::FailedSignalingUsedQueue(e)
|
||||||
})
|
})
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)));
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user