Skip to content

Commit bd3a25b

Browse files
committed
fix(msi): allocate GSI for MSI and legacy IRQ from different ranges
Currently, we're limited to 24 GSI lines, which is too little for PCI devices. Keep the current ranges as "legacy IRQ", and create a new range for "GSI" that goes up to the kvm theoretical maximum of 4096 lines. Signed-off-by: Riccardo Mancini <[email protected]>
1 parent 52a9252 commit bd3a25b

File tree

11 files changed

+165
-75
lines changed

11 files changed

+165
-75
lines changed

src/vmm/src/arch/aarch64/gic/gicv2/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ impl GICv2 {
135135
// On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020).
136136
// SPIs are used to signal interrupts from various peripherals accessible across
137137
// the whole system so these are the ones that we increment when adding a new virtio device.
138-
// KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the highest SPI number. Consequently, we will have a
139-
// total of `super::layout::IRQ_MAX - 32` usable SPIs in our microVM.
140-
let nr_irqs: u32 = super::layout::IRQ_MAX;
138+
// KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the number of interrupts (SGI, PPI, and SPI).
139+
// Consequently, we need to add 32 to the number of SPIs ("IRQ").
140+
let nr_irqs: u32 = crate::arch::NR_IRQ + crate::layout::SPI_BASE;
141141
let nr_irqs_ptr = &nr_irqs as *const u32;
142142
Self::set_device_attribute(
143143
gic_device.device_fd(),

src/vmm/src/arch/aarch64/gic/gicv2/regs/dist_regs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use kvm_ioctls::DeviceFd;
88

99
use crate::arch::aarch64::gic::GicError;
1010
use crate::arch::aarch64::gic::regs::{GicRegState, MmioReg, SimpleReg, VgicRegEngine};
11-
use crate::arch::{IRQ_BASE, IRQ_MAX};
11+
use crate::arch::{NR_IRQ, SPI_BASE};
1212

1313
// Distributor registers as detailed at page 75 from
1414
// https://developer.arm.com/documentation/ihi0048/latest/.
@@ -62,9 +62,9 @@ impl MmioReg for SharedIrqReg {
6262
// read-as-zero/write-ignore (RAZ/WI) policy.
6363
// The first part of a shared-irq register, the one corresponding to the
6464
// SGI and PPI IRQs (0-32) is RAZ/WI, so we skip it.
65-
let start = self.offset + u64::from(IRQ_BASE) * u64::from(self.bits_per_irq) / 8;
65+
let start = self.offset + u64::from(SPI_BASE) * u64::from(self.bits_per_irq) / 8;
6666

67-
let size_in_bits = u64::from(self.bits_per_irq) * u64::from(IRQ_MAX - IRQ_BASE);
67+
let size_in_bits = u64::from(self.bits_per_irq) * u64::from(NR_IRQ);
6868
let mut size_in_bytes = size_in_bits / 8;
6969
if size_in_bits % 8 > 0 {
7070
size_in_bytes += 1;

src/vmm/src/arch/aarch64/gic/gicv3/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ impl GICv3 {
184184
// On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020).
185185
// SPIs are used to signal interrupts from various peripherals accessible across
186186
// the whole system so these are the ones that we increment when adding a new virtio device.
187-
// KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the highest SPI number. Consequently, we will have a
188-
// total of `super::layout::IRQ_MAX - 32` usable SPIs in our microVM.
189-
let nr_irqs: u32 = super::layout::IRQ_MAX;
187+
// KVM_DEV_ARM_VGIC_GRP_NR_IRQS sets the number of interrupts (SGI, PPI, and SPI).
188+
// Consequently, we need to add 32 to the number of SPIs ("IRQ").
189+
let nr_irqs: u32 = crate::arch::NR_IRQ + crate::layout::SPI_BASE;
190190
let nr_irqs_ptr = &nr_irqs as *const u32;
191191
Self::set_device_attribute(
192192
gic_device.device_fd(),

src/vmm/src/arch/aarch64/gic/gicv3/regs/dist_regs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use kvm_ioctls::DeviceFd;
88

99
use crate::arch::aarch64::gic::GicError;
1010
use crate::arch::aarch64::gic::regs::{GicRegState, MmioReg, SimpleReg, VgicRegEngine};
11-
use crate::arch::{IRQ_BASE, IRQ_MAX};
11+
use crate::arch::{NR_IRQ, SPI_BASE};
1212

1313
// Distributor registers as detailed at page 456 from
1414
// https://static.docs.arm.com/ihi0069/c/IHI0069C_gic_architecture_specification.pdf.
@@ -64,9 +64,9 @@ impl MmioReg for SharedIrqReg {
6464
// read-as-zero/write-ignore (RAZ/WI) policy.
6565
// The first part of a shared-irq register, the one corresponding to the
6666
// SGI and PPI IRQs (0-32) is RAZ/WI, so we skip it.
67-
let start = self.offset + u64::from(IRQ_BASE) * u64::from(self.bits_per_irq) / 8;
67+
let start = self.offset + u64::from(SPI_BASE) * u64::from(self.bits_per_irq) / 8;
6868

69-
let size_in_bits = u64::from(self.bits_per_irq) * u64::from(IRQ_MAX - IRQ_BASE);
69+
let size_in_bits = u64::from(self.bits_per_irq) * u64::from(NR_IRQ);
7070
let mut size_in_bytes = size_in_bits / 8;
7171
if size_in_bits % 8 > 0 {
7272
size_in_bytes += 1;

src/vmm/src/arch/aarch64/layout.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,19 @@ pub const FDT_MAX_SIZE: usize = 0x20_0000;
7676
// * bigger than 32
7777
// * less than 1023 and
7878
// * a multiple of 32.
79-
/// The highest usable SPI on aarch64.
80-
pub const IRQ_MAX: u32 = 128;
81-
82-
/// First usable interrupt on aarch64.
83-
pub const IRQ_BASE: u32 = 32;
84-
85-
// The Linux kernel automatically shifts the GSI by 32 if it is an SPI,
86-
// allowing us to start numbering from 0 instead of 32.
87-
/// The first usable GSI on aarch64.
88-
pub const GSI_BASE: u32 = 0;
89-
90-
/// The maximum usable GSI on aarch64.
91-
pub const GSI_MAX: u32 = IRQ_MAX - IRQ_BASE - 1;
79+
// The first 32 SPIs are reserved, but KVM already shifts the gsi we
80+
// pass, so we go from 0 to 95 for legacy gsis ("irq") and the remaining
81+
// we use for MSI.
82+
/// Offset of first legacy SPI in the GIC
83+
pub const SPI_BASE: u32 = 32;
84+
/// First usable interrupt on aarch64 (corresponds to SPI #32)
85+
pub const IRQ_BASE: u32 = 0;
86+
/// The highest usable SPI on aarch64 is 127 - 32 = 95
87+
pub const IRQ_MAX: u32 = 95;
88+
/// First GSI after legacy interrupts which will be used by MSI
89+
pub const GSI_BASE: u32 = IRQ_MAX + 1;
90+
/// The highest available GSI in KVM (KVM_MAX_IRQ_ROUTES=4096)
91+
pub const GSI_MAX: u32 = 4095;
9292

9393
/// The start of the memory area reserved for MMIO 32-bit accesses.
9494
/// Below this address will reside the GIC, above this address will reside the MMIO devices.

src/vmm/src/arch/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub use aarch64::{
2727
layout::MEM_64BIT_DEVICES_START, layout::MMIO32_MEM_SIZE, layout::MMIO32_MEM_START,
2828
layout::PCI_MMCONFIG_SIZE, layout::PCI_MMCONFIG_START,
2929
layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT, layout::RTC_MEM_START, layout::SERIAL_MEM_START,
30-
layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START, load_kernel,
30+
layout::SPI_BASE, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START, load_kernel,
3131
};
3232

3333
/// Module for x86_64 related functionality.
@@ -53,6 +53,11 @@ pub use crate::arch::x86_64::{
5353
load_kernel,
5454
};
5555

56+
/// Total count of legacy interrupt lines available (IRQs)
57+
pub const NR_IRQ: u32 = IRQ_MAX - IRQ_BASE + 1;
58+
/// Total count of MSI GSIs available
59+
pub const NR_GSI: u32 = GSI_MAX - GSI_BASE + 1;
60+
5661
/// Types of devices that can get attached to this platform.
5762
#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy, Serialize, Deserialize)]
5863
pub enum DeviceType {

src/vmm/src/arch/x86_64/layout.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ pub const CMDLINE_MAX_SIZE: usize = 2048;
2121
/// Start of the high memory.
2222
pub const HIMEM_START: u64 = 0x0010_0000; // 1 MB.
2323

24-
// Typically, on x86 systems 24 IRQs are used (0-23).
24+
// Typically, on x86 systems 24 IRQs are used for legacy devices (0-23).
25+
// However, the first 5 are reserved.
26+
// We allocate the remaining GSIs to MSIs.
2527
/// First usable IRQ ID for virtio device interrupts on x86_64.
2628
pub const IRQ_BASE: u32 = 5;
2729
/// Last usable IRQ ID for virtio device interrupts on x86_64.
2830
pub const IRQ_MAX: u32 = 23;
29-
30-
/// The first usable GSI on x86_64 is the same as the first usable IRQ ID.
31-
pub const GSI_BASE: u32 = IRQ_BASE;
32-
33-
/// The maximum usable GSI on x86_64 is the same as the last usable IRQ ID.
34-
pub const GSI_MAX: u32 = IRQ_MAX;
31+
/// First GSI after legacy interrupts which will be used by MSI
32+
pub const GSI_BASE: u32 = IRQ_MAX + 1;
33+
/// The highest available GSI in KVM (KVM_MAX_IRQ_ROUTES=4096)
34+
pub const GSI_MAX: u32 = 4095;
3535

3636
/// Address for the TSS setup.
3737
pub const KVM_TSS_ADDRESS: u64 = 0xfffb_d000;

src/vmm/src/device_manager/mmio.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ fn add_virtio_aml(
8484
len: u64,
8585
irq: u32,
8686
) -> Result<(), aml::AmlError> {
87-
let dev_id = irq - crate::arch::GSI_BASE;
87+
let dev_id = irq - crate::arch::IRQ_BASE;
8888
debug!(
8989
"acpi: Building AML for VirtIO device _SB_.V{:03}. memory range: {:#010x}:{} irq: {}",
9090
dev_id, addr, len, irq
@@ -156,7 +156,7 @@ impl MMIODeviceManager {
156156
resource_allocator: &mut ResourceAllocator,
157157
irq_count: u32,
158158
) -> Result<MMIODeviceInfo, MmioError> {
159-
let irq = match resource_allocator.allocate_gsi(irq_count)?[..] {
159+
let irq = match resource_allocator.allocate_irq(irq_count)?[..] {
160160
[] => None,
161161
[irq] => Some(irq),
162162
_ => return Err(MmioError::InvalidIrqConfig),
@@ -276,11 +276,11 @@ impl MMIODeviceManager {
276276
let device_info = if let Some(device_info) = device_info_opt {
277277
device_info
278278
} else {
279-
let gsi = vm.resource_allocator().allocate_gsi(1)?;
279+
let irq = vm.resource_allocator().allocate_irq(1)?;
280280
MMIODeviceInfo {
281281
addr: SERIAL_MEM_START,
282282
len: MMIO_LEN,
283-
irq: Some(gsi[0]),
283+
irq: Some(irq[0]),
284284
}
285285
};
286286

@@ -335,11 +335,11 @@ impl MMIODeviceManager {
335335
let device_info = if let Some(device_info) = device_info_opt {
336336
device_info
337337
} else {
338-
let gsi = vm.resource_allocator().allocate_gsi(1)?;
338+
let irq = vm.resource_allocator().allocate_irq(1)?;
339339
MMIODeviceInfo {
340340
addr: RTC_MEM_START,
341341
len: MMIO_LEN,
342-
irq: Some(gsi[0]),
342+
irq: Some(irq[0]),
343343
}
344344
};
345345

@@ -612,15 +612,15 @@ pub(crate) mod tests {
612612
let dev = device_manager.get_virtio_device(0, "dummy").unwrap();
613613
assert_eq!(dev.resources.addr, arch::MEM_32BIT_DEVICES_START);
614614
assert_eq!(dev.resources.len, MMIO_LEN);
615-
assert_eq!(dev.resources.irq, Some(arch::GSI_BASE));
615+
assert_eq!(dev.resources.irq, Some(arch::IRQ_BASE));
616616

617617
device_manager
618618
.for_each_virtio_device(|virtio_type, device_id, mmio_device| {
619619
assert_eq!(*virtio_type, 0);
620620
assert_eq!(device_id, "dummy");
621621
assert_eq!(mmio_device.resources.addr, arch::MEM_32BIT_DEVICES_START);
622622
assert_eq!(mmio_device.resources.len, MMIO_LEN);
623-
assert_eq!(mmio_device.resources.irq, Some(arch::GSI_BASE));
623+
assert_eq!(mmio_device.resources.irq, Some(arch::IRQ_BASE));
624624
Ok::<(), ()>(())
625625
})
626626
.unwrap();
@@ -643,7 +643,7 @@ pub(crate) mod tests {
643643
#[cfg(target_arch = "aarch64")]
644644
vm.setup_irqchip(1).unwrap();
645645

646-
for _i in crate::arch::GSI_BASE..=crate::arch::GSI_MAX {
646+
for _i in crate::arch::IRQ_BASE..=crate::arch::IRQ_MAX {
647647
device_manager
648648
.register_virtio_test_device(
649649
&vm,
@@ -711,7 +711,7 @@ pub(crate) mod tests {
711711
.addr
712712
);
713713
assert_eq!(
714-
crate::arch::GSI_BASE,
714+
crate::arch::IRQ_BASE,
715715
device_manager.virtio_devices[&(type_id, id)]
716716
.resources
717717
.irq
@@ -762,7 +762,7 @@ pub(crate) mod tests {
762762
let device_info = device_manager
763763
.allocate_mmio_resources(&mut resource_allocator, 1)
764764
.unwrap();
765-
assert_eq!(device_info.irq.unwrap(), crate::arch::GSI_BASE);
765+
assert_eq!(device_info.irq.unwrap(), crate::arch::IRQ_BASE);
766766
}
767767

768768
#[test]

src/vmm/src/devices/acpi/vmgenid.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@ impl VmGenId {
8888
mem: &GuestMemoryMmap,
8989
resource_allocator: &mut ResourceAllocator,
9090
) -> Result<Self, VmGenIdError> {
91-
let gsi = resource_allocator.allocate_gsi(1)?;
91+
let irq = resource_allocator.allocate_irq(1)?;
9292
// The generation ID needs to live in an 8-byte aligned buffer
9393
let addr = resource_allocator.allocate_system_memory(
9494
VMGENID_MEM_SIZE,
9595
8,
9696
vm_allocator::AllocPolicy::LastMatch,
9797
)?;
9898

99-
Self::from_parts(GuestAddress(addr), gsi[0], mem)
99+
Self::from_parts(GuestAddress(addr), irq[0], mem)
100100
}
101101

102102
// Create a 16-bytes random number

0 commit comments

Comments
 (0)