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
@@ -507,7 +510,7 @@ impl DeviceInfoForFDT for MMIODeviceInfo {
507
510
self . addr
508
511
}
509
512
fn irq ( & self ) -> u32 {
510
- self . irqs [ 0 ]
513
+ self . irq . unwrap ( ) . into ( )
511
514
}
512
515
fn length ( & self ) -> u64 {
513
516
self . len
@@ -555,11 +558,10 @@ mod tests {
555
558
#[ cfg( target_arch = "x86_64" ) ]
556
559
/// Gets the number of interrupts used by the devices registered.
557
560
pub fn used_irqs_count ( & self ) -> usize {
558
- let mut irq_number = 0 ;
559
561
self . get_device_info ( )
560
562
. iter ( )
561
- . for_each ( |( _, device_info) | irq_number += device_info. irqs . len ( ) ) ;
562
- irq_number
563
+ . filter ( |( _, device_info) | device_info. irq . is_some ( ) )
564
+ . count ( )
563
565
}
564
566
}
565
567
@@ -762,7 +764,10 @@ mod tests {
762
764
) ;
763
765
assert_eq ! (
764
766
crate :: arch:: IRQ_BASE ,
765
- device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ] . irqs[ 0 ]
767
+ device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ]
768
+ . irq
769
+ . unwrap( )
770
+ . get( )
766
771
) ;
767
772
768
773
let id = "bar" ;
@@ -799,50 +804,39 @@ mod tests {
799
804
}
800
805
801
806
#[ test]
802
- fn test_slot_irq_allocation ( ) {
807
+ fn test_no_irq_allocation ( ) {
803
808
let mut device_manager = MMIODeviceManager :: new ( ) ;
804
809
let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
810
+
805
811
let device_info = device_manager
806
812
. allocate_mmio_resources ( & mut resource_allocator, 0 )
807
813
. unwrap ( ) ;
808
- assert_eq ! ( device_info. irqs. len( ) , 0 ) ;
814
+ assert ! ( device_info. irq. is_none( ) ) ;
815
+ }
816
+
817
+ #[ test]
818
+ fn test_irq_allocation ( ) {
819
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
820
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
821
+
809
822
let device_info = device_manager
810
823
. allocate_mmio_resources ( & mut resource_allocator, 1 )
811
824
. unwrap ( ) ;
812
- assert_eq ! ( device_info. irqs[ 0 ] , crate :: arch:: IRQ_BASE ) ;
813
- assert_eq ! (
814
- format!(
815
- "{}" ,
816
- device_manager
817
- . allocate_mmio_resources(
818
- & mut resource_allocator,
819
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE + 1
820
- )
821
- . unwrap_err( )
822
- ) ,
823
- "Failed to allocate requested resource: The requested resource is not available."
824
- . to_string( )
825
- ) ;
825
+ assert_eq ! ( device_info. irq. unwrap( ) . get( ) , crate :: arch:: IRQ_BASE ) ;
826
+ }
826
827
827
- let device_info = device_manager
828
- . allocate_mmio_resources (
829
- & mut resource_allocator,
830
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE - 1 ,
831
- )
832
- . unwrap ( ) ;
833
- assert_eq ! ( device_info. irqs[ 16 ] , crate :: arch:: IRQ_BASE + 17 ) ;
828
+ #[ test]
829
+ fn test_allocation_failure ( ) {
830
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
831
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
834
832
assert_eq ! (
835
833
format!(
836
834
"{}" ,
837
835
device_manager
838
836
. allocate_mmio_resources( & mut resource_allocator, 2 )
839
837
. unwrap_err( )
840
838
) ,
841
- "Failed to allocate requested resource: The requested resource is not available."
842
- . to_string( )
839
+ "Invalid MMIO IRQ configuration." . to_string( )
843
840
) ;
844
- device_manager
845
- . allocate_mmio_resources ( & mut resource_allocator, 0 )
846
- . unwrap ( ) ;
847
841
}
848
842
}
0 commit comments