// 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 = result::Result; /// 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, next_irq: u32, next_gsi: u32, } impl GsiAllocator { /// New GSI allocator pub fn new(apics: Vec) -> 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 { 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 { 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) } }