xref: /cloud-hypervisor/vm-allocator/src/gsi.rs (revision 21f05ebb4fb0ddf1f148d9b5329c9259297ed3c7)
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
27     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
43     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
67     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
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
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
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 {
111     fn default() -> Self {
112         GsiAllocator::new()
113     }
114 }
115