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::irq_event::IrqLevelEvent; 7 use crate::pci::MsixConfig; 8 use base::Event; 9 use std::cell::RefCell; 10 use std::rc::Rc; 11 use std::sync::atomic::{AtomicUsize, Ordering}; 12 use std::sync::Arc; 13 use sync::Mutex; 14 15 pub trait SignalableInterrupt { 16 /// Writes to the irqfd to VMM to deliver virtual interrupt to the guest. signal(&self, vector: u16, interrupt_status_mask: u32)17 fn signal(&self, vector: u16, interrupt_status_mask: u32); 18 19 /// Notify the driver that buffers have been placed in the used queue. signal_used_queue(&self, vector: u16)20 fn signal_used_queue(&self, vector: u16) { 21 self.signal(vector, INTERRUPT_STATUS_USED_RING) 22 } 23 24 /// Notify the driver that the device configuration has changed. signal_config_changed(&self)25 fn signal_config_changed(&self); 26 27 /// Get the event to signal resampling is needed if it exists. get_resample_evt(&self) -> Option<&Event>28 fn get_resample_evt(&self) -> Option<&Event>; 29 30 /// Reads the status and writes to the interrupt event. Doesn't read the resample event, it 31 /// assumes the resample has been requested. do_interrupt_resample(&self)32 fn do_interrupt_resample(&self); 33 } 34 35 pub struct Interrupt { 36 interrupt_status: Arc<AtomicUsize>, 37 interrupt_evt: IrqLevelEvent, 38 msix_config: Option<Arc<Mutex<MsixConfig>>>, 39 config_msix_vector: u16, 40 } 41 42 impl SignalableInterrupt for Interrupt { 43 /// Virtqueue Interrupts From The Device 44 /// 45 /// If MSI-X is enabled in this device, MSI-X interrupt is preferred. 46 /// Write to the irqfd to VMM to deliver virtual interrupt to the guest signal(&self, vector: u16, interrupt_status_mask: u32)47 fn signal(&self, vector: u16, interrupt_status_mask: u32) { 48 // Don't need to set ISR for MSI-X interrupts 49 if let Some(msix_config) = &self.msix_config { 50 let mut msix_config = msix_config.lock(); 51 if msix_config.enabled() { 52 if vector != VIRTIO_MSI_NO_VECTOR { 53 msix_config.trigger(vector); 54 } 55 return; 56 } 57 } 58 59 // Set bit in ISR and inject the interrupt if it was not already pending. 60 // Don't need to inject the interrupt if the guest hasn't processed it. 61 if self 62 .interrupt_status 63 .fetch_or(interrupt_status_mask as usize, Ordering::SeqCst) 64 == 0 65 { 66 // Write to irqfd to inject INTx interrupt 67 self.interrupt_evt.trigger().unwrap(); 68 } 69 } 70 signal_config_changed(&self)71 fn signal_config_changed(&self) { 72 self.signal(self.config_msix_vector, INTERRUPT_STATUS_CONFIG_CHANGED) 73 } 74 get_resample_evt(&self) -> Option<&Event>75 fn get_resample_evt(&self) -> Option<&Event> { 76 Some(self.interrupt_evt.get_resample()) 77 } 78 do_interrupt_resample(&self)79 fn do_interrupt_resample(&self) { 80 if self.interrupt_status.load(Ordering::SeqCst) != 0 { 81 self.interrupt_evt.trigger().unwrap(); 82 } 83 } 84 } 85 86 impl<I: SignalableInterrupt> SignalableInterrupt for Arc<Mutex<I>> { signal(&self, vector: u16, interrupt_status_mask: u32)87 fn signal(&self, vector: u16, interrupt_status_mask: u32) { 88 self.lock().signal(vector, interrupt_status_mask); 89 } 90 signal_used_queue(&self, vector: u16)91 fn signal_used_queue(&self, vector: u16) { 92 self.lock().signal_used_queue(vector); 93 } 94 signal_config_changed(&self)95 fn signal_config_changed(&self) { 96 self.lock().signal_config_changed(); 97 } 98 get_resample_evt(&self) -> Option<&Event>99 fn get_resample_evt(&self) -> Option<&Event> { 100 // Cannot get resample event from a borrowed item. 101 None 102 } 103 do_interrupt_resample(&self)104 fn do_interrupt_resample(&self) {} 105 } 106 107 impl<I: SignalableInterrupt> SignalableInterrupt for Rc<RefCell<I>> { signal(&self, vector: u16, interrupt_status_mask: u32)108 fn signal(&self, vector: u16, interrupt_status_mask: u32) { 109 self.borrow().signal(vector, interrupt_status_mask); 110 } 111 signal_used_queue(&self, vector: u16)112 fn signal_used_queue(&self, vector: u16) { 113 self.borrow().signal_used_queue(vector); 114 } 115 signal_config_changed(&self)116 fn signal_config_changed(&self) { 117 self.borrow().signal_config_changed(); 118 } 119 get_resample_evt(&self) -> Option<&Event>120 fn get_resample_evt(&self) -> Option<&Event> { 121 // Cannot get resample event from a borrowed item. 122 None 123 } 124 do_interrupt_resample(&self)125 fn do_interrupt_resample(&self) {} 126 } 127 128 impl Interrupt { new( interrupt_status: Arc<AtomicUsize>, interrupt_evt: IrqLevelEvent, msix_config: Option<Arc<Mutex<MsixConfig>>>, config_msix_vector: u16, ) -> Interrupt129 pub fn new( 130 interrupt_status: Arc<AtomicUsize>, 131 interrupt_evt: IrqLevelEvent, 132 msix_config: Option<Arc<Mutex<MsixConfig>>>, 133 config_msix_vector: u16, 134 ) -> Interrupt { 135 Interrupt { 136 interrupt_status, 137 interrupt_evt, 138 msix_config, 139 config_msix_vector, 140 } 141 } 142 143 /// Get a reference to the interrupt event. get_interrupt_evt(&self) -> &Event144 pub fn get_interrupt_evt(&self) -> &Event { 145 self.interrupt_evt.get_trigger() 146 } 147 148 /// Handle interrupt resampling event, reading the value from the event and doing the resample. interrupt_resample(&self)149 pub fn interrupt_resample(&self) { 150 self.interrupt_evt.clear_resample(); 151 self.do_interrupt_resample(); 152 } 153 154 /// Get a reference to the msix configuration get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>>155 pub fn get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>> { 156 &self.msix_config 157 } 158 } 159