1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Traits for working with MSI interrupts.
use parking_lot::Mutex;
use std::sync::Arc;
use std::sync::Weak;
use vmcore::interrupt::Interrupt;
/// Trait implemented by targets capable of receiving MSI interrupts.
pub trait MsiInterruptTarget: Send + Sync {
/// Creates a new interrupt object.
fn new_interrupt(&self) -> Box<dyn MsiControl>;
}
/// Trait modelling an individual MSI interrupt.
pub trait MsiControl: Send {
/// Enables the interrupt, so that signaling the interrupt delivers an MSI
/// to the specified address/data pair.
fn enable(&mut self, address: u64, data: u32);
/// Disables the interrupt, allowing the backing object to release resources
/// associated with this MSI.
fn disable(&mut self);
/// Signals the interrupt.
///
/// The caller must ensure that the interrupt is enabled with the same
/// address/data pair before calling this method. The address/data is
/// provided here redundantly for the convenience of the implementation.
fn signal(&mut self, address: u64, data: u32);
// FUTURE: add mechanisms to use an OS event object for signal. This is
// necessary to support sending interrupts across processes.
//
// This is complicated by differing requirements for the different backends,
// e.g. KVM supports taking whatever eventfd you want, while WHP wants to be
// the one to provide the event object.
}
impl<T: Send + FnMut(u64, u32)> MsiControl for T {
fn enable(&mut self, _address: u64, _data: u32) {}
fn disable(&mut self) {}
fn signal(&mut self, address: u64, data: u32) {
(*self)(address, data)
}
}
/// A set of message-signaled interrupts that have yet to be connected to a
/// backing interrupt controller.
pub struct MsiInterruptSet {
interrupts: Vec<Weak<Mutex<MsiInterruptState>>>,
}
impl MsiInterruptSet {
/// Creates a new empty set of message signaled interrupts.
pub fn new() -> Self {
Self {
interrupts: Vec::new(),
}
}
/// Returns the number of interrupts in the set.
pub fn len(&self) -> usize {
self.interrupts.len()
}
/// Connects the interrupts created with `builder()` to the given target
/// interrupt controller.
pub fn connect(self, target: &dyn MsiInterruptTarget) {
for interrupt in self.interrupts.into_iter().filter_map(|i| i.upgrade()) {
let mut control = target.new_interrupt();
let mut state = interrupt.lock();
if let Some((address, data)) = state.address_data {
control.enable(address, data);
if state.pending {
control.signal(address, data);
state.pending = false;
}
}
state.control = Some(control);
}
}
}
/// Trait for registering message-signaled interrupts for a device.
pub trait RegisterMsi: Send {
/// Returns a new message-signaled interrupt for this device.
fn new_msi(&mut self) -> MsiInterrupt;
}
impl RegisterMsi for MsiInterruptSet {
fn new_msi(&mut self) -> MsiInterrupt {
let state = Arc::new(Mutex::new(MsiInterruptState {
pending: false,
address_data: None,
control: None,
}));
self.interrupts.push(Arc::downgrade(&state));
MsiInterrupt { state }
}
}
/// A message-signaled interrupt.
pub struct MsiInterrupt {
state: Arc<Mutex<MsiInterruptState>>,
}
struct MsiInterruptState {
pending: bool,
address_data: Option<(u64, u32)>,
control: Option<Box<dyn MsiControl>>,
}
impl MsiInterrupt {
/// Enables the interrupt.
///
/// If `set_pending`, or if the internal pending state is set, then delivers
/// the interrupt immediately.
pub fn enable(&mut self, address: u64, data: u32, set_pending: bool) {
let mut state = self.state.lock();
let state = &mut *state;
state.pending |= set_pending;
state.address_data = Some((address, data));
if let Some(control) = &mut state.control {
control.enable(address, data);
if state.pending {
control.signal(address, data);
state.pending = false;
}
}
}
/// Disables the interrupt.
///
/// Interrupt deliveries while the interrupt is disabled will set an
/// internal pending state.
pub fn disable(&mut self) {
let mut state = self.state.lock();
state.address_data = None;
if let Some(control) = &mut state.control {
control.disable();
}
}
/// Clears any internal pending state and returns it.
pub fn drain_pending(&mut self) -> bool {
let mut state = self.state.lock();
std::mem::take(&mut state.pending)
}
/// Returns an object that can be used to deliver the interrupt.
pub fn interrupt(&mut self) -> Interrupt {
let state = self.state.clone();
Interrupt::from_fn(move || {
let mut state = state.lock();
let state = &mut *state;
if let Some((control, (address, data))) = state.control.as_mut().zip(state.address_data)
{
control.signal(address, data);
} else {
state.pending = true;
}
})
}
}