mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-26 15:45:19 +00:00
0a04a950a1
GSI (Global System Interrupt) is an extension of just a linear array of IRQs. It takes IOAPICs into account for example. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
85 lines
1.8 KiB
Rust
85 lines
1.8 KiB
Rust
// Copyright © 2019 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
|
|
|
use std::collections::btree_map::BTreeMap;
|
|
use std::result;
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
Overflow,
|
|
}
|
|
|
|
pub type Result<T> = result::Result<T, Error>;
|
|
|
|
/// GsiApic
|
|
#[derive(Copy, Clone)]
|
|
pub struct GsiApic {
|
|
base: u32,
|
|
irqs: u32,
|
|
}
|
|
|
|
impl GsiApic {
|
|
/// New GSI APIC
|
|
pub fn new(base: u32, irqs: u32) -> Self {
|
|
GsiApic { base, irqs }
|
|
}
|
|
}
|
|
|
|
/// GsiAllocator
|
|
pub struct GsiAllocator {
|
|
apics: BTreeMap<u32, u32>,
|
|
next_irq: u32,
|
|
next_gsi: u32,
|
|
}
|
|
|
|
impl GsiAllocator {
|
|
/// New GSI allocator
|
|
pub fn new(apics: Vec<GsiApic>) -> Self {
|
|
let mut allocator = GsiAllocator {
|
|
apics: BTreeMap::new(),
|
|
next_irq: 0xffff_ffff,
|
|
next_gsi: 0,
|
|
};
|
|
|
|
for apic in &apics {
|
|
if apic.base < allocator.next_irq {
|
|
allocator.next_irq = apic.base;
|
|
}
|
|
|
|
if apic.base + apic.irqs > allocator.next_gsi {
|
|
allocator.next_gsi = apic.base + apic.irqs;
|
|
}
|
|
|
|
allocator.apics.insert(apic.base, apic.irqs);
|
|
}
|
|
|
|
allocator
|
|
}
|
|
|
|
/// Allocate a GSI
|
|
pub fn allocate_gsi(&mut self) -> Result<u32> {
|
|
self.next_gsi = self.next_gsi.checked_add(1).ok_or(Error::Overflow)?;
|
|
|
|
Ok(self.next_gsi - 1)
|
|
}
|
|
|
|
/// Allocate an IRQ
|
|
pub fn allocate_irq(&mut self) -> Result<u32> {
|
|
let mut irq: u32 = 0;
|
|
for (base, irqs) in self.apics.iter() {
|
|
// HACKHACK - This only works with 1 single IOAPIC...
|
|
if self.next_irq >= *base && self.next_irq < *base + *irqs {
|
|
irq = self.next_irq;
|
|
self.next_irq += 1;
|
|
}
|
|
}
|
|
|
|
if irq == 0 {
|
|
return Err(Error::Overflow);
|
|
}
|
|
|
|
Ok(irq)
|
|
}
|
|
}
|