xref: /cloud-hypervisor/vm-allocator/src/gsi.rs (revision 5b715f483d8912e2c4c3ae20492798220cef9773)
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