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" ) ]
@@ -76,8 +77,8 @@ pub struct MMIODeviceInfo {
76
77
pub addr : u64 ,
77
78
/// Mmio addr range length.
78
79
pub len : u64 ,
79
- /// Used Irq line(s) for the device.
80
- pub irqs : Vec < u32 > ,
80
+ /// Used Irq line for the device.
81
+ pub irq : Option < NonZeroU32 > , // NOTE: guaranteed to be a value not 0, 0 is not allowed
81
82
}
82
83
83
84
#[ cfg( target_arch = "x86_64" ) ]
@@ -142,15 +143,20 @@ impl MMIODeviceManager {
142
143
resource_allocator : & mut ResourceAllocator ,
143
144
irq_count : u32 ,
144
145
) -> Result < MMIODeviceInfo , MmioError > {
145
- let irqs = resource_allocator. allocate_gsi ( irq_count) ?;
146
+ let irq = match resource_allocator. allocate_gsi ( irq_count) ?[ ..] {
147
+ [ ] => None ,
148
+ [ irq] => NonZeroU32 :: new ( irq) ,
149
+ _ => return Err ( MmioError :: InvalidIrqConfig ) ,
150
+ } ;
151
+
146
152
let device_info = MMIODeviceInfo {
147
153
addr : resource_allocator. allocate_mmio_memory (
148
154
MMIO_LEN ,
149
155
MMIO_LEN ,
150
156
AllocPolicy :: FirstMatch ,
151
157
) ?,
152
158
len : MMIO_LEN ,
153
- irqs ,
159
+ irq ,
154
160
} ;
155
161
Ok ( device_info)
156
162
}
@@ -179,9 +185,9 @@ impl MMIODeviceManager {
179
185
) -> Result < ( ) , MmioError > {
180
186
// Our virtio devices are currently hardcoded to use a single IRQ.
181
187
// Validate that requirement.
182
- if device_info . irqs . len ( ) != 1 {
188
+ let Some ( irq ) = device_info . irq else {
183
189
return Err ( MmioError :: InvalidIrqConfig ) ;
184
- }
190
+ } ;
185
191
let identifier;
186
192
{
187
193
let locked_device = mmio_device. locked_device ( ) ;
@@ -193,11 +199,8 @@ impl MMIODeviceManager {
193
199
vm. register_ioevent ( queue_evt, & io_addr, u32:: try_from ( i) . unwrap ( ) )
194
200
. map_err ( MmioError :: RegisterIoEvent ) ?;
195
201
}
196
- vm. register_irqfd (
197
- & locked_device. interrupt_trigger ( ) . irq_evt ,
198
- device_info. irqs [ 0 ] ,
199
- )
200
- . map_err ( MmioError :: RegisterIrqFd ) ?;
202
+ vm. register_irqfd ( & locked_device. interrupt_trigger ( ) . irq_evt , irq. get ( ) )
203
+ . map_err ( MmioError :: RegisterIrqFd ) ?;
201
204
}
202
205
203
206
self . register_mmio_device (
@@ -222,7 +225,7 @@ impl MMIODeviceManager {
222
225
. add_virtio_mmio_device (
223
226
device_info. len ,
224
227
GuestAddress ( device_info. addr ) ,
225
- device_info. irqs [ 0 ] ,
228
+ device_info. irq . unwrap ( ) . get ( ) ,
226
229
None ,
227
230
)
228
231
. map_err ( MmioError :: Cmdline )
@@ -249,7 +252,7 @@ impl MMIODeviceManager {
249
252
device_info. len ,
250
253
// We are sure that `irqs` has at least one element; allocate_mmio_resources makes
251
254
// sure of it.
252
- device_info. irqs [ 0 ] ,
255
+ device_info. irq . unwrap ( ) . get ( ) ,
253
256
) ;
254
257
}
255
258
Ok ( device_info)
@@ -281,7 +284,7 @@ impl MMIODeviceManager {
281
284
. unwrap ( )
282
285
. serial
283
286
. interrupt_evt ( ) ,
284
- device_info. irqs [ 0 ] ,
287
+ device_info. irq . unwrap ( ) . get ( ) ,
285
288
)
286
289
. map_err ( MmioError :: RegisterIrqFd ) ?;
287
290
@@ -517,7 +520,7 @@ impl DeviceInfoForFDT for MMIODeviceInfo {
517
520
self . addr
518
521
}
519
522
fn irq ( & self ) -> u32 {
520
- self . irqs [ 0 ]
523
+ self . irq . unwrap ( ) . into ( )
521
524
}
522
525
fn length ( & self ) -> u64 {
523
526
self . len
@@ -565,11 +568,10 @@ mod tests {
565
568
#[ cfg( target_arch = "x86_64" ) ]
566
569
/// Gets the number of interrupts used by the devices registered.
567
570
pub fn used_irqs_count ( & self ) -> usize {
568
- let mut irq_number = 0 ;
569
571
self . get_device_info ( )
570
572
. iter ( )
571
- . for_each ( |( _, device_info) | irq_number += device_info. irqs . len ( ) ) ;
572
- irq_number
573
+ . filter ( |( _, device_info) | device_info. irq . is_some ( ) )
574
+ . count ( )
573
575
}
574
576
}
575
577
@@ -772,7 +774,10 @@ mod tests {
772
774
) ;
773
775
assert_eq ! (
774
776
crate :: arch:: IRQ_BASE ,
775
- device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ] . irqs[ 0 ]
777
+ device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ]
778
+ . irq
779
+ . unwrap( )
780
+ . get( )
776
781
) ;
777
782
778
783
let id = "bar" ;
@@ -809,50 +814,39 @@ mod tests {
809
814
}
810
815
811
816
#[ test]
812
- fn test_slot_irq_allocation ( ) {
817
+ fn test_no_irq_allocation ( ) {
813
818
let mut device_manager = MMIODeviceManager :: new ( ) ;
814
819
let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
820
+
815
821
let device_info = device_manager
816
822
. allocate_mmio_resources ( & mut resource_allocator, 0 )
817
823
. unwrap ( ) ;
818
- assert_eq ! ( device_info. irqs. len( ) , 0 ) ;
824
+ assert ! ( device_info. irq. is_none( ) ) ;
825
+ }
826
+
827
+ #[ test]
828
+ fn test_irq_allocation ( ) {
829
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
830
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
831
+
819
832
let device_info = device_manager
820
833
. allocate_mmio_resources ( & mut resource_allocator, 1 )
821
834
. unwrap ( ) ;
822
- assert_eq ! ( device_info. irqs[ 0 ] , crate :: arch:: IRQ_BASE ) ;
823
- assert_eq ! (
824
- format!(
825
- "{}" ,
826
- device_manager
827
- . allocate_mmio_resources(
828
- & mut resource_allocator,
829
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE + 1
830
- )
831
- . unwrap_err( )
832
- ) ,
833
- "Failed to allocate requested resource: The requested resource is not available."
834
- . to_string( )
835
- ) ;
835
+ assert_eq ! ( device_info. irq. unwrap( ) . get( ) , crate :: arch:: IRQ_BASE ) ;
836
+ }
836
837
837
- let device_info = device_manager
838
- . allocate_mmio_resources (
839
- & mut resource_allocator,
840
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE - 1 ,
841
- )
842
- . unwrap ( ) ;
843
- assert_eq ! ( device_info. irqs[ 16 ] , crate :: arch:: IRQ_BASE + 17 ) ;
838
+ #[ test]
839
+ fn test_allocation_failure ( ) {
840
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
841
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
844
842
assert_eq ! (
845
843
format!(
846
844
"{}" ,
847
845
device_manager
848
846
. allocate_mmio_resources( & mut resource_allocator, 2 )
849
847
. unwrap_err( )
850
848
) ,
851
- "Failed to allocate requested resource: The requested resource is not available."
852
- . to_string( )
849
+ "Invalid MMIO IRQ configuration." . to_string( )
853
850
) ;
854
- device_manager
855
- . allocate_mmio_resources ( & mut resource_allocator, 0 )
856
- . unwrap ( ) ;
857
851
}
858
852
}
0 commit comments