7
7
8
8
use std:: collections:: HashMap ;
9
9
use std:: fmt:: Debug ;
10
+ use std:: num:: NonZeroU32 ;
10
11
use std:: sync:: { Arc , Mutex } ;
11
12
12
13
#[ cfg( target_arch = "x86_64" ) ]
@@ -79,8 +80,8 @@ pub struct MMIODeviceInfo {
79
80
pub addr : u64 ,
80
81
/// Mmio addr range length.
81
82
pub len : u64 ,
82
- /// Used Irq line(s) for the device.
83
- pub irqs : Vec < u32 > ,
83
+ /// Used Irq line for the device.
84
+ pub irq : Option < NonZeroU32 > , // NOTE: guaranteed to be a value not 0, 0 is not allowed
84
85
}
85
86
86
87
#[ cfg( target_arch = "x86_64" ) ]
@@ -150,15 +151,20 @@ impl MMIODeviceManager {
150
151
resource_allocator : & mut ResourceAllocator ,
151
152
irq_count : u32 ,
152
153
) -> Result < MMIODeviceInfo , MmioError > {
153
- let irqs = resource_allocator. allocate_gsi ( irq_count) ?;
154
+ let irq = match resource_allocator. allocate_gsi ( irq_count) ?[ ..] {
155
+ [ ] => None ,
156
+ [ irq] => NonZeroU32 :: new ( irq) ,
157
+ _ => return Err ( MmioError :: InvalidIrqConfig ) ,
158
+ } ;
159
+
154
160
let device_info = MMIODeviceInfo {
155
161
addr : resource_allocator. allocate_mmio_memory (
156
162
MMIO_LEN ,
157
163
MMIO_LEN ,
158
164
AllocPolicy :: FirstMatch ,
159
165
) ?,
160
166
len : MMIO_LEN ,
161
- irqs ,
167
+ irq ,
162
168
} ;
163
169
Ok ( device_info)
164
170
}
@@ -187,9 +193,9 @@ impl MMIODeviceManager {
187
193
) -> Result < ( ) , MmioError > {
188
194
// Our virtio devices are currently hardcoded to use a single IRQ.
189
195
// Validate that requirement.
190
- if device_info . irqs . len ( ) != 1 {
196
+ let Some ( irq ) = device_info . irq else {
191
197
return Err ( MmioError :: InvalidIrqConfig ) ;
192
- }
198
+ } ;
193
199
let identifier;
194
200
{
195
201
let locked_device = mmio_device. locked_device ( ) ;
@@ -201,11 +207,8 @@ impl MMIODeviceManager {
201
207
vm. register_ioevent ( queue_evt, & io_addr, u32:: try_from ( i) . unwrap ( ) )
202
208
. map_err ( MmioError :: RegisterIoEvent ) ?;
203
209
}
204
- vm. register_irqfd (
205
- & locked_device. interrupt_trigger ( ) . irq_evt ,
206
- device_info. irqs [ 0 ] ,
207
- )
208
- . map_err ( MmioError :: RegisterIrqFd ) ?;
210
+ vm. register_irqfd ( & locked_device. interrupt_trigger ( ) . irq_evt , irq. get ( ) )
211
+ . map_err ( MmioError :: RegisterIrqFd ) ?;
209
212
}
210
213
211
214
self . register_mmio_device (
@@ -230,7 +233,7 @@ impl MMIODeviceManager {
230
233
. add_virtio_mmio_device (
231
234
device_info. len ,
232
235
GuestAddress ( device_info. addr ) ,
233
- device_info. irqs [ 0 ] ,
236
+ device_info. irq . unwrap ( ) . get ( ) ,
234
237
None ,
235
238
)
236
239
. map_err ( MmioError :: Cmdline )
@@ -257,7 +260,7 @@ impl MMIODeviceManager {
257
260
device_info. len ,
258
261
// We are sure that `irqs` has at least one element; allocate_mmio_resources makes
259
262
// sure of it.
260
- device_info. irqs [ 0 ] ,
263
+ device_info. irq . unwrap ( ) . get ( ) ,
261
264
) ?;
262
265
}
263
266
Ok ( device_info)
@@ -289,7 +292,7 @@ impl MMIODeviceManager {
289
292
. unwrap ( )
290
293
. serial
291
294
. interrupt_evt ( ) ,
292
- device_info. irqs [ 0 ] ,
295
+ device_info. irq . unwrap ( ) . get ( ) ,
293
296
)
294
297
. map_err ( MmioError :: RegisterIrqFd ) ?;
295
298
@@ -525,7 +528,7 @@ impl DeviceInfoForFDT for MMIODeviceInfo {
525
528
self . addr
526
529
}
527
530
fn irq ( & self ) -> u32 {
528
- self . irqs [ 0 ]
531
+ self . irq . unwrap ( ) . into ( )
529
532
}
530
533
fn length ( & self ) -> u64 {
531
534
self . len
@@ -574,11 +577,10 @@ mod tests {
574
577
#[ cfg( target_arch = "x86_64" ) ]
575
578
/// Gets the number of interrupts used by the devices registered.
576
579
pub fn used_irqs_count ( & self ) -> usize {
577
- let mut irq_number = 0 ;
578
580
self . get_device_info ( )
579
581
. iter ( )
580
- . for_each ( |( _, device_info) | irq_number += device_info. irqs . len ( ) ) ;
581
- irq_number
582
+ . filter ( |( _, device_info) | device_info. irq . is_some ( ) )
583
+ . count ( )
582
584
}
583
585
}
584
586
@@ -784,7 +786,10 @@ mod tests {
784
786
) ;
785
787
assert_eq ! (
786
788
crate :: arch:: IRQ_BASE ,
787
- device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ] . irqs[ 0 ]
789
+ device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ]
790
+ . irq
791
+ . unwrap( )
792
+ . get( )
788
793
) ;
789
794
790
795
let id = "bar" ;
@@ -821,50 +826,39 @@ mod tests {
821
826
}
822
827
823
828
#[ test]
824
- fn test_slot_irq_allocation ( ) {
829
+ fn test_no_irq_allocation ( ) {
825
830
let mut device_manager = MMIODeviceManager :: new ( ) ;
826
831
let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
832
+
827
833
let device_info = device_manager
828
834
. allocate_mmio_resources ( & mut resource_allocator, 0 )
829
835
. unwrap ( ) ;
830
- assert_eq ! ( device_info. irqs. len( ) , 0 ) ;
836
+ assert ! ( device_info. irq. is_none( ) ) ;
837
+ }
838
+
839
+ #[ test]
840
+ fn test_irq_allocation ( ) {
841
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
842
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
843
+
831
844
let device_info = device_manager
832
845
. allocate_mmio_resources ( & mut resource_allocator, 1 )
833
846
. unwrap ( ) ;
834
- assert_eq ! ( device_info. irqs[ 0 ] , crate :: arch:: IRQ_BASE ) ;
835
- assert_eq ! (
836
- format!(
837
- "{}" ,
838
- device_manager
839
- . allocate_mmio_resources(
840
- & mut resource_allocator,
841
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE + 1
842
- )
843
- . unwrap_err( )
844
- ) ,
845
- "Failed to allocate requested resource: The requested resource is not available."
846
- . to_string( )
847
- ) ;
847
+ assert_eq ! ( device_info. irq. unwrap( ) . get( ) , crate :: arch:: IRQ_BASE ) ;
848
+ }
848
849
849
- let device_info = device_manager
850
- . allocate_mmio_resources (
851
- & mut resource_allocator,
852
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE - 1 ,
853
- )
854
- . unwrap ( ) ;
855
- assert_eq ! ( device_info. irqs[ 16 ] , crate :: arch:: IRQ_BASE + 17 ) ;
850
+ #[ test]
851
+ fn test_allocation_failure ( ) {
852
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
853
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
856
854
assert_eq ! (
857
855
format!(
858
856
"{}" ,
859
857
device_manager
860
858
. allocate_mmio_resources( & mut resource_allocator, 2 )
861
859
. unwrap_err( )
862
860
) ,
863
- "Failed to allocate requested resource: The requested resource is not available."
864
- . to_string( )
861
+ "Invalid MMIO IRQ configuration." . to_string( )
865
862
) ;
866
- device_manager
867
- . allocate_mmio_resources ( & mut resource_allocator, 0 )
868
- . unwrap ( ) ;
869
863
}
870
864
}
0 commit comments