77
88use std:: collections:: HashMap ;
99use std:: fmt:: Debug ;
10+ use std:: num:: NonZeroU32 ;
1011use std:: sync:: { Arc , Mutex } ;
1112
1213#[ cfg( target_arch = "x86_64" ) ]
@@ -79,8 +80,8 @@ pub struct MMIODeviceInfo {
7980 pub addr : u64 ,
8081 /// Mmio addr range length.
8182 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
8485}
8586
8687#[ cfg( target_arch = "x86_64" ) ]
@@ -150,15 +151,20 @@ impl MMIODeviceManager {
150151 resource_allocator : & mut ResourceAllocator ,
151152 irq_count : u32 ,
152153 ) -> 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+
154160 let device_info = MMIODeviceInfo {
155161 addr : resource_allocator. allocate_mmio_memory (
156162 MMIO_LEN ,
157163 MMIO_LEN ,
158164 AllocPolicy :: FirstMatch ,
159165 ) ?,
160166 len : MMIO_LEN ,
161- irqs ,
167+ irq ,
162168 } ;
163169 Ok ( device_info)
164170 }
@@ -187,9 +193,9 @@ impl MMIODeviceManager {
187193 ) -> Result < ( ) , MmioError > {
188194 // Our virtio devices are currently hardcoded to use a single IRQ.
189195 // Validate that requirement.
190- if device_info . irqs . len ( ) != 1 {
196+ let Some ( irq ) = device_info . irq else {
191197 return Err ( MmioError :: InvalidIrqConfig ) ;
192- }
198+ } ;
193199 let identifier;
194200 {
195201 let locked_device = mmio_device. locked_device ( ) ;
@@ -201,11 +207,8 @@ impl MMIODeviceManager {
201207 vm. register_ioevent ( queue_evt, & io_addr, u32:: try_from ( i) . unwrap ( ) )
202208 . map_err ( MmioError :: RegisterIoEvent ) ?;
203209 }
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 ) ?;
209212 }
210213
211214 self . register_mmio_device (
@@ -230,7 +233,7 @@ impl MMIODeviceManager {
230233 . add_virtio_mmio_device (
231234 device_info. len ,
232235 GuestAddress ( device_info. addr ) ,
233- device_info. irqs [ 0 ] ,
236+ device_info. irq . unwrap ( ) . get ( ) ,
234237 None ,
235238 )
236239 . map_err ( MmioError :: Cmdline )
@@ -257,7 +260,7 @@ impl MMIODeviceManager {
257260 device_info. len ,
258261 // We are sure that `irqs` has at least one element; allocate_mmio_resources makes
259262 // sure of it.
260- device_info. irqs [ 0 ] ,
263+ device_info. irq . unwrap ( ) . get ( ) ,
261264 ) ?;
262265 }
263266 Ok ( device_info)
@@ -289,7 +292,7 @@ impl MMIODeviceManager {
289292 . unwrap ( )
290293 . serial
291294 . interrupt_evt ( ) ,
292- device_info. irqs [ 0 ] ,
295+ device_info. irq . unwrap ( ) . get ( ) ,
293296 )
294297 . map_err ( MmioError :: RegisterIrqFd ) ?;
295298
@@ -525,7 +528,7 @@ impl DeviceInfoForFDT for MMIODeviceInfo {
525528 self . addr
526529 }
527530 fn irq ( & self ) -> u32 {
528- self . irqs [ 0 ]
531+ self . irq . unwrap ( ) . into ( )
529532 }
530533 fn length ( & self ) -> u64 {
531534 self . len
@@ -574,11 +577,10 @@ mod tests {
574577 #[ cfg( target_arch = "x86_64" ) ]
575578 /// Gets the number of interrupts used by the devices registered.
576579 pub fn used_irqs_count ( & self ) -> usize {
577- let mut irq_number = 0 ;
578580 self . get_device_info ( )
579581 . 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 ( )
582584 }
583585 }
584586
@@ -784,7 +786,10 @@ mod tests {
784786 ) ;
785787 assert_eq ! (
786788 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( )
788793 ) ;
789794
790795 let id = "bar" ;
@@ -821,50 +826,39 @@ mod tests {
821826 }
822827
823828 #[ test]
824- fn test_slot_irq_allocation ( ) {
829+ fn test_no_irq_allocation ( ) {
825830 let mut device_manager = MMIODeviceManager :: new ( ) ;
826831 let mut resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
832+
827833 let device_info = device_manager
828834 . allocate_mmio_resources ( & mut resource_allocator, 0 )
829835 . 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+
831844 let device_info = device_manager
832845 . allocate_mmio_resources ( & mut resource_allocator, 1 )
833846 . 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+ }
848849
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 ( ) ;
856854 assert_eq ! (
857855 format!(
858856 "{}" ,
859857 device_manager
860858 . allocate_mmio_resources( & mut resource_allocator, 2 )
861859 . unwrap_err( )
862860 ) ,
863- "Failed to allocate requested resource: The requested resource is not available."
864- . to_string( )
861+ "Invalid MMIO IRQ configuration." . to_string( )
865862 ) ;
866- device_manager
867- . allocate_mmio_resources ( & mut resource_allocator, 0 )
868- . unwrap ( ) ;
869863 }
870864}
0 commit comments