@@ -182,6 +182,25 @@ impl MmioDevice {
182
182
}
183
183
}
184
184
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
+
185
204
/// Update driver status according to the state machine defined by VirtIO Spec 1.0.
186
205
/// Please refer to VirtIO Spec 1.0, section 2.1.1 and 3.1.1.
187
206
///
@@ -210,10 +229,10 @@ impl MmioDevice {
210
229
// check will fail and take the device into an unusable state.
211
230
if !self . device_activated && self . are_queues_valid ( ) {
212
231
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 {
214
233
self . device
215
234
. activate (
216
- mem,
235
+ mem. clone ( ) ,
217
236
interrupt_evt. try_clone ( ) . expect ( "Failed to clone eventfd" ) ,
218
237
self . interrupt_status . clone ( ) ,
219
238
self . queues . clone ( ) ,
@@ -226,11 +245,25 @@ impl MmioDevice {
226
245
}
227
246
}
228
247
_ if ( v & DEVICE_FAILED ) != 0 => {
229
- // TODO: stop device
248
+ // TODO: notify backend driver to stop the device
230
249
self . driver_status |= DEVICE_FAILED ;
231
250
}
232
251
_ 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 ( ) ;
234
267
}
235
268
_ => {
236
269
warn ! (
@@ -363,18 +396,25 @@ impl BusDevice for MmioDevice {
363
396
#[ cfg( test) ]
364
397
mod tests {
365
398
use byteorder:: { ByteOrder , LittleEndian } ;
399
+ use std:: sync:: atomic:: ATOMIC_USIZE_INIT ;
366
400
367
401
use super :: * ;
368
402
403
+ static DEVICE_RESET_ENABLED : AtomicUsize = ATOMIC_USIZE_INIT ;
404
+
369
405
struct DummyDevice {
370
406
acked_features : u32 ,
407
+ interrupt_evt : Option < EventFd > ,
408
+ queue_evts : Option < Vec < EventFd > > ,
371
409
config_bytes : [ u8 ; 0xeff ] ,
372
410
}
373
411
374
412
impl DummyDevice {
375
413
fn new ( ) -> Self {
376
414
DummyDevice {
377
415
acked_features : 0 ,
416
+ interrupt_evt : None ,
417
+ queue_evts : None ,
378
418
config_bytes : [ 0 ; 0xeff ] ,
379
419
}
380
420
}
@@ -408,13 +448,26 @@ mod tests {
408
448
fn activate (
409
449
& mut self ,
410
450
_mem : GuestMemory ,
411
- _interrupt_evt : EventFd ,
451
+ interrupt_evt : EventFd ,
412
452
_status : Arc < AtomicUsize > ,
413
453
_queues : Vec < Queue > ,
414
- _queue_evts : Vec < EventFd > ,
454
+ queue_evts : Vec < EventFd > ,
415
455
) -> ActivateResult {
456
+ self . interrupt_evt = Some ( interrupt_evt) ;
457
+ self . queue_evts = Some ( queue_evts) ;
416
458
Ok ( ( ) )
417
459
}
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
+ }
418
471
}
419
472
420
473
fn set_driver_status ( d : & mut MmioDevice , status : u32 ) {
@@ -747,15 +800,68 @@ mod tests {
747
800
d. write ( 0x44 , & buf[ ..] ) ;
748
801
d. read ( 0x44 , & mut buf[ ..] ) ;
749
802
assert_eq ! ( LittleEndian :: read_u32( & buf[ ..] ) , 1 ) ;
803
+ }
750
804
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
751
846
LittleEndian :: write_u32 ( & mut buf[ ..] , 0x8f ) ;
752
847
d. write ( 0x70 , & buf[ ..] ) ;
753
848
assert_eq ! ( d. driver_status, 0x8f ) ;
754
- // TODO: assert!(d.device_activated);
849
+ assert ! ( d. device_activated) ;
755
850
851
+ // Nothing happens when backend driver doesn't support reset
852
+ DEVICE_RESET_ENABLED . store ( 0 , Ordering :: SeqCst ) ;
756
853
LittleEndian :: write_u32 ( & mut buf[ ..] , 0x0 ) ;
757
854
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) ;
760
866
}
761
867
}
0 commit comments