@@ -19,7 +19,9 @@ use crate::snapshot::Persist;
1919/// * Memory allocations in the MMIO address space
2020#[ derive( Debug , Clone , Serialize , Deserialize ) ]
2121pub struct ResourceAllocator {
22- /// Allocator for device interrupt lines
22+ /// Allocator for legacy device interrupt lines
23+ pub irq_allocator : IdAllocator ,
24+ /// Allocator for PCI device GSIs
2325 pub gsi_allocator : IdAllocator ,
2426 /// Allocator for memory in the 32-bit MMIO address space
2527 pub mmio32_memory : AddressAllocator ,
@@ -41,6 +43,7 @@ impl ResourceAllocator {
4143 // It is fine for us to unwrap the following since we know we are passing valid ranges for
4244 // all allocators
4345 Self {
46+ irq_allocator : IdAllocator :: new ( arch:: IRQ_BASE , arch:: IRQ_MAX ) . unwrap ( ) ,
4447 gsi_allocator : IdAllocator :: new ( arch:: GSI_BASE , arch:: GSI_MAX ) . unwrap ( ) ,
4548 mmio32_memory : AddressAllocator :: new (
4649 arch:: MEM_32BIT_DEVICES_START ,
@@ -57,6 +60,30 @@ impl ResourceAllocator {
5760 }
5861 }
5962
63+ /// Allocate a number of legacy IRQs
64+ ///
65+ /// # Arguments
66+ ///
67+ /// * `irq_count` - The number of legacy IRQs to allocate
68+ pub fn allocate_irq ( & mut self , irq_count : u32 ) -> Result < Vec < u32 > , vm_allocator:: Error > {
69+ let mut irqs = Vec :: with_capacity ( irq_count as usize ) ;
70+
71+ for _ in 0 ..irq_count {
72+ match self . irq_allocator . allocate_id ( ) {
73+ Ok ( irq) => irqs. push ( irq) ,
74+ Err ( err) => {
75+ // It is ok to unwrap here, we just allocated the GSI
76+ irqs. into_iter ( ) . for_each ( |irq| {
77+ self . irq_allocator . free_id ( irq) . unwrap ( ) ;
78+ } ) ;
79+ return Err ( err) ;
80+ }
81+ }
82+ }
83+
84+ Ok ( irqs)
85+ }
86+
6087 /// Allocate a number of GSIs
6188 ///
6289 /// # Arguments
@@ -167,10 +194,47 @@ mod tests {
167194 use vm_allocator:: AllocPolicy ;
168195
169196 use super :: ResourceAllocator ;
170- use crate :: arch:: { self , GSI_BASE } ;
197+ use crate :: arch:: { self , GSI_BASE , IRQ_BASE , NR_GSI , NR_IRQ } ;
171198 use crate :: snapshot:: { Persist , Snapshot } ;
172199
173- const MAX_IRQS : u32 = arch:: GSI_MAX - arch:: GSI_BASE + 1 ;
200+ #[ test]
201+ fn test_allocate_irq ( ) {
202+ let mut allocator = ResourceAllocator :: new ( ) ;
203+ // asking for 0 IRQs should return us an empty vector
204+ assert_eq ! ( allocator. allocate_irq( 0 ) , Ok ( vec![ ] ) ) ;
205+ // We cannot allocate more GSIs than available
206+ assert_eq ! (
207+ allocator. allocate_irq( NR_IRQ + 1 ) ,
208+ Err ( vm_allocator:: Error :: ResourceNotAvailable )
209+ ) ;
210+ // But allocating all of them at once should work
211+ assert_eq ! (
212+ allocator. allocate_irq( NR_IRQ ) ,
213+ Ok ( ( arch:: IRQ_BASE ..=arch:: IRQ_MAX ) . collect:: <Vec <_>>( ) )
214+ ) ;
215+ // And now we ran out of GSIs
216+ assert_eq ! (
217+ allocator. allocate_irq( 1 ) ,
218+ Err ( vm_allocator:: Error :: ResourceNotAvailable )
219+ ) ;
220+ // But we should be able to ask for 0 GSIs
221+ assert_eq ! ( allocator. allocate_irq( 0 ) , Ok ( vec![ ] ) ) ;
222+
223+ let mut allocator = ResourceAllocator :: new ( ) ;
224+ // We should be able to allocate 1 GSI
225+ assert_eq ! ( allocator. allocate_irq( 1 ) , Ok ( vec![ arch:: IRQ_BASE ] ) ) ;
226+ // We can't allocate MAX_IRQS any more
227+ assert_eq ! (
228+ allocator. allocate_irq( NR_IRQ ) ,
229+ Err ( vm_allocator:: Error :: ResourceNotAvailable )
230+ ) ;
231+ // We can allocate another one and it should be the second available
232+ assert_eq ! ( allocator. allocate_irq( 1 ) , Ok ( vec![ arch:: IRQ_BASE + 1 ] ) ) ;
233+ // Let's allocate the rest in a loop
234+ for i in arch:: IRQ_BASE + 2 ..=arch:: IRQ_MAX {
235+ assert_eq ! ( allocator. allocate_irq( 1 ) , Ok ( vec![ i] ) ) ;
236+ }
237+ }
174238
175239 #[ test]
176240 fn test_allocate_gsi ( ) {
@@ -179,12 +243,12 @@ mod tests {
179243 assert_eq ! ( allocator. allocate_gsi( 0 ) , Ok ( vec![ ] ) ) ;
180244 // We cannot allocate more GSIs than available
181245 assert_eq ! (
182- allocator. allocate_gsi( MAX_IRQS + 1 ) ,
246+ allocator. allocate_gsi( NR_GSI ) ,
183247 Err ( vm_allocator:: Error :: ResourceNotAvailable )
184248 ) ;
185249 // But allocating all of them at once should work
186250 assert_eq ! (
187- allocator. allocate_gsi( MAX_IRQS ) ,
251+ allocator. allocate_gsi( NR_GSI ) ,
188252 Ok ( ( arch:: GSI_BASE ..=arch:: GSI_MAX ) . collect:: <Vec <_>>( ) )
189253 ) ;
190254 // And now we ran out of GSIs
@@ -200,7 +264,7 @@ mod tests {
200264 assert_eq ! ( allocator. allocate_gsi( 1 ) , Ok ( vec![ arch:: GSI_BASE ] ) ) ;
201265 // We can't allocate MAX_IRQS any more
202266 assert_eq ! (
203- allocator. allocate_gsi( MAX_IRQS ) ,
267+ allocator. allocate_gsi( NR_GSI ) ,
204268 Err ( vm_allocator:: Error :: ResourceNotAvailable )
205269 ) ;
206270 // We can allocate another one and it should be the second available
@@ -221,10 +285,14 @@ mod tests {
221285 #[ test]
222286 fn test_save_restore ( ) {
223287 let mut allocator0 = ResourceAllocator :: new ( ) ;
288+ let irq_0 = allocator0. allocate_irq ( 1 ) . unwrap ( ) [ 0 ] ;
289+ assert_eq ! ( irq_0, IRQ_BASE ) ;
224290 let gsi_0 = allocator0. allocate_gsi ( 1 ) . unwrap ( ) [ 0 ] ;
225291 assert_eq ! ( gsi_0, GSI_BASE ) ;
226292
227293 let mut allocator1 = clone_allocator ( & allocator0) ;
294+ let irq_1 = allocator1. allocate_irq ( 1 ) . unwrap ( ) [ 0 ] ;
295+ assert_eq ! ( irq_1, IRQ_BASE + 1 ) ;
228296 let gsi_1 = allocator1. allocate_gsi ( 1 ) . unwrap ( ) [ 0 ] ;
229297 assert_eq ! ( gsi_1, GSI_BASE + 1 ) ;
230298 let mmio32_mem = allocator1
@@ -251,6 +319,8 @@ mod tests {
251319 . allocate_system_memory ( 0x42 , 1 , AllocPolicy :: ExactMatch ( system_mem) )
252320 . unwrap_err ( ) ;
253321
322+ let irq_2 = allocator2. allocate_irq ( 1 ) . unwrap ( ) [ 0 ] ;
323+ assert_eq ! ( irq_2, IRQ_BASE + 2 ) ;
254324 let gsi_2 = allocator2. allocate_gsi ( 1 ) . unwrap ( ) [ 0 ] ;
255325 assert_eq ! ( gsi_2, GSI_BASE + 2 ) ;
256326 let mmio32_mem = allocator1
0 commit comments