Skip to content

Commit 7263cd9

Browse files
committed
Add generic heplers to manage MSI interrupts
Introduce generic mechanism to support message signalled interrupts based on KVM hypervisor. Signed-off-by: Liu Jiang <[email protected]> Signed-off-by: Bin Zha <[email protected]>
1 parent 01cc5fa commit 7263cd9

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ vmm-sys-util = "~0"
1616
legacy-irq = []
1717
msi-irq = []
1818
kvm-irq = ["kvm-ioctls", "kvm-bindings"]
19+
kvm-msi-generic = ["msi-irq", "kvm-irq"]
1920
kvm-legacy-irq = ["legacy-irq", "kvm-irq"]

src/interrupt/kvm/mod.rs

+45
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ use super::*;
2020
mod legacy_irq;
2121
#[cfg(feature = "kvm-legacy-irq")]
2222
use self::legacy_irq::LegacyIrq;
23+
#[cfg(feature = "kvm-msi-generic")]
24+
mod msi_generic;
25+
26+
/// Maximum number of global interrupt sources.
27+
pub const MAX_IRQS: InterruptIndex = 1024;
2328

2429
/// Structure to manage interrupt sources for a virtual machine based on the Linux KVM framework.
2530
///
@@ -178,6 +183,46 @@ impl KvmIrqRouting {
178183
}
179184
}
180185

186+
#[cfg(feature = "kvm-msi-generic")]
187+
impl KvmIrqRouting {
188+
pub(super) fn add(&self, entries: &[kvm_irq_routing_entry]) -> Result<()> {
189+
// Safe to unwrap because there's no legal way to break the mutex.
190+
let mut routes = self.routes.lock().unwrap();
191+
for entry in entries {
192+
if entry.gsi >= MAX_IRQS {
193+
return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
194+
} else if routes.contains_key(&hash_key(entry)) {
195+
return Err(std::io::Error::from_raw_os_error(libc::EEXIST));
196+
}
197+
}
198+
199+
for entry in entries {
200+
let _ = routes.insert(hash_key(entry), *entry);
201+
}
202+
self.set_routing(&routes)
203+
}
204+
205+
pub(super) fn remove(&self, entries: &[kvm_irq_routing_entry]) -> Result<()> {
206+
// Safe to unwrap because there's no legal way to break the mutex.
207+
let mut routes = self.routes.lock().unwrap();
208+
for entry in entries {
209+
let _ = routes.remove(&hash_key(entry));
210+
}
211+
self.set_routing(&routes)
212+
}
213+
214+
pub(super) fn modify(&self, entry: &kvm_irq_routing_entry) -> Result<()> {
215+
// Safe to unwrap because there's no legal way to break the mutex.
216+
let mut routes = self.routes.lock().unwrap();
217+
if !routes.contains_key(&hash_key(entry)) {
218+
return Err(std::io::Error::from_raw_os_error(libc::ENOENT));
219+
}
220+
221+
let _ = routes.insert(hash_key(entry), *entry);
222+
self.set_routing(&routes)
223+
}
224+
}
225+
181226
/// Helper function convert from vmm_sys_util::errno::Error to std::io::Error.
182227
pub fn from_sys_util_errno(e: vmm_sys_util::errno::Error) -> std::io::Error {
183228
std::io::Error::from_raw_os_error(e.errno())

src/interrupt/kvm/msi_generic.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (C) 2019 Alibaba Cloud. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Helper utilities for handling MSI interrupts.
5+
6+
use kvm_bindings::{kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
7+
8+
use super::*;
9+
10+
pub(super) struct MsiConfig {
11+
pub(super) irqfd: EventFd,
12+
pub(super) config: Mutex<MsiIrqSourceConfig>,
13+
}
14+
15+
impl MsiConfig {
16+
pub(super) fn new() -> Self {
17+
MsiConfig {
18+
irqfd: EventFd::new(0).unwrap(),
19+
config: Mutex::new(Default::default()),
20+
}
21+
}
22+
}
23+
24+
pub(super) fn new_msi_routing_entry(
25+
gsi: InterruptIndex,
26+
msicfg: &MsiIrqSourceConfig,
27+
) -> kvm_irq_routing_entry {
28+
let mut entry = kvm_irq_routing_entry {
29+
gsi,
30+
type_: KVM_IRQ_ROUTING_MSI,
31+
flags: 0,
32+
..Default::default()
33+
};
34+
entry.u.msi.address_hi = msicfg.high_addr;
35+
entry.u.msi.address_lo = msicfg.low_addr;
36+
entry.u.msi.data = msicfg.data;
37+
entry
38+
}
39+
40+
#[allow(irrefutable_let_patterns)]
41+
pub(super) fn create_msi_routing_entries(
42+
base: InterruptIndex,
43+
configs: &[InterruptSourceConfig],
44+
) -> Result<Vec<kvm_irq_routing_entry>> {
45+
let _ = base
46+
.checked_add(configs.len() as u32)
47+
.ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
48+
let mut entries = Vec::with_capacity(configs.len());
49+
for (i, ref val) in configs.iter().enumerate() {
50+
if let InterruptSourceConfig::MsiIrq(msicfg) = val {
51+
let entry = new_msi_routing_entry(base + i as u32, msicfg);
52+
entries.push(entry);
53+
} else {
54+
return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
55+
}
56+
}
57+
Ok(entries)
58+
}

0 commit comments

Comments
 (0)