• 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::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