• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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