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