1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicUsize; 7*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc; 9*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 10*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant; 11*bb4ee6a4SAndroid Build Coastguard Worker 12*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 13*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 14*bb4ee6a4SAndroid Build Coastguard Worker use base::Event; 15*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 16*bb4ee6a4SAndroid Build Coastguard Worker use metrics::log_metric; 17*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 18*bb4ee6a4SAndroid Build Coastguard Worker use metrics::MetricEventType; 19*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize; 20*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize; 21*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex; 22*bb4ee6a4SAndroid Build Coastguard Worker 23*bb4ee6a4SAndroid Build Coastguard Worker use super::INTERRUPT_STATUS_CONFIG_CHANGED; 24*bb4ee6a4SAndroid Build Coastguard Worker use super::INTERRUPT_STATUS_USED_RING; 25*bb4ee6a4SAndroid Build Coastguard Worker use super::VIRTIO_MSI_NO_VECTOR; 26*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 27*bb4ee6a4SAndroid Build Coastguard Worker use crate::acpi::PmWakeupEvent; 28*bb4ee6a4SAndroid Build Coastguard Worker use crate::irq_event::IrqEdgeEvent; 29*bb4ee6a4SAndroid Build Coastguard Worker use crate::irq_event::IrqLevelEvent; 30*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::MsixConfig; 31*bb4ee6a4SAndroid Build Coastguard Worker 32*bb4ee6a4SAndroid Build Coastguard Worker struct TransportPci { 33*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_lvl: IrqLevelEvent, 34*bb4ee6a4SAndroid Build Coastguard Worker msix_config: Option<Arc<Mutex<MsixConfig>>>, 35*bb4ee6a4SAndroid Build Coastguard Worker config_msix_vector: u16, 36*bb4ee6a4SAndroid Build Coastguard Worker } 37*bb4ee6a4SAndroid Build Coastguard Worker 38*bb4ee6a4SAndroid Build Coastguard Worker enum Transport { 39*bb4ee6a4SAndroid Build Coastguard Worker Pci { 40*bb4ee6a4SAndroid Build Coastguard Worker pci: TransportPci, 41*bb4ee6a4SAndroid Build Coastguard Worker }, 42*bb4ee6a4SAndroid Build Coastguard Worker Mmio { 43*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_edge: IrqEdgeEvent, 44*bb4ee6a4SAndroid Build Coastguard Worker }, 45*bb4ee6a4SAndroid Build Coastguard Worker VhostUser { 46*bb4ee6a4SAndroid Build Coastguard Worker call_evt: Event, 47*bb4ee6a4SAndroid Build Coastguard Worker signal_config_changed_fn: Box<dyn Fn() + Send + Sync>, 48*bb4ee6a4SAndroid Build Coastguard Worker }, 49*bb4ee6a4SAndroid Build Coastguard Worker } 50*bb4ee6a4SAndroid Build Coastguard Worker 51*bb4ee6a4SAndroid Build Coastguard Worker struct InterruptInner { 52*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: AtomicUsize, 53*bb4ee6a4SAndroid Build Coastguard Worker transport: Transport, 54*bb4ee6a4SAndroid Build Coastguard Worker async_intr_status: bool, 55*bb4ee6a4SAndroid Build Coastguard Worker pm_state: Arc<Mutex<PmState>>, 56*bb4ee6a4SAndroid Build Coastguard Worker } 57*bb4ee6a4SAndroid Build Coastguard Worker 58*bb4ee6a4SAndroid Build Coastguard Worker impl InterruptInner { 59*bb4ee6a4SAndroid Build Coastguard Worker /// Add `interrupt_status_mask` to any existing interrupt status. 60*bb4ee6a4SAndroid Build Coastguard Worker /// 61*bb4ee6a4SAndroid Build Coastguard Worker /// Returns `true` if the interrupt should be triggered after this update. update_interrupt_status(&self, interrupt_status_mask: u32) -> bool62*bb4ee6a4SAndroid Build Coastguard Worker fn update_interrupt_status(&self, interrupt_status_mask: u32) -> bool { 63*bb4ee6a4SAndroid Build Coastguard Worker // Set bit in ISR and inject the interrupt if it was not already pending. 64*bb4ee6a4SAndroid Build Coastguard Worker // Don't need to inject the interrupt if the guest hasn't processed it. 65*bb4ee6a4SAndroid Build Coastguard Worker // In hypervisors where interrupt_status is updated asynchronously, inject the 66*bb4ee6a4SAndroid Build Coastguard Worker // interrupt even if the previous interrupt appears to be already pending. 67*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_status 68*bb4ee6a4SAndroid Build Coastguard Worker .fetch_or(interrupt_status_mask as usize, Ordering::SeqCst) 69*bb4ee6a4SAndroid Build Coastguard Worker == 0 70*bb4ee6a4SAndroid Build Coastguard Worker || self.async_intr_status 71*bb4ee6a4SAndroid Build Coastguard Worker } 72*bb4ee6a4SAndroid Build Coastguard Worker } 73*bb4ee6a4SAndroid Build Coastguard Worker 74*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone)] 75*bb4ee6a4SAndroid Build Coastguard Worker pub struct Interrupt { 76*bb4ee6a4SAndroid Build Coastguard Worker inner: Arc<InterruptInner>, 77*bb4ee6a4SAndroid Build Coastguard Worker } 78*bb4ee6a4SAndroid Build Coastguard Worker 79*bb4ee6a4SAndroid Build Coastguard Worker impl fmt::Debug for Interrupt { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result80*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 81*bb4ee6a4SAndroid Build Coastguard Worker write!(f, "Interrupt") 82*bb4ee6a4SAndroid Build Coastguard Worker } 83*bb4ee6a4SAndroid Build Coastguard Worker } 84*bb4ee6a4SAndroid Build Coastguard Worker 85*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 86*bb4ee6a4SAndroid Build Coastguard Worker pub struct InterruptSnapshot { 87*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: usize, 88*bb4ee6a4SAndroid Build Coastguard Worker } 89*bb4ee6a4SAndroid Build Coastguard Worker 90*bb4ee6a4SAndroid Build Coastguard Worker impl Interrupt { 91*bb4ee6a4SAndroid Build Coastguard Worker /// Writes to the irqfd to VMM to deliver virtual interrupt to the guest. 92*bb4ee6a4SAndroid Build Coastguard Worker /// 93*bb4ee6a4SAndroid Build Coastguard Worker /// If MSI-X is enabled in this device, MSI-X interrupt is preferred. 94*bb4ee6a4SAndroid Build Coastguard Worker /// Write to the irqfd to VMM to deliver virtual interrupt to the guest signal(&self, vector: u16, interrupt_status_mask: u32)95*bb4ee6a4SAndroid Build Coastguard Worker pub fn signal(&self, vector: u16, interrupt_status_mask: u32) { 96*bb4ee6a4SAndroid Build Coastguard Worker if self 97*bb4ee6a4SAndroid Build Coastguard Worker .inner 98*bb4ee6a4SAndroid Build Coastguard Worker .pm_state 99*bb4ee6a4SAndroid Build Coastguard Worker .lock() 100*bb4ee6a4SAndroid Build Coastguard Worker .handle_interrupt(vector, interrupt_status_mask) 101*bb4ee6a4SAndroid Build Coastguard Worker { 102*bb4ee6a4SAndroid Build Coastguard Worker return; 103*bb4ee6a4SAndroid Build Coastguard Worker } 104*bb4ee6a4SAndroid Build Coastguard Worker 105*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.transport { 106*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => { 107*bb4ee6a4SAndroid Build Coastguard Worker // Don't need to set ISR for MSI-X interrupts 108*bb4ee6a4SAndroid Build Coastguard Worker if let Some(msix_config) = &pci.msix_config { 109*bb4ee6a4SAndroid Build Coastguard Worker let mut msix_config = msix_config.lock(); 110*bb4ee6a4SAndroid Build Coastguard Worker if msix_config.enabled() { 111*bb4ee6a4SAndroid Build Coastguard Worker if vector != VIRTIO_MSI_NO_VECTOR { 112*bb4ee6a4SAndroid Build Coastguard Worker msix_config.trigger(vector); 113*bb4ee6a4SAndroid Build Coastguard Worker } 114*bb4ee6a4SAndroid Build Coastguard Worker return; 115*bb4ee6a4SAndroid Build Coastguard Worker } 116*bb4ee6a4SAndroid Build Coastguard Worker } 117*bb4ee6a4SAndroid Build Coastguard Worker 118*bb4ee6a4SAndroid Build Coastguard Worker if self.inner.update_interrupt_status(interrupt_status_mask) { 119*bb4ee6a4SAndroid Build Coastguard Worker pci.irq_evt_lvl.trigger().unwrap(); 120*bb4ee6a4SAndroid Build Coastguard Worker } 121*bb4ee6a4SAndroid Build Coastguard Worker } 122*bb4ee6a4SAndroid Build Coastguard Worker Transport::Mmio { irq_evt_edge } => { 123*bb4ee6a4SAndroid Build Coastguard Worker if self.inner.update_interrupt_status(interrupt_status_mask) { 124*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_edge.trigger().unwrap(); 125*bb4ee6a4SAndroid Build Coastguard Worker } 126*bb4ee6a4SAndroid Build Coastguard Worker } 127*bb4ee6a4SAndroid Build Coastguard Worker Transport::VhostUser { call_evt, .. } => { 128*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/187487351): To avoid sending unnecessary events, we might want to support 129*bb4ee6a4SAndroid Build Coastguard Worker // interrupt status. For this purpose, we need a mechanism to share interrupt status 130*bb4ee6a4SAndroid Build Coastguard Worker // between the vmm and the device process. 131*bb4ee6a4SAndroid Build Coastguard Worker call_evt.signal().unwrap(); 132*bb4ee6a4SAndroid Build Coastguard Worker } 133*bb4ee6a4SAndroid Build Coastguard Worker } 134*bb4ee6a4SAndroid Build Coastguard Worker } 135*bb4ee6a4SAndroid Build Coastguard Worker 136*bb4ee6a4SAndroid Build Coastguard Worker /// Notify the driver that buffers have been placed in the used queue. signal_used_queue(&self, vector: u16)137*bb4ee6a4SAndroid Build Coastguard Worker pub fn signal_used_queue(&self, vector: u16) { 138*bb4ee6a4SAndroid Build Coastguard Worker self.signal(vector, INTERRUPT_STATUS_USED_RING) 139*bb4ee6a4SAndroid Build Coastguard Worker } 140*bb4ee6a4SAndroid Build Coastguard Worker 141*bb4ee6a4SAndroid Build Coastguard Worker /// Notify the driver that the device configuration has changed. signal_config_changed(&self)142*bb4ee6a4SAndroid Build Coastguard Worker pub fn signal_config_changed(&self) { 143*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.as_ref().transport { 144*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => { 145*bb4ee6a4SAndroid Build Coastguard Worker self.signal(pci.config_msix_vector, INTERRUPT_STATUS_CONFIG_CHANGED) 146*bb4ee6a4SAndroid Build Coastguard Worker } 147*bb4ee6a4SAndroid Build Coastguard Worker Transport::Mmio { .. } => { 148*bb4ee6a4SAndroid Build Coastguard Worker self.signal(VIRTIO_MSI_NO_VECTOR, INTERRUPT_STATUS_CONFIG_CHANGED) 149*bb4ee6a4SAndroid Build Coastguard Worker } 150*bb4ee6a4SAndroid Build Coastguard Worker Transport::VhostUser { 151*bb4ee6a4SAndroid Build Coastguard Worker signal_config_changed_fn, 152*bb4ee6a4SAndroid Build Coastguard Worker .. 153*bb4ee6a4SAndroid Build Coastguard Worker } => signal_config_changed_fn(), 154*bb4ee6a4SAndroid Build Coastguard Worker } 155*bb4ee6a4SAndroid Build Coastguard Worker } 156*bb4ee6a4SAndroid Build Coastguard Worker 157*bb4ee6a4SAndroid Build Coastguard Worker /// Get the event to signal resampling is needed if it exists. get_resample_evt(&self) -> Option<&Event>158*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_resample_evt(&self) -> Option<&Event> { 159*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.as_ref().transport { 160*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => Some(pci.irq_evt_lvl.get_resample()), 161*bb4ee6a4SAndroid Build Coastguard Worker _ => None, 162*bb4ee6a4SAndroid Build Coastguard Worker } 163*bb4ee6a4SAndroid Build Coastguard Worker } 164*bb4ee6a4SAndroid Build Coastguard Worker 165*bb4ee6a4SAndroid Build Coastguard Worker /// Reads the status and writes to the interrupt event. Doesn't read the resample event, it 166*bb4ee6a4SAndroid Build Coastguard Worker /// assumes the resample has been requested. do_interrupt_resample(&self)167*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_interrupt_resample(&self) { 168*bb4ee6a4SAndroid Build Coastguard Worker if self.inner.interrupt_status.load(Ordering::SeqCst) != 0 { 169*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.as_ref().transport { 170*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => pci.irq_evt_lvl.trigger().unwrap(), 171*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("do_interrupt_resample() not supported"), 172*bb4ee6a4SAndroid Build Coastguard Worker } 173*bb4ee6a4SAndroid Build Coastguard Worker } 174*bb4ee6a4SAndroid Build Coastguard Worker } 175*bb4ee6a4SAndroid Build Coastguard Worker } 176*bb4ee6a4SAndroid Build Coastguard Worker 177*bb4ee6a4SAndroid Build Coastguard Worker impl Interrupt { new( irq_evt_lvl: IrqLevelEvent, msix_config: Option<Arc<Mutex<MsixConfig>>>, config_msix_vector: u16, #[cfg(target_arch = "x86_64")] wakeup_event: Option<(PmWakeupEvent, MetricEventType)>, ) -> Interrupt178*bb4ee6a4SAndroid Build Coastguard Worker pub fn new( 179*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_lvl: IrqLevelEvent, 180*bb4ee6a4SAndroid Build Coastguard Worker msix_config: Option<Arc<Mutex<MsixConfig>>>, 181*bb4ee6a4SAndroid Build Coastguard Worker config_msix_vector: u16, 182*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] wakeup_event: Option<(PmWakeupEvent, MetricEventType)>, 183*bb4ee6a4SAndroid Build Coastguard Worker ) -> Interrupt { 184*bb4ee6a4SAndroid Build Coastguard Worker Interrupt { 185*bb4ee6a4SAndroid Build Coastguard Worker inner: Arc::new(InterruptInner { 186*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: AtomicUsize::new(0), 187*bb4ee6a4SAndroid Build Coastguard Worker async_intr_status: false, 188*bb4ee6a4SAndroid Build Coastguard Worker transport: Transport::Pci { 189*bb4ee6a4SAndroid Build Coastguard Worker pci: TransportPci { 190*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_lvl, 191*bb4ee6a4SAndroid Build Coastguard Worker msix_config, 192*bb4ee6a4SAndroid Build Coastguard Worker config_msix_vector, 193*bb4ee6a4SAndroid Build Coastguard Worker }, 194*bb4ee6a4SAndroid Build Coastguard Worker }, 195*bb4ee6a4SAndroid Build Coastguard Worker pm_state: PmState::new( 196*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 197*bb4ee6a4SAndroid Build Coastguard Worker wakeup_event, 198*bb4ee6a4SAndroid Build Coastguard Worker ), 199*bb4ee6a4SAndroid Build Coastguard Worker }), 200*bb4ee6a4SAndroid Build Coastguard Worker } 201*bb4ee6a4SAndroid Build Coastguard Worker } 202*bb4ee6a4SAndroid Build Coastguard Worker 203*bb4ee6a4SAndroid Build Coastguard Worker /// Create a new `Interrupt`, restoring internal state to match `snapshot`. 204*bb4ee6a4SAndroid Build Coastguard Worker /// 205*bb4ee6a4SAndroid Build Coastguard Worker /// The other arguments are assumed to be snapshot'd and restore'd elsewhere. new_from_snapshot( irq_evt_lvl: IrqLevelEvent, msix_config: Option<Arc<Mutex<MsixConfig>>>, config_msix_vector: u16, snapshot: InterruptSnapshot, #[cfg(target_arch = "x86_64")] wakeup_event: Option<(PmWakeupEvent, MetricEventType)>, ) -> Interrupt206*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_from_snapshot( 207*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_lvl: IrqLevelEvent, 208*bb4ee6a4SAndroid Build Coastguard Worker msix_config: Option<Arc<Mutex<MsixConfig>>>, 209*bb4ee6a4SAndroid Build Coastguard Worker config_msix_vector: u16, 210*bb4ee6a4SAndroid Build Coastguard Worker snapshot: InterruptSnapshot, 211*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] wakeup_event: Option<(PmWakeupEvent, MetricEventType)>, 212*bb4ee6a4SAndroid Build Coastguard Worker ) -> Interrupt { 213*bb4ee6a4SAndroid Build Coastguard Worker Interrupt { 214*bb4ee6a4SAndroid Build Coastguard Worker inner: Arc::new(InterruptInner { 215*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: AtomicUsize::new(snapshot.interrupt_status), 216*bb4ee6a4SAndroid Build Coastguard Worker async_intr_status: false, 217*bb4ee6a4SAndroid Build Coastguard Worker transport: Transport::Pci { 218*bb4ee6a4SAndroid Build Coastguard Worker pci: TransportPci { 219*bb4ee6a4SAndroid Build Coastguard Worker irq_evt_lvl, 220*bb4ee6a4SAndroid Build Coastguard Worker msix_config, 221*bb4ee6a4SAndroid Build Coastguard Worker config_msix_vector, 222*bb4ee6a4SAndroid Build Coastguard Worker }, 223*bb4ee6a4SAndroid Build Coastguard Worker }, 224*bb4ee6a4SAndroid Build Coastguard Worker pm_state: PmState::new( 225*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 226*bb4ee6a4SAndroid Build Coastguard Worker wakeup_event, 227*bb4ee6a4SAndroid Build Coastguard Worker ), 228*bb4ee6a4SAndroid Build Coastguard Worker }), 229*bb4ee6a4SAndroid Build Coastguard Worker } 230*bb4ee6a4SAndroid Build Coastguard Worker } 231*bb4ee6a4SAndroid Build Coastguard Worker new_mmio(irq_evt_edge: IrqEdgeEvent, async_intr_status: bool) -> Interrupt232*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_mmio(irq_evt_edge: IrqEdgeEvent, async_intr_status: bool) -> Interrupt { 233*bb4ee6a4SAndroid Build Coastguard Worker Interrupt { 234*bb4ee6a4SAndroid Build Coastguard Worker inner: Arc::new(InterruptInner { 235*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: AtomicUsize::new(0), 236*bb4ee6a4SAndroid Build Coastguard Worker transport: Transport::Mmio { irq_evt_edge }, 237*bb4ee6a4SAndroid Build Coastguard Worker async_intr_status, 238*bb4ee6a4SAndroid Build Coastguard Worker pm_state: PmState::new( 239*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 240*bb4ee6a4SAndroid Build Coastguard Worker None, 241*bb4ee6a4SAndroid Build Coastguard Worker ), 242*bb4ee6a4SAndroid Build Coastguard Worker }), 243*bb4ee6a4SAndroid Build Coastguard Worker } 244*bb4ee6a4SAndroid Build Coastguard Worker } 245*bb4ee6a4SAndroid Build Coastguard Worker 246*bb4ee6a4SAndroid Build Coastguard Worker /// Create an `Interrupt` wrapping a vhost-user vring call event and function that sends a 247*bb4ee6a4SAndroid Build Coastguard Worker /// VHOST_USER_BACKEND_CONFIG_CHANGE_MSG to the frontend. new_vhost_user( call_evt: Event, signal_config_changed_fn: Box<dyn Fn() + Send + Sync>, ) -> Interrupt248*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_vhost_user( 249*bb4ee6a4SAndroid Build Coastguard Worker call_evt: Event, 250*bb4ee6a4SAndroid Build Coastguard Worker signal_config_changed_fn: Box<dyn Fn() + Send + Sync>, 251*bb4ee6a4SAndroid Build Coastguard Worker ) -> Interrupt { 252*bb4ee6a4SAndroid Build Coastguard Worker Interrupt { 253*bb4ee6a4SAndroid Build Coastguard Worker inner: Arc::new(InterruptInner { 254*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: AtomicUsize::new(0), 255*bb4ee6a4SAndroid Build Coastguard Worker transport: Transport::VhostUser { 256*bb4ee6a4SAndroid Build Coastguard Worker call_evt, 257*bb4ee6a4SAndroid Build Coastguard Worker signal_config_changed_fn, 258*bb4ee6a4SAndroid Build Coastguard Worker }, 259*bb4ee6a4SAndroid Build Coastguard Worker async_intr_status: false, 260*bb4ee6a4SAndroid Build Coastguard Worker pm_state: PmState::new( 261*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 262*bb4ee6a4SAndroid Build Coastguard Worker None, 263*bb4ee6a4SAndroid Build Coastguard Worker ), 264*bb4ee6a4SAndroid Build Coastguard Worker }), 265*bb4ee6a4SAndroid Build Coastguard Worker } 266*bb4ee6a4SAndroid Build Coastguard Worker } 267*bb4ee6a4SAndroid Build Coastguard Worker 268*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] new_for_test() -> Interrupt269*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_for_test() -> Interrupt { 270*bb4ee6a4SAndroid Build Coastguard Worker Interrupt::new( 271*bb4ee6a4SAndroid Build Coastguard Worker IrqLevelEvent::new().unwrap(), 272*bb4ee6a4SAndroid Build Coastguard Worker None, 273*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_MSI_NO_VECTOR, 274*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 275*bb4ee6a4SAndroid Build Coastguard Worker None, 276*bb4ee6a4SAndroid Build Coastguard Worker ) 277*bb4ee6a4SAndroid Build Coastguard Worker } 278*bb4ee6a4SAndroid Build Coastguard Worker 279*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] new_for_test_with_msix() -> Interrupt280*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_for_test_with_msix() -> Interrupt { 281*bb4ee6a4SAndroid Build Coastguard Worker let (_, unused_config_tube) = base::Tube::pair().unwrap(); 282*bb4ee6a4SAndroid Build Coastguard Worker let msix_vectors = 2; 283*bb4ee6a4SAndroid Build Coastguard Worker let msix_cfg = MsixConfig::new( 284*bb4ee6a4SAndroid Build Coastguard Worker msix_vectors, 285*bb4ee6a4SAndroid Build Coastguard Worker unused_config_tube, 286*bb4ee6a4SAndroid Build Coastguard Worker 0, 287*bb4ee6a4SAndroid Build Coastguard Worker "test_device".to_owned(), 288*bb4ee6a4SAndroid Build Coastguard Worker ); 289*bb4ee6a4SAndroid Build Coastguard Worker 290*bb4ee6a4SAndroid Build Coastguard Worker Interrupt::new( 291*bb4ee6a4SAndroid Build Coastguard Worker IrqLevelEvent::new().unwrap(), 292*bb4ee6a4SAndroid Build Coastguard Worker Some(Arc::new(Mutex::new(msix_cfg))), 293*bb4ee6a4SAndroid Build Coastguard Worker msix_vectors, 294*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 295*bb4ee6a4SAndroid Build Coastguard Worker None, 296*bb4ee6a4SAndroid Build Coastguard Worker ) 297*bb4ee6a4SAndroid Build Coastguard Worker } 298*bb4ee6a4SAndroid Build Coastguard Worker 299*bb4ee6a4SAndroid Build Coastguard Worker /// Get a reference to the interrupt event. get_interrupt_evt(&self) -> &Event300*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_interrupt_evt(&self) -> &Event { 301*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.as_ref().transport { 302*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => pci.irq_evt_lvl.get_trigger(), 303*bb4ee6a4SAndroid Build Coastguard Worker Transport::Mmio { irq_evt_edge } => irq_evt_edge.get_trigger(), 304*bb4ee6a4SAndroid Build Coastguard Worker Transport::VhostUser { call_evt, .. } => call_evt, 305*bb4ee6a4SAndroid Build Coastguard Worker } 306*bb4ee6a4SAndroid Build Coastguard Worker } 307*bb4ee6a4SAndroid Build Coastguard Worker 308*bb4ee6a4SAndroid Build Coastguard Worker /// Handle interrupt resampling event, reading the value from the event and doing the resample. interrupt_resample(&self)309*bb4ee6a4SAndroid Build Coastguard Worker pub fn interrupt_resample(&self) { 310*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.as_ref().transport { 311*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => { 312*bb4ee6a4SAndroid Build Coastguard Worker pci.irq_evt_lvl.clear_resample(); 313*bb4ee6a4SAndroid Build Coastguard Worker self.do_interrupt_resample(); 314*bb4ee6a4SAndroid Build Coastguard Worker } 315*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("interrupt_resample() not supported"), 316*bb4ee6a4SAndroid Build Coastguard Worker } 317*bb4ee6a4SAndroid Build Coastguard Worker } 318*bb4ee6a4SAndroid Build Coastguard Worker 319*bb4ee6a4SAndroid Build Coastguard Worker /// Get a reference to the msix configuration get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>>320*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>> { 321*bb4ee6a4SAndroid Build Coastguard Worker match &self.inner.as_ref().transport { 322*bb4ee6a4SAndroid Build Coastguard Worker Transport::Pci { pci } => &pci.msix_config, 323*bb4ee6a4SAndroid Build Coastguard Worker _ => &None, 324*bb4ee6a4SAndroid Build Coastguard Worker } 325*bb4ee6a4SAndroid Build Coastguard Worker } 326*bb4ee6a4SAndroid Build Coastguard Worker 327*bb4ee6a4SAndroid Build Coastguard Worker /// Reads the current value of the interrupt status. read_interrupt_status(&self) -> u8328*bb4ee6a4SAndroid Build Coastguard Worker pub fn read_interrupt_status(&self) -> u8 { 329*bb4ee6a4SAndroid Build Coastguard Worker self.inner.interrupt_status.load(Ordering::SeqCst) as u8 330*bb4ee6a4SAndroid Build Coastguard Worker } 331*bb4ee6a4SAndroid Build Coastguard Worker 332*bb4ee6a4SAndroid Build Coastguard Worker /// Reads the current value of the interrupt status and resets it to 0. read_and_reset_interrupt_status(&self) -> u8333*bb4ee6a4SAndroid Build Coastguard Worker pub fn read_and_reset_interrupt_status(&self) -> u8 { 334*bb4ee6a4SAndroid Build Coastguard Worker self.inner.interrupt_status.swap(0, Ordering::SeqCst) as u8 335*bb4ee6a4SAndroid Build Coastguard Worker } 336*bb4ee6a4SAndroid Build Coastguard Worker 337*bb4ee6a4SAndroid Build Coastguard Worker /// Clear the bits set in `mask` in the interrupt status. clear_interrupt_status_bits(&self, mask: u8)338*bb4ee6a4SAndroid Build Coastguard Worker pub fn clear_interrupt_status_bits(&self, mask: u8) { 339*bb4ee6a4SAndroid Build Coastguard Worker self.inner 340*bb4ee6a4SAndroid Build Coastguard Worker .interrupt_status 341*bb4ee6a4SAndroid Build Coastguard Worker .fetch_and(!(mask as usize), Ordering::SeqCst); 342*bb4ee6a4SAndroid Build Coastguard Worker } 343*bb4ee6a4SAndroid Build Coastguard Worker 344*bb4ee6a4SAndroid Build Coastguard Worker /// Snapshot internal state. Can be restored with with `Interrupt::new_from_snapshot`. snapshot(&self) -> InterruptSnapshot345*bb4ee6a4SAndroid Build Coastguard Worker pub fn snapshot(&self) -> InterruptSnapshot { 346*bb4ee6a4SAndroid Build Coastguard Worker InterruptSnapshot { 347*bb4ee6a4SAndroid Build Coastguard Worker interrupt_status: self.inner.interrupt_status.load(Ordering::SeqCst), 348*bb4ee6a4SAndroid Build Coastguard Worker } 349*bb4ee6a4SAndroid Build Coastguard Worker } 350*bb4ee6a4SAndroid Build Coastguard Worker set_suspended(&self, suspended: bool)351*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_suspended(&self, suspended: bool) { 352*bb4ee6a4SAndroid Build Coastguard Worker let retrigger_evts = self.inner.pm_state.lock().set_suspended(suspended); 353*bb4ee6a4SAndroid Build Coastguard Worker for (vector, interrupt_status_mask) in retrigger_evts.into_iter() { 354*bb4ee6a4SAndroid Build Coastguard Worker self.signal(vector, interrupt_status_mask); 355*bb4ee6a4SAndroid Build Coastguard Worker } 356*bb4ee6a4SAndroid Build Coastguard Worker } 357*bb4ee6a4SAndroid Build Coastguard Worker 358*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] set_wakeup_event_active(&self, active: bool)359*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_wakeup_event_active(&self, active: bool) { 360*bb4ee6a4SAndroid Build Coastguard Worker self.inner.pm_state.lock().set_wakeup_event_active(active); 361*bb4ee6a4SAndroid Build Coastguard Worker } 362*bb4ee6a4SAndroid Build Coastguard Worker } 363*bb4ee6a4SAndroid Build Coastguard Worker 364*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 365*bb4ee6a4SAndroid Build Coastguard Worker struct WakeupState { 366*bb4ee6a4SAndroid Build Coastguard Worker wakeup_event: PmWakeupEvent, 367*bb4ee6a4SAndroid Build Coastguard Worker wakeup_enabled: bool, 368*bb4ee6a4SAndroid Build Coastguard Worker armed_time: Instant, 369*bb4ee6a4SAndroid Build Coastguard Worker metrics_event: MetricEventType, 370*bb4ee6a4SAndroid Build Coastguard Worker wakeup_clear_evt: Option<Event>, 371*bb4ee6a4SAndroid Build Coastguard Worker } 372*bb4ee6a4SAndroid Build Coastguard Worker 373*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 374*bb4ee6a4SAndroid Build Coastguard Worker impl WakeupState { new(wakeup_event: Option<(PmWakeupEvent, MetricEventType)>) -> Option<Self>375*bb4ee6a4SAndroid Build Coastguard Worker fn new(wakeup_event: Option<(PmWakeupEvent, MetricEventType)>) -> Option<Self> { 376*bb4ee6a4SAndroid Build Coastguard Worker wakeup_event.map(|(wakeup_event, metrics_event)| Self { 377*bb4ee6a4SAndroid Build Coastguard Worker wakeup_event, 378*bb4ee6a4SAndroid Build Coastguard Worker wakeup_enabled: false, 379*bb4ee6a4SAndroid Build Coastguard Worker // Not actually armed, but simpler than wrapping with an Option. 380*bb4ee6a4SAndroid Build Coastguard Worker armed_time: Instant::now(), 381*bb4ee6a4SAndroid Build Coastguard Worker metrics_event, 382*bb4ee6a4SAndroid Build Coastguard Worker wakeup_clear_evt: None, 383*bb4ee6a4SAndroid Build Coastguard Worker }) 384*bb4ee6a4SAndroid Build Coastguard Worker } 385*bb4ee6a4SAndroid Build Coastguard Worker trigger_wakeup(&mut self)386*bb4ee6a4SAndroid Build Coastguard Worker fn trigger_wakeup(&mut self) { 387*bb4ee6a4SAndroid Build Coastguard Worker if self.wakeup_clear_evt.is_some() { 388*bb4ee6a4SAndroid Build Coastguard Worker return; 389*bb4ee6a4SAndroid Build Coastguard Worker } 390*bb4ee6a4SAndroid Build Coastguard Worker 391*bb4ee6a4SAndroid Build Coastguard Worker let elapsed = self.armed_time.elapsed().as_millis(); 392*bb4ee6a4SAndroid Build Coastguard Worker log_metric( 393*bb4ee6a4SAndroid Build Coastguard Worker self.metrics_event.clone(), 394*bb4ee6a4SAndroid Build Coastguard Worker elapsed.try_into().unwrap_or(i64::MAX), 395*bb4ee6a4SAndroid Build Coastguard Worker ); 396*bb4ee6a4SAndroid Build Coastguard Worker 397*bb4ee6a4SAndroid Build Coastguard Worker match self.wakeup_event.trigger_wakeup() { 398*bb4ee6a4SAndroid Build Coastguard Worker Ok(clear_evt) => self.wakeup_clear_evt = clear_evt, 399*bb4ee6a4SAndroid Build Coastguard Worker Err(err) => error!("Wakeup trigger failed {:?}", err), 400*bb4ee6a4SAndroid Build Coastguard Worker } 401*bb4ee6a4SAndroid Build Coastguard Worker } 402*bb4ee6a4SAndroid Build Coastguard Worker } 403*bb4ee6a4SAndroid Build Coastguard Worker 404*bb4ee6a4SAndroid Build Coastguard Worker // Power management state of the interrupt. 405*bb4ee6a4SAndroid Build Coastguard Worker struct PmState { 406*bb4ee6a4SAndroid Build Coastguard Worker // Whether or not the virtio device that owns this interrupt is suspended. A 407*bb4ee6a4SAndroid Build Coastguard Worker // suspended virtio device MUST NOT send notifications (i.e. interrupts) to the 408*bb4ee6a4SAndroid Build Coastguard Worker // driver. 409*bb4ee6a4SAndroid Build Coastguard Worker suspended: bool, 410*bb4ee6a4SAndroid Build Coastguard Worker // The queue of interrupts that the virtio device has generated while suspended. 411*bb4ee6a4SAndroid Build Coastguard Worker // These are deferred and sent in order when the device is un-suspended. 412*bb4ee6a4SAndroid Build Coastguard Worker pending_signals: Vec<(u16, u32)>, 413*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 414*bb4ee6a4SAndroid Build Coastguard Worker wakeup_state: Option<WakeupState>, 415*bb4ee6a4SAndroid Build Coastguard Worker } 416*bb4ee6a4SAndroid Build Coastguard Worker 417*bb4ee6a4SAndroid Build Coastguard Worker impl PmState { new( #[cfg(target_arch = "x86_64")] wakeup_event: Option<(PmWakeupEvent, MetricEventType)>, ) -> Arc<Mutex<Self>>418*bb4ee6a4SAndroid Build Coastguard Worker fn new( 419*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] wakeup_event: Option<(PmWakeupEvent, MetricEventType)>, 420*bb4ee6a4SAndroid Build Coastguard Worker ) -> Arc<Mutex<Self>> { 421*bb4ee6a4SAndroid Build Coastguard Worker Arc::new(Mutex::new(Self { 422*bb4ee6a4SAndroid Build Coastguard Worker suspended: false, 423*bb4ee6a4SAndroid Build Coastguard Worker pending_signals: Vec::new(), 424*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 425*bb4ee6a4SAndroid Build Coastguard Worker wakeup_state: WakeupState::new(wakeup_event), 426*bb4ee6a4SAndroid Build Coastguard Worker })) 427*bb4ee6a4SAndroid Build Coastguard Worker } 428*bb4ee6a4SAndroid Build Coastguard Worker handle_interrupt(&mut self, vector: u16, mask: u32) -> bool429*bb4ee6a4SAndroid Build Coastguard Worker fn handle_interrupt(&mut self, vector: u16, mask: u32) -> bool { 430*bb4ee6a4SAndroid Build Coastguard Worker if self.suspended { 431*bb4ee6a4SAndroid Build Coastguard Worker self.pending_signals.push((vector, mask)); 432*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 433*bb4ee6a4SAndroid Build Coastguard Worker if let Some(wakeup_state) = self.wakeup_state.as_mut() { 434*bb4ee6a4SAndroid Build Coastguard Worker if wakeup_state.wakeup_enabled { 435*bb4ee6a4SAndroid Build Coastguard Worker wakeup_state.trigger_wakeup(); 436*bb4ee6a4SAndroid Build Coastguard Worker } 437*bb4ee6a4SAndroid Build Coastguard Worker } 438*bb4ee6a4SAndroid Build Coastguard Worker } 439*bb4ee6a4SAndroid Build Coastguard Worker self.suspended 440*bb4ee6a4SAndroid Build Coastguard Worker } 441*bb4ee6a4SAndroid Build Coastguard Worker set_suspended(&mut self, suspended: bool) -> Vec<(u16, u32)>442*bb4ee6a4SAndroid Build Coastguard Worker fn set_suspended(&mut self, suspended: bool) -> Vec<(u16, u32)> { 443*bb4ee6a4SAndroid Build Coastguard Worker self.suspended = suspended; 444*bb4ee6a4SAndroid Build Coastguard Worker std::mem::take(&mut self.pending_signals) 445*bb4ee6a4SAndroid Build Coastguard Worker } 446*bb4ee6a4SAndroid Build Coastguard Worker 447*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] set_wakeup_event_active(&mut self, active: bool)448*bb4ee6a4SAndroid Build Coastguard Worker fn set_wakeup_event_active(&mut self, active: bool) { 449*bb4ee6a4SAndroid Build Coastguard Worker let Some(wakeup_state) = self.wakeup_state.as_mut() else { 450*bb4ee6a4SAndroid Build Coastguard Worker return; 451*bb4ee6a4SAndroid Build Coastguard Worker }; 452*bb4ee6a4SAndroid Build Coastguard Worker 453*bb4ee6a4SAndroid Build Coastguard Worker wakeup_state.wakeup_enabled = active; 454*bb4ee6a4SAndroid Build Coastguard Worker if active { 455*bb4ee6a4SAndroid Build Coastguard Worker wakeup_state.armed_time = Instant::now(); 456*bb4ee6a4SAndroid Build Coastguard Worker if !self.pending_signals.is_empty() { 457*bb4ee6a4SAndroid Build Coastguard Worker wakeup_state.trigger_wakeup(); 458*bb4ee6a4SAndroid Build Coastguard Worker } 459*bb4ee6a4SAndroid Build Coastguard Worker } else if let Some(clear_evt) = wakeup_state.wakeup_clear_evt.take() { 460*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = clear_evt.signal() { 461*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to signal clear event {}", e); 462*bb4ee6a4SAndroid Build Coastguard Worker } 463*bb4ee6a4SAndroid Build Coastguard Worker } 464*bb4ee6a4SAndroid Build Coastguard Worker } 465*bb4ee6a4SAndroid Build Coastguard Worker } 466