@@ -19,7 +19,9 @@ use crate::snapshot::Persist;
19
19
/// * Memory allocations in the MMIO address space
20
20
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
21
21
pub 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
23
25
pub gsi_allocator : IdAllocator ,
24
26
/// Allocator for memory in the 32-bit MMIO address space
25
27
pub mmio32_memory : AddressAllocator ,
@@ -41,7 +43,8 @@ impl ResourceAllocator {
41
43
// It is fine for us to unwrap the following since we know we are passing valid ranges for
42
44
// all allocators
43
45
Self {
44
- gsi_allocator : IdAllocator :: new ( arch:: IRQ_BASE , arch:: IRQ_MAX ) . unwrap ( ) ,
46
+ irq_allocator : IdAllocator :: new ( arch:: IRQ_BASE , arch:: IRQ_MAX ) . unwrap ( ) ,
47
+ gsi_allocator : IdAllocator :: new ( arch:: GSI_BASE , arch:: GSI_MAX ) . unwrap ( ) ,
45
48
mmio32_memory : AddressAllocator :: new (
46
49
arch:: MEM_32BIT_DEVICES_START ,
47
50
arch:: MEM_32BIT_DEVICES_SIZE ,
@@ -57,6 +60,30 @@ impl ResourceAllocator {
57
60
}
58
61
}
59
62
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
+
60
87
/// Allocate a number of GSIs
61
88
///
62
89
/// # Arguments
@@ -167,25 +194,66 @@ mod tests {
167
194
use vm_allocator:: AllocPolicy ;
168
195
169
196
use super :: ResourceAllocator ;
170
- use crate :: arch:: { self , IRQ_BASE } ;
197
+ use crate :: arch:: { self , GSI_BASE , IRQ_BASE } ;
171
198
use crate :: snapshot:: { Persist , Snapshot } ;
172
199
173
200
const MAX_IRQS : u32 = arch:: IRQ_MAX - arch:: IRQ_BASE + 1 ;
174
201
202
+ #[ test]
203
+ fn test_allocate_irq ( ) {
204
+ let mut allocator = ResourceAllocator :: new ( ) ;
205
+ // asking for 0 IRQs should return us an empty vector
206
+ assert_eq ! ( allocator. allocate_irq( 0 ) , Ok ( vec![ ] ) ) ;
207
+ // We cannot allocate more GSIs than available
208
+ assert_eq ! (
209
+ allocator. allocate_irq( MAX_IRQS + 1 ) ,
210
+ Err ( vm_allocator:: Error :: ResourceNotAvailable )
211
+ ) ;
212
+ // But allocating all of them at once should work
213
+ assert_eq ! (
214
+ allocator. allocate_irq( MAX_IRQS ) ,
215
+ Ok ( ( arch:: IRQ_BASE ..=arch:: IRQ_MAX ) . collect:: <Vec <_>>( ) )
216
+ ) ;
217
+ // And now we ran out of GSIs
218
+ assert_eq ! (
219
+ allocator. allocate_irq( 1 ) ,
220
+ Err ( vm_allocator:: Error :: ResourceNotAvailable )
221
+ ) ;
222
+ // But we should be able to ask for 0 GSIs
223
+ assert_eq ! ( allocator. allocate_irq( 0 ) , Ok ( vec![ ] ) ) ;
224
+
225
+ let mut allocator = ResourceAllocator :: new ( ) ;
226
+ // We should be able to allocate 1 GSI
227
+ assert_eq ! ( allocator. allocate_irq( 1 ) , Ok ( vec![ arch:: IRQ_BASE ] ) ) ;
228
+ // We can't allocate MAX_IRQS any more
229
+ assert_eq ! (
230
+ allocator. allocate_irq( MAX_IRQS ) ,
231
+ Err ( vm_allocator:: Error :: ResourceNotAvailable )
232
+ ) ;
233
+ // We can allocate another one and it should be the second available
234
+ assert_eq ! ( allocator. allocate_irq( 1 ) , Ok ( vec![ arch:: IRQ_BASE + 1 ] ) ) ;
235
+ // Let's allocate the rest in a loop
236
+ for i in arch:: IRQ_BASE + 2 ..=arch:: IRQ_MAX {
237
+ assert_eq ! ( allocator. allocate_irq( 1 ) , Ok ( vec![ i] ) ) ;
238
+ }
239
+ }
240
+
241
+ const MAX_GSIS : u32 = arch:: GSI_MAX - arch:: GSI_BASE + 1 ;
242
+
175
243
#[ test]
176
244
fn test_allocate_gsi ( ) {
177
245
let mut allocator = ResourceAllocator :: new ( ) ;
178
246
// asking for 0 IRQs should return us an empty vector
179
247
assert_eq ! ( allocator. allocate_gsi( 0 ) , Ok ( vec![ ] ) ) ;
180
248
// We cannot allocate more GSIs than available
181
249
assert_eq ! (
182
- allocator. allocate_gsi( MAX_IRQS + 1 ) ,
250
+ allocator. allocate_gsi( MAX_GSIS + 1 ) ,
183
251
Err ( vm_allocator:: Error :: ResourceNotAvailable )
184
252
) ;
185
253
// But allocating all of them at once should work
186
254
assert_eq ! (
187
- allocator. allocate_gsi( MAX_IRQS ) ,
188
- Ok ( ( arch:: IRQ_BASE ..=arch:: IRQ_MAX ) . collect:: <Vec <_>>( ) )
255
+ allocator. allocate_gsi( MAX_GSIS ) ,
256
+ Ok ( ( arch:: GSI_BASE ..=arch:: GSI_MAX ) . collect:: <Vec <_>>( ) )
189
257
) ;
190
258
// And now we ran out of GSIs
191
259
assert_eq ! (
@@ -197,16 +265,16 @@ mod tests {
197
265
198
266
let mut allocator = ResourceAllocator :: new ( ) ;
199
267
// We should be able to allocate 1 GSI
200
- assert_eq ! ( allocator. allocate_gsi( 1 ) , Ok ( vec![ arch:: IRQ_BASE ] ) ) ;
268
+ assert_eq ! ( allocator. allocate_gsi( 1 ) , Ok ( vec![ arch:: GSI_BASE ] ) ) ;
201
269
// We can't allocate MAX_IRQS any more
202
270
assert_eq ! (
203
- allocator. allocate_gsi( MAX_IRQS ) ,
271
+ allocator. allocate_gsi( MAX_GSIS ) ,
204
272
Err ( vm_allocator:: Error :: ResourceNotAvailable )
205
273
) ;
206
274
// We can allocate another one and it should be the second available
207
- assert_eq ! ( allocator. allocate_gsi( 1 ) , Ok ( vec![ arch:: IRQ_BASE + 1 ] ) ) ;
275
+ assert_eq ! ( allocator. allocate_gsi( 1 ) , Ok ( vec![ arch:: GSI_BASE + 1 ] ) ) ;
208
276
// Let's allocate the rest in a loop
209
- for i in arch:: IRQ_BASE + 2 ..=arch:: IRQ_MAX {
277
+ for i in arch:: GSI_BASE + 2 ..=arch:: GSI_MAX {
210
278
assert_eq ! ( allocator. allocate_gsi( 1 ) , Ok ( vec![ i] ) ) ;
211
279
}
212
280
}
@@ -221,12 +289,16 @@ mod tests {
221
289
#[ test]
222
290
fn test_save_restore ( ) {
223
291
let mut allocator0 = ResourceAllocator :: new ( ) ;
292
+ let irq_0 = allocator0. allocate_irq ( 1 ) . unwrap ( ) [ 0 ] ;
293
+ assert_eq ! ( irq_0, IRQ_BASE ) ;
224
294
let gsi_0 = allocator0. allocate_gsi ( 1 ) . unwrap ( ) [ 0 ] ;
225
- assert_eq ! ( gsi_0, IRQ_BASE ) ;
295
+ assert_eq ! ( gsi_0, GSI_BASE ) ;
226
296
227
297
let mut allocator1 = clone_allocator ( & allocator0) ;
298
+ let irq_1 = allocator1. allocate_irq ( 1 ) . unwrap ( ) [ 0 ] ;
299
+ assert_eq ! ( irq_1, IRQ_BASE + 1 ) ;
228
300
let gsi_1 = allocator1. allocate_gsi ( 1 ) . unwrap ( ) [ 0 ] ;
229
- assert_eq ! ( gsi_1, IRQ_BASE + 1 ) ;
301
+ assert_eq ! ( gsi_1, GSI_BASE + 1 ) ;
230
302
let mmio32_mem = allocator1
231
303
. allocate_32bit_mmio_memory ( 0x42 , 1 , AllocPolicy :: FirstMatch )
232
304
. unwrap ( ) ;
@@ -251,8 +323,10 @@ mod tests {
251
323
. allocate_system_memory ( 0x42 , 1 , AllocPolicy :: ExactMatch ( system_mem) )
252
324
. unwrap_err ( ) ;
253
325
326
+ let irq_2 = allocator2. allocate_irq ( 1 ) . unwrap ( ) [ 0 ] ;
327
+ assert_eq ! ( irq_2, IRQ_BASE + 2 ) ;
254
328
let gsi_2 = allocator2. allocate_gsi ( 1 ) . unwrap ( ) [ 0 ] ;
255
- assert_eq ! ( gsi_2, IRQ_BASE + 2 ) ;
329
+ assert_eq ! ( gsi_2, GSI_BASE + 2 ) ;
256
330
let mmio32_mem = allocator1
257
331
. allocate_32bit_mmio_memory ( 0x42 , 1 , AllocPolicy :: FirstMatch )
258
332
. unwrap ( ) ;
0 commit comments