Bläddra i källkod

Merge pull request #54 from rcore-os/notify

Support available buffer notification suppression, and send notifications for console and input
Andrew Walbran 2 år sedan
förälder
incheckning
4461c73a37
4 ändrade filer med 31 tillägg och 3 borttagningar
  1. 6 2
      src/device/blk.rs
  2. 3 0
      src/device/console.rs
  3. 6 0
      src/device/input.rs
  4. 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)
     }
 

+ 3 - 0
src/device/console.rs

@@ -119,6 +119,9 @@ impl<H: Hal, T: Transport> VirtIOConsole<'_, H, T> {
             // Safe because the buffer lasts at least as long as the queue, and there are no other
             // outstanding requests using the buffer.
             self.receive_token = Some(unsafe { self.receiveq.add(&[], &[self.queue_buf_rx]) }?);
+            if self.receiveq.should_notify() {
+                self.transport.notify(QUEUE_RECEIVEQ_PORT_0);
+            }
         }
         Ok(())
     }

+ 6 - 0
src/device/input.rs

@@ -45,6 +45,9 @@ impl<H: Hal, T: Transport> VirtIOInput<H, T> {
             let token = unsafe { event_queue.add(&[], &[event.as_bytes_mut()])? };
             assert_eq!(token, i as u16);
         }
+        if event_queue.should_notify() {
+            transport.notify(QUEUE_EVENT);
+        }
 
         transport.finish_init();
 
@@ -76,6 +79,9 @@ impl<H: Hal, T: Transport> VirtIOInput<H, T> {
                 // the list of free descriptors in the queue, so `add` reuses the descriptor which
                 // was just freed by `pop_used`.
                 assert_eq!(new_token, token);
+                if self.event_queue.should_notify() {
+                    self.transport.notify(QUEUE_EVENT);
+                }
                 return Some(*event);
             }
         }

+ 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.