Browse Source

Suppress available buffer notifications if the device asks to.

Andrew Walbran 2 years ago
parent
commit
4b6045b8f3
2 changed files with 22 additions and 3 deletions
  1. 6 2
      src/device/blk.rs
  2. 16 1
      src/queue.rs

+ 6 - 2
src/device/blk.rs

@@ -188,7 +188,9 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
         let token = self
             .queue
             .add(&[req.as_bytes()], &[buf, resp.as_bytes_mut()])?;
-        self.transport.notify(QUEUE);
+        if self.queue.should_notify() {
+            self.transport.notify(QUEUE);
+        }
         Ok(token)
     }
 
@@ -267,7 +269,9 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
         let token = self
             .queue
             .add(&[req.as_bytes(), buf], &[resp.as_bytes_mut()])?;
-        self.transport.notify(QUEUE);
+        if self.queue.should_notify() {
+            self.transport.notify(QUEUE);
+        }
         Ok(token)
     }
 

+ 16 - 1
src/queue.rs

@@ -167,7 +167,9 @@ impl<H: Hal, const SIZE: usize> VirtQueue<H, SIZE> {
         let token = unsafe { self.add(inputs, outputs) }?;
 
         // Notify the queue.
-        transport.notify(self.queue_idx);
+        if self.should_notify() {
+            transport.notify(self.queue_idx);
+        }
 
         // Wait until there is at least one element in the used ring.
         while !self.can_pop() {
@@ -177,6 +179,19 @@ impl<H: Hal, const SIZE: usize> VirtQueue<H, SIZE> {
         self.pop_used(token, inputs, outputs)
     }
 
+    /// Returns whether the driver should notify the device after adding a new buffer to the
+    /// virtqueue.
+    ///
+    /// This will be false if the device has supressed notifications.
+    pub fn should_notify(&self) -> bool {
+        // Read barrier, so we read a fresh value from the device.
+        fence(Ordering::SeqCst);
+
+        // Safe because self.used points to a valid, aligned, initialised, dereferenceable, readable
+        // instance of UsedRing.
+        unsafe { (*self.used.as_ptr()).flags & 0x0001 == 0 }
+    }
+
     /// Returns a non-null pointer to the descriptor at the given index.
     fn desc_ptr(&mut self, index: u16) -> *mut Descriptor {
         // Safe because self.desc is properly aligned and dereferenceable.