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,7 +199,7 @@ 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 ( locked_device. interrupt_evt ( ) , device_info . irqs [ 0 ] )
202
+ vm. register_irqfd ( locked_device. interrupt_evt ( ) , irq . get ( ) )
197
203
. map_err ( MmioError :: RegisterIrqFd ) ?;
198
204
}
199
205
@@ -219,7 +225,7 @@ impl MMIODeviceManager {
219
225
. add_virtio_mmio_device (
220
226
device_info. len ,
221
227
GuestAddress ( device_info. addr ) ,
222
- device_info. irqs [ 0 ] ,
228
+ device_info. irq . unwrap ( ) . get ( ) ,
223
229
None ,
224
230
)
225
231
. map_err ( MmioError :: Cmdline )
@@ -246,7 +252,7 @@ impl MMIODeviceManager {
246
252
device_info. len ,
247
253
// We are sure that `irqs` has at least one element; allocate_mmio_resources makes
248
254
// sure of it.
249
- device_info. irqs [ 0 ] ,
255
+ device_info. irq . unwrap ( ) . get ( ) ,
250
256
) ;
251
257
}
252
258
Ok ( device_info)
@@ -278,7 +284,7 @@ impl MMIODeviceManager {
278
284
. unwrap ( )
279
285
. serial
280
286
. interrupt_evt ( ) ,
281
- device_info. irqs [ 0 ] ,
287
+ device_info. irq . unwrap ( ) . get ( ) ,
282
288
)
283
289
. map_err ( MmioError :: RegisterIrqFd ) ?;
284
290
@@ -504,7 +510,7 @@ impl DeviceInfoForFDT for MMIODeviceInfo {
504
510
self . addr
505
511
}
506
512
fn irq ( & self ) -> u32 {
507
- self . irqs [ 0 ]
513
+ self . irq . unwrap ( )
508
514
}
509
515
fn length ( & self ) -> u64 {
510
516
self . len
@@ -552,10 +558,11 @@ mod tests {
552
558
#[ cfg( target_arch = "x86_64" ) ]
553
559
/// Gets the number of interrupts used by the devices registered.
554
560
pub fn used_irqs_count ( & self ) -> usize {
555
- let mut irq_number = 0 ;
556
- self . get_device_info ( )
561
+ let irq_number = self
562
+ . get_device_info ( )
557
563
. iter ( )
558
- . for_each ( |( _, device_info) | irq_number += device_info. irqs . len ( ) ) ;
564
+ . map ( |( _, device_info) | device_info. irq . is_some ( ) )
565
+ . count ( ) ;
559
566
irq_number
560
567
}
561
568
}
@@ -763,7 +770,10 @@ mod tests {
763
770
) ;
764
771
assert_eq ! (
765
772
crate :: arch:: IRQ_BASE ,
766
- device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ] . irqs[ 0 ]
773
+ device_manager. id_to_dev_info[ & ( DeviceType :: Virtio ( type_id) , id) ]
774
+ . irq
775
+ . unwrap( )
776
+ . get( )
767
777
) ;
768
778
769
779
let id = "bar" ;
@@ -800,50 +810,39 @@ mod tests {
800
810
}
801
811
802
812
#[ test]
803
- fn test_slot_irq_allocation ( ) {
813
+ fn test_no_irq_allocation ( ) {
804
814
let mut device_manager = MMIODeviceManager :: new ( ) ;
805
815
let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
816
+
806
817
let device_info = device_manager
807
818
. allocate_mmio_resources ( & mut resource_allocator, 0 )
808
819
. unwrap ( ) ;
809
- assert_eq ! ( device_info. irqs. len( ) , 0 ) ;
820
+ assert ! ( device_info. irq. is_none( ) ) ;
821
+ }
822
+
823
+ #[ test]
824
+ fn test_irq_allocation ( ) {
825
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
826
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
827
+
810
828
let device_info = device_manager
811
829
. allocate_mmio_resources ( & mut resource_allocator, 1 )
812
830
. unwrap ( ) ;
813
- assert_eq ! ( device_info. irqs[ 0 ] , crate :: arch:: IRQ_BASE ) ;
814
- assert_eq ! (
815
- format!(
816
- "{}" ,
817
- device_manager
818
- . allocate_mmio_resources(
819
- & mut resource_allocator,
820
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE + 1
821
- )
822
- . unwrap_err( )
823
- ) ,
824
- "Failed to allocate requested resource: The requested resource is not available."
825
- . to_string( )
826
- ) ;
831
+ assert_eq ! ( device_info. irq. unwrap( ) . get( ) , crate :: arch:: IRQ_BASE ) ;
832
+ }
827
833
828
- let device_info = device_manager
829
- . allocate_mmio_resources (
830
- & mut resource_allocator,
831
- crate :: arch:: IRQ_MAX - crate :: arch:: IRQ_BASE - 1 ,
832
- )
833
- . unwrap ( ) ;
834
- assert_eq ! ( device_info. irqs[ 16 ] , crate :: arch:: IRQ_BASE + 17 ) ;
834
+ #[ test]
835
+ fn test_allocation_failure ( ) {
836
+ let mut device_manager = MMIODeviceManager :: new ( ) ;
837
+ let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
835
838
assert_eq ! (
836
839
format!(
837
840
"{}" ,
838
841
device_manager
839
842
. allocate_mmio_resources( & mut resource_allocator, 2 )
840
843
. unwrap_err( )
841
844
) ,
842
- "Failed to allocate requested resource: The requested resource is not available."
843
- . to_string( )
845
+ "Invalid MMIO IRQ configuration." . to_string( )
844
846
) ;
845
- device_manager
846
- . allocate_mmio_resources ( & mut resource_allocator, 0 )
847
- . unwrap ( ) ;
848
847
}
849
848
}
0 commit comments