1 // Copyright © 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 4 5 #[cfg(target_arch = "x86_64")] 6 use std::collections::btree_map::BTreeMap; 7 use std::result; 8 9 #[derive(Debug)] 10 pub enum Error { 11 Overflow, 12 } 13 14 pub type Result<T> = result::Result<T, Error>; 15 16 /// GsiApic 17 #[cfg(target_arch = "x86_64")] 18 #[derive(Copy, Clone)] 19 pub struct GsiApic { 20 base: u32, 21 irqs: u32, 22 } 23 24 #[cfg(target_arch = "x86_64")] 25 impl GsiApic { 26 /// New GSI APIC new(base: u32, irqs: u32) -> Self27 pub fn new(base: u32, irqs: u32) -> Self { 28 GsiApic { base, irqs } 29 } 30 } 31 32 /// GsiAllocator 33 pub struct GsiAllocator { 34 #[cfg(target_arch = "x86_64")] 35 apics: BTreeMap<u32, u32>, 36 next_irq: u32, 37 next_gsi: u32, 38 } 39 40 impl GsiAllocator { 41 #[cfg(target_arch = "x86_64")] 42 /// New GSI allocator new(apics: Vec<GsiApic>) -> Self43 pub fn new(apics: Vec<GsiApic>) -> Self { 44 let mut allocator = GsiAllocator { 45 apics: BTreeMap::new(), 46 next_irq: 0xffff_ffff, 47 next_gsi: 0, 48 }; 49 50 for apic in &apics { 51 if apic.base < allocator.next_irq { 52 allocator.next_irq = apic.base; 53 } 54 55 if apic.base + apic.irqs > allocator.next_gsi { 56 allocator.next_gsi = apic.base + apic.irqs; 57 } 58 59 allocator.apics.insert(apic.base, apic.irqs); 60 } 61 62 allocator 63 } 64 65 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 66 /// New GSI allocator new() -> Self67 pub fn new() -> Self { 68 GsiAllocator { 69 next_irq: arch::IRQ_BASE, 70 next_gsi: arch::IRQ_BASE, 71 } 72 } 73 74 /// Allocate a GSI allocate_gsi(&mut self) -> Result<u32>75 pub fn allocate_gsi(&mut self) -> Result<u32> { 76 let gsi = self.next_gsi; 77 self.next_gsi = self.next_gsi.checked_add(1).ok_or(Error::Overflow)?; 78 Ok(gsi) 79 } 80 81 #[cfg(target_arch = "x86_64")] 82 /// Allocate an IRQ allocate_irq(&mut self) -> Result<u32>83 pub fn allocate_irq(&mut self) -> Result<u32> { 84 let mut irq: u32 = 0; 85 for (base, irqs) in self.apics.iter() { 86 // HACKHACK - This only works with 1 single IOAPIC... 87 if self.next_irq >= *base && self.next_irq < *base + *irqs { 88 irq = self.next_irq; 89 self.next_irq += 1; 90 } 91 } 92 93 if irq == 0 { 94 return Err(Error::Overflow); 95 } 96 97 Ok(irq) 98 } 99 100 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 101 /// Allocate an IRQ allocate_irq(&mut self) -> Result<u32>102 pub fn allocate_irq(&mut self) -> Result<u32> { 103 let irq = self.next_irq; 104 self.next_irq = self.next_irq.checked_add(1).ok_or(Error::Overflow)?; 105 Ok(irq) 106 } 107 } 108 109 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 110 impl Default for GsiAllocator { default() -> Self111 fn default() -> Self { 112 GsiAllocator::new() 113 } 114 } 115