10a04a950SSamuel Ortiz // Copyright © 2019 Intel Corporation 20a04a950SSamuel Ortiz // 30a04a950SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 40a04a950SSamuel Ortiz 5e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 60a04a950SSamuel Ortiz use std::collections::btree_map::BTreeMap; 70a04a950SSamuel Ortiz use std::result; 80a04a950SSamuel Ortiz 90a04a950SSamuel Ortiz #[derive(Debug)] 100a04a950SSamuel Ortiz pub enum Error { 110a04a950SSamuel Ortiz Overflow, 120a04a950SSamuel Ortiz } 130a04a950SSamuel Ortiz 140a04a950SSamuel Ortiz pub type Result<T> = result::Result<T, Error>; 150a04a950SSamuel Ortiz 160a04a950SSamuel Ortiz /// GsiApic 17e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 180a04a950SSamuel Ortiz #[derive(Copy, Clone)] 190a04a950SSamuel Ortiz pub struct GsiApic { 200a04a950SSamuel Ortiz base: u32, 210a04a950SSamuel Ortiz irqs: u32, 220a04a950SSamuel Ortiz } 230a04a950SSamuel Ortiz 24e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 250a04a950SSamuel Ortiz impl GsiApic { 260a04a950SSamuel Ortiz /// New GSI APIC new(base: u32, irqs: u32) -> Self270a04a950SSamuel Ortiz pub fn new(base: u32, irqs: u32) -> Self { 280a04a950SSamuel Ortiz GsiApic { base, irqs } 290a04a950SSamuel Ortiz } 300a04a950SSamuel Ortiz } 310a04a950SSamuel Ortiz 320a04a950SSamuel Ortiz /// GsiAllocator 330a04a950SSamuel Ortiz pub struct GsiAllocator { 34e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 350a04a950SSamuel Ortiz apics: BTreeMap<u32, u32>, 360a04a950SSamuel Ortiz next_irq: u32, 370a04a950SSamuel Ortiz next_gsi: u32, 380a04a950SSamuel Ortiz } 390a04a950SSamuel Ortiz 400a04a950SSamuel Ortiz impl GsiAllocator { 41e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 420a04a950SSamuel Ortiz /// New GSI allocator new(apics: Vec<GsiApic>) -> Self430a04a950SSamuel Ortiz pub fn new(apics: Vec<GsiApic>) -> Self { 440a04a950SSamuel Ortiz let mut allocator = GsiAllocator { 450a04a950SSamuel Ortiz apics: BTreeMap::new(), 460a04a950SSamuel Ortiz next_irq: 0xffff_ffff, 470a04a950SSamuel Ortiz next_gsi: 0, 480a04a950SSamuel Ortiz }; 490a04a950SSamuel Ortiz 500a04a950SSamuel Ortiz for apic in &apics { 510a04a950SSamuel Ortiz if apic.base < allocator.next_irq { 520a04a950SSamuel Ortiz allocator.next_irq = apic.base; 530a04a950SSamuel Ortiz } 540a04a950SSamuel Ortiz 550a04a950SSamuel Ortiz if apic.base + apic.irqs > allocator.next_gsi { 560a04a950SSamuel Ortiz allocator.next_gsi = apic.base + apic.irqs; 570a04a950SSamuel Ortiz } 580a04a950SSamuel Ortiz 590a04a950SSamuel Ortiz allocator.apics.insert(apic.base, apic.irqs); 600a04a950SSamuel Ortiz } 610a04a950SSamuel Ortiz 620a04a950SSamuel Ortiz allocator 630a04a950SSamuel Ortiz } 640a04a950SSamuel Ortiz 65*5b715f48SRuoqing He #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 66e9488846SMichael Zhao /// New GSI allocator new() -> Self67e9488846SMichael Zhao pub fn new() -> Self { 68e9488846SMichael Zhao GsiAllocator { 69e9488846SMichael Zhao next_irq: arch::IRQ_BASE, 70e9488846SMichael Zhao next_gsi: arch::IRQ_BASE, 71e9488846SMichael Zhao } 720a04a950SSamuel Ortiz } 730a04a950SSamuel Ortiz 74e9488846SMichael Zhao /// Allocate a GSI allocate_gsi(&mut self) -> Result<u32>75e9488846SMichael Zhao pub fn allocate_gsi(&mut self) -> Result<u32> { 76e9488846SMichael Zhao let gsi = self.next_gsi; 77e9488846SMichael Zhao self.next_gsi = self.next_gsi.checked_add(1).ok_or(Error::Overflow)?; 78e9488846SMichael Zhao Ok(gsi) 79e9488846SMichael Zhao } 80e9488846SMichael Zhao 81e9488846SMichael Zhao #[cfg(target_arch = "x86_64")] 820a04a950SSamuel Ortiz /// Allocate an IRQ allocate_irq(&mut self) -> Result<u32>830a04a950SSamuel Ortiz pub fn allocate_irq(&mut self) -> Result<u32> { 840a04a950SSamuel Ortiz let mut irq: u32 = 0; 850a04a950SSamuel Ortiz for (base, irqs) in self.apics.iter() { 860a04a950SSamuel Ortiz // HACKHACK - This only works with 1 single IOAPIC... 870a04a950SSamuel Ortiz if self.next_irq >= *base && self.next_irq < *base + *irqs { 880a04a950SSamuel Ortiz irq = self.next_irq; 890a04a950SSamuel Ortiz self.next_irq += 1; 900a04a950SSamuel Ortiz } 910a04a950SSamuel Ortiz } 920a04a950SSamuel Ortiz 930a04a950SSamuel Ortiz if irq == 0 { 940a04a950SSamuel Ortiz return Err(Error::Overflow); 950a04a950SSamuel Ortiz } 960a04a950SSamuel Ortiz 970a04a950SSamuel Ortiz Ok(irq) 980a04a950SSamuel Ortiz } 99e9488846SMichael Zhao 100*5b715f48SRuoqing He #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 101e9488846SMichael Zhao /// Allocate an IRQ allocate_irq(&mut self) -> Result<u32>102e9488846SMichael Zhao pub fn allocate_irq(&mut self) -> Result<u32> { 103e9488846SMichael Zhao let irq = self.next_irq; 104e9488846SMichael Zhao self.next_irq = self.next_irq.checked_add(1).ok_or(Error::Overflow)?; 105e9488846SMichael Zhao Ok(irq) 106e9488846SMichael Zhao } 1070a04a950SSamuel Ortiz } 10899a98f27SRavi kumar Veeramally 109*5b715f48SRuoqing He #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 11099a98f27SRavi kumar Veeramally impl Default for GsiAllocator { default() -> Self11199a98f27SRavi kumar Veeramally fn default() -> Self { 11299a98f27SRavi kumar Veeramally GsiAllocator::new() 11399a98f27SRavi kumar Veeramally } 11499a98f27SRavi kumar Veeramally } 115