1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use super::{INTERRUPT_STATUS_CONFIG_CHANGED, INTERRUPT_STATUS_USED_RING, VIRTIO_MSI_NO_VECTOR}; 6 use crate::pci::MsixConfig; 7 use base::Event; 8 use std::sync::atomic::{AtomicUsize, Ordering}; 9 use std::sync::Arc; 10 use sync::Mutex; 11 12 pub trait SignalableInterrupt { 13 /// Writes to the irqfd to VMM to deliver virtual interrupt to the guest. signal(&self, vector: u16, interrupt_status_mask: u32)14 fn signal(&self, vector: u16, interrupt_status_mask: u32); 15 16 /// Notify the driver that buffers have been placed in the used queue. signal_used_queue(&self, vector: u16)17 fn signal_used_queue(&self, vector: u16) { 18 self.signal(vector, INTERRUPT_STATUS_USED_RING) 19 } 20 21 /// Notify the driver that the device configuration has changed. signal_config_changed(&self)22 fn signal_config_changed(&self); 23 24 /// Get the event to signal resampling is needed if it exists. get_resample_evt(&self) -> Option<&Event>25 fn get_resample_evt(&self) -> Option<&Event>; 26 27 /// Reads the status and writes to the interrupt event. Doesn't read the resample event, it 28 /// assumes the resample has been requested. do_interrupt_resample(&self)29 fn do_interrupt_resample(&self); 30 } 31 32 pub struct Interrupt { 33 interrupt_status: Arc<AtomicUsize>, 34 interrupt_evt: Event, 35 interrupt_resample_evt: Event, 36 msix_config: Option<Arc<Mutex<MsixConfig>>>, 37 config_msix_vector: u16, 38 } 39 40 impl SignalableInterrupt for Interrupt { 41 /// Virtqueue Interrupts From The Device 42 /// 43 /// If MSI-X is enabled in this device, MSI-X interrupt is preferred. 44 /// Write to the irqfd to VMM to deliver virtual interrupt to the guest signal(&self, vector: u16, interrupt_status_mask: u32)45 fn signal(&self, vector: u16, interrupt_status_mask: u32) { 46 // Don't need to set ISR for MSI-X interrupts 47 if let Some(msix_config) = &self.msix_config { 48 let mut msix_config = msix_config.lock(); 49 if msix_config.enabled() { 50 if vector != VIRTIO_MSI_NO_VECTOR { 51 msix_config.trigger(vector); 52 } 53 return; 54 } 55 } 56 57 // Set bit in ISR and inject the interrupt if it was not already pending. 58 // Don't need to inject the interrupt if the guest hasn't processed it. 59 if self 60 .interrupt_status 61 .fetch_or(interrupt_status_mask as usize, Ordering::SeqCst) 62 == 0 63 { 64 // Write to irqfd to inject INTx interrupt 65 self.interrupt_evt.write(1).unwrap(); 66 } 67 } 68 signal_config_changed(&self)69 fn signal_config_changed(&self) { 70 self.signal(self.config_msix_vector, INTERRUPT_STATUS_CONFIG_CHANGED) 71 } 72 get_resample_evt(&self) -> Option<&Event>73 fn get_resample_evt(&self) -> Option<&Event> { 74 Some(&self.interrupt_resample_evt) 75 } 76 do_interrupt_resample(&self)77 fn do_interrupt_resample(&self) { 78 if self.interrupt_status.load(Ordering::SeqCst) != 0 { 79 self.interrupt_evt.write(1).unwrap(); 80 } 81 } 82 } 83 84 impl Interrupt { new( interrupt_status: Arc<AtomicUsize>, interrupt_evt: Event, interrupt_resample_evt: Event, msix_config: Option<Arc<Mutex<MsixConfig>>>, config_msix_vector: u16, ) -> Interrupt85 pub fn new( 86 interrupt_status: Arc<AtomicUsize>, 87 interrupt_evt: Event, 88 interrupt_resample_evt: Event, 89 msix_config: Option<Arc<Mutex<MsixConfig>>>, 90 config_msix_vector: u16, 91 ) -> Interrupt { 92 Interrupt { 93 interrupt_status, 94 interrupt_evt, 95 interrupt_resample_evt, 96 msix_config, 97 config_msix_vector, 98 } 99 } 100 101 /// Handle interrupt resampling event, reading the value from the event and doing the resample. interrupt_resample(&self)102 pub fn interrupt_resample(&self) { 103 let _ = self.interrupt_resample_evt.read(); 104 self.do_interrupt_resample(); 105 } 106 107 /// Get a reference to the msix configuration get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>>108 pub fn get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>> { 109 &self.msix_config 110 } 111 } 112