浏览代码

Merge pull request #69 from rcore-os/resetcleanup

Fix bugs with device and queue reset
Andrew Walbran 1 年之前
父节点
当前提交
4d90ab542f
共有 4 个文件被更改,包括 28 次插入11 次删除
  1. 4 0
      src/transport/fake.rs
  2. 9 0
      src/transport/mmio.rs
  3. 3 0
      src/transport/mod.rs
  4. 12 11
      src/transport/pci.rs

+ 4 - 0
src/transport/fake.rs

@@ -38,6 +38,10 @@ impl<C> Transport for FakeTransport<C> {
         self.state.lock().unwrap().queues[queue as usize].notified = true;
     }
 
+    fn get_status(&self) -> DeviceStatus {
+        self.state.lock().unwrap().status
+    }
+
     fn set_status(&mut self, status: DeviceStatus) {
         self.state.lock().unwrap().status = status;
     }

+ 9 - 0
src/transport/mmio.rs

@@ -350,6 +350,11 @@ impl Transport for MmioTransport {
         }
     }
 
+    fn get_status(&self) -> DeviceStatus {
+        // Safe because self.header points to a valid VirtIO MMIO region.
+        unsafe { volread!(self.header, status) }
+    }
+
     fn set_status(&mut self, status: DeviceStatus) {
         // Safe because self.header points to a valid VirtIO MMIO region.
         unsafe {
@@ -442,7 +447,11 @@ impl Transport for MmioTransport {
                 // Safe because self.header points to a valid VirtIO MMIO region.
                 unsafe {
                     volwrite!(self.header, queue_sel, queue.into());
+
                     volwrite!(self.header, queue_ready, 0);
+                    // Wait until we read the same value back, to ensure synchronisation (see 4.2.2.2).
+                    while volread!(self.header, queue_ready) != 0 {}
+
                     volwrite!(self.header, queue_num, 0);
                     volwrite!(self.header, queue_desc_low, 0);
                     volwrite!(self.header, queue_desc_high, 0);

+ 3 - 0
src/transport/mod.rs

@@ -26,6 +26,9 @@ pub trait Transport {
     /// Notifies the given queue on the device.
     fn notify(&mut self, queue: u16);
 
+    /// Gets the device status.
+    fn get_status(&self) -> DeviceStatus;
+
     /// Sets the device status.
     fn set_status(&mut self, status: DeviceStatus);
 

+ 12 - 11
src/transport/pci.rs

@@ -251,6 +251,13 @@ impl Transport for PciTransport {
         }
     }
 
+    fn get_status(&self) -> DeviceStatus {
+        // Safe because the common config pointer is valid and we checked in get_bar_region that it
+        // was aligned.
+        let status = unsafe { volread!(self.common_cfg, device_status) };
+        DeviceStatus::from_bits_truncate(status.into())
+    }
+
     fn set_status(&mut self, status: DeviceStatus) {
         // Safe because the common config pointer is valid and we checked in get_bar_region that it
         // was aligned.
@@ -287,16 +294,9 @@ impl Transport for PciTransport {
         }
     }
 
-    fn queue_unset(&mut self, queue: u16) {
-        // Safe because the common config pointer is valid and we checked in get_bar_region that it
-        // was aligned.
-        unsafe {
-            volwrite!(self.common_cfg, queue_select, queue);
-            volwrite!(self.common_cfg, queue_size, 0);
-            volwrite!(self.common_cfg, queue_desc, 0);
-            volwrite!(self.common_cfg, queue_driver, 0);
-            volwrite!(self.common_cfg, queue_device, 0);
-        }
+    fn queue_unset(&mut self, _queue: u16) {
+        // The VirtIO spec doesn't allow queues to be unset once they have been set up for the PCI
+        // transport, so this is a no-op.
     }
 
     fn queue_used(&mut self, queue: u16) -> bool {
@@ -341,7 +341,8 @@ impl Transport for PciTransport {
 impl Drop for PciTransport {
     fn drop(&mut self) {
         // Reset the device when the transport is dropped.
-        self.set_status(DeviceStatus::empty())
+        self.set_status(DeviceStatus::empty());
+        while self.get_status() != DeviceStatus::empty() {}
     }
 }