@@ -182,6 +182,25 @@ impl MmioDevice {
182182 }
183183 }
184184
185+ fn reset ( & mut self ) {
186+ if self . device_activated {
187+ warn ! ( "reset device while it's still in active state" ) ;
188+ return ;
189+ }
190+ self . features_select = 0 ;
191+ self . acked_features_select = 0 ;
192+ self . queue_select = 0 ;
193+ self . interrupt_status . store ( 0 , Ordering :: SeqCst ) ;
194+ self . driver_status = 0 ;
195+ // . Keep interrupt_evt and queue_evts as is. There may be pending
196+ // notifications in those eventfds, but nothing will happen other
197+ // than supurious wakeups.
198+ // . Do not reset config_generation and keep it monotonically increasing
199+ for queue in self . queues . as_mut_slice ( ) {
200+ * queue = Queue :: new ( queue. get_max_size ( ) ) ;
201+ }
202+ }
203+
185204 /// Update driver status according to the state machine defined by VirtIO Spec 1.0.
186205 /// Please refer to VirtIO Spec 1.0, section 2.1.1 and 3.1.1.
187206 ///
@@ -210,10 +229,10 @@ impl MmioDevice {
210229 // check will fail and take the device into an unusable state.
211230 if !self . device_activated && self . are_queues_valid ( ) {
212231 if let Some ( ref interrupt_evt) = self . interrupt_evt {
213- if let Some ( mem) = self . mem . take ( ) {
232+ if let Some ( ref mem) = self . mem {
214233 self . device
215234 . activate (
216- mem,
235+ mem. clone ( ) ,
217236 interrupt_evt. try_clone ( ) . expect ( "Failed to clone eventfd" ) ,
218237 self . interrupt_status . clone ( ) ,
219238 self . queues . clone ( ) ,
@@ -226,11 +245,25 @@ impl MmioDevice {
226245 }
227246 }
228247 _ if ( v & DEVICE_FAILED ) != 0 => {
229- // TODO: stop device
248+ // TODO: notify backend driver to stop the device
230249 self . driver_status |= DEVICE_FAILED ;
231250 }
232251 _ if v == 0 => {
233- return ; // TODO reset device status
252+ if self . device_activated {
253+ match self . device . reset ( ) {
254+ Some ( ( _interrupt_evt, mut queue_evts) ) => {
255+ self . device_activated = false ;
256+ self . queue_evts . append ( & mut queue_evts) ;
257+ }
258+ // Backend device driver doesn't support reset,
259+ // just mark the device as FAILED.
260+ None => {
261+ self . driver_status |= DEVICE_FAILED ;
262+ return ;
263+ }
264+ }
265+ }
266+ self . reset ( ) ;
234267 }
235268 _ => {
236269 warn ! (
@@ -363,18 +396,25 @@ impl BusDevice for MmioDevice {
363396#[ cfg( test) ]
364397mod tests {
365398 use byteorder:: { ByteOrder , LittleEndian } ;
399+ use std:: sync:: atomic:: ATOMIC_USIZE_INIT ;
366400
367401 use super :: * ;
368402
403+ static DEVICE_RESET_ENABLED : AtomicUsize = ATOMIC_USIZE_INIT ;
404+
369405 struct DummyDevice {
370406 acked_features : u32 ,
407+ interrupt_evt : Option < EventFd > ,
408+ queue_evts : Option < Vec < EventFd > > ,
371409 config_bytes : [ u8 ; 0xeff ] ,
372410 }
373411
374412 impl DummyDevice {
375413 fn new ( ) -> Self {
376414 DummyDevice {
377415 acked_features : 0 ,
416+ interrupt_evt : None ,
417+ queue_evts : None ,
378418 config_bytes : [ 0 ; 0xeff ] ,
379419 }
380420 }
@@ -408,13 +448,26 @@ mod tests {
408448 fn activate (
409449 & mut self ,
410450 _mem : GuestMemory ,
411- _interrupt_evt : EventFd ,
451+ interrupt_evt : EventFd ,
412452 _status : Arc < AtomicUsize > ,
413453 _queues : Vec < Queue > ,
414- _queue_evts : Vec < EventFd > ,
454+ queue_evts : Vec < EventFd > ,
415455 ) -> ActivateResult {
456+ self . interrupt_evt = Some ( interrupt_evt) ;
457+ self . queue_evts = Some ( queue_evts) ;
416458 Ok ( ( ) )
417459 }
460+
461+ fn reset ( & mut self ) -> Option < ( EventFd , Vec < EventFd > ) > {
462+ if self . interrupt_evt . is_some ( ) && DEVICE_RESET_ENABLED . load ( Ordering :: SeqCst ) != 0 {
463+ Some ( (
464+ self . interrupt_evt . take ( ) . unwrap ( ) ,
465+ self . queue_evts . take ( ) . unwrap ( ) ,
466+ ) )
467+ } else {
468+ None
469+ }
470+ }
418471 }
419472
420473 fn set_driver_status ( d : & mut MmioDevice , status : u32 ) {
@@ -747,15 +800,68 @@ mod tests {
747800 d. write ( 0x44 , & buf[ ..] ) ;
748801 d. read ( 0x44 , & mut buf[ ..] ) ;
749802 assert_eq ! ( LittleEndian :: read_u32( & buf[ ..] ) , 1 ) ;
803+ }
750804
805+ fn activate_device ( d : & mut MmioDevice ) {
806+ set_driver_status ( d, DEVICE_ACKNOWLEDGE ) ;
807+ set_driver_status ( d, DEVICE_ACKNOWLEDGE | DEVICE_DRIVER ) ;
808+ set_driver_status ( d, DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_FEATURES_OK ) ;
809+
810+ // Setup queue data structures
811+ let mut buf = vec ! [ 0 ; 4 ] ;
812+ for q in 0 ..d. queues . len ( ) {
813+ d. queue_select = q as u32 ;
814+ LittleEndian :: write_u32 ( & mut buf[ ..] , 16 ) ;
815+ d. write ( 0x38 , & buf[ ..] ) ;
816+ LittleEndian :: write_u32 ( & mut buf[ ..] , 1 ) ;
817+ d. write ( 0x44 , & buf[ ..] ) ;
818+ }
819+ assert ! ( d. are_queues_valid( ) ) ;
820+ assert ! ( !d. device_activated) ;
821+
822+ // Device should be ready for activation now.
823+ set_driver_status (
824+ d,
825+ DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_FEATURES_OK | DEVICE_DRIVER_OK ,
826+ ) ;
827+ assert_eq ! (
828+ d. driver_status,
829+ DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_FEATURES_OK | DEVICE_DRIVER_OK
830+ ) ;
831+ assert ! ( d. device_activated) ;
832+ }
833+
834+ #[ test]
835+ fn test_bus_device_reset ( ) {
836+ let m = GuestMemory :: new ( & [ ( GuestAddress ( 0 ) , 0x1000 ) ] ) . unwrap ( ) ;
837+ let mut d = MmioDevice :: new ( m, Box :: new ( DummyDevice :: new ( ) ) ) . unwrap ( ) ;
838+ let mut buf = vec ! [ 0 ; 4 ] ;
839+
840+ assert ! ( !d. are_queues_valid( ) ) ;
841+ assert ! ( !d. device_activated) ;
842+ assert_eq ! ( d. driver_status, 0 ) ;
843+ activate_device ( & mut d) ;
844+
845+ // Marking device as FAILED should not affect device_activated state
751846 LittleEndian :: write_u32 ( & mut buf[ ..] , 0x8f ) ;
752847 d. write ( 0x70 , & buf[ ..] ) ;
753848 assert_eq ! ( d. driver_status, 0x8f ) ;
754- // TODO: assert!(d.device_activated);
849+ assert ! ( d. device_activated) ;
755850
851+ // Nothing happens when backend driver doesn't support reset
852+ DEVICE_RESET_ENABLED . store ( 0 , Ordering :: SeqCst ) ;
756853 LittleEndian :: write_u32 ( & mut buf[ ..] , 0x0 ) ;
757854 d. write ( 0x70 , & buf[ ..] ) ;
758- // TODO: assert_eq!(d.driver_status, 0x0);
759- // TODO: assert!(d.device_activated);
855+ assert_eq ! ( d. driver_status, 0x8f ) ;
856+ assert ! ( d. device_activated) ;
857+
858+ DEVICE_RESET_ENABLED . store ( 1 , Ordering :: SeqCst ) ;
859+ LittleEndian :: write_u32 ( & mut buf[ ..] , 0x0 ) ;
860+ d. write ( 0x70 , & buf[ ..] ) ;
861+ assert_eq ! ( d. driver_status, 0x0 ) ;
862+ assert ! ( !d. device_activated) ;
863+
864+ DEVICE_RESET_ENABLED . store ( 0 , Ordering :: SeqCst ) ;
865+ activate_device ( & mut d) ;
760866 }
761867}
0 commit comments