]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat/virtio: Implement support for event index notification suppression
authorMarco Schlumpp <marco@unikraft.io>
Mon, 20 Feb 2023 13:57:00 +0000 (14:57 +0100)
committerRazvan Deaconescu <razvand@unikraft.io>
Fri, 20 Oct 2023 16:35:55 +0000 (19:35 +0300)
This allows the drivers/device to specify the other side should
send a notification. This is required for firecracker which does not
support the original notification suppression flag.

Signed-off-by: Marco Schlumpp <marco@unikraft.io>
Reviewed-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Andrei Tatar <andrei@unikraft.io>
Approved-by: Razvan Deaconescu <razvand@unikraft.io>
GitHub-Closes: #1089

drivers/virtio/include/virtio/virtqueue.h
drivers/virtio/net/virtio_net.c
drivers/virtio/ring/include/virtio/virtio_ring.h
drivers/virtio/ring/virtio_ring.c

index 731050554e29a8cb1933531638611cedbb0db961..f09c902af850648d28cb132f917bb270542d45b8 100644 (file)
@@ -66,6 +66,8 @@ struct virtqueue {
        virtqueue_callback_t vq_callback;
        /* Next entry of the queue */
        UK_TAILQ_ENTRY(struct virtqueue) next;
+       /* EVENT_IDX notification suppression is used */
+       __u8 uses_event_idx;
        /* Private data structure used by the driver of the queue */
        void *priv;
 };
index 539636feca393914d6938e65a437b94f141a3fe8..70144b1553ff799382783fc53e199db8dd296728 100644 (file)
@@ -974,6 +974,15 @@ static int virtio_netdev_feature_negotiate(struct uk_netdev *n)
        if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_NET_F_HOST_TSO4))
                VIRTIO_FEATURE_SET(drv_features, VIRTIO_NET_F_HOST_TSO4);
 
+       /**
+        * Use index based event supression when it's available.
+        * This allows a more fine-grained control when the hypervisor should
+        * notify the guest. Some hypervisors such as firecracker also do not
+        * support the original flag.
+        */
+       if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_F_EVENT_IDX))
+               VIRTIO_FEATURE_SET(drv_features, VIRTIO_F_EVENT_IDX);
+
        /**
         * Announce our enabled driver features back to the backend device
         */
index 07fe21cd16c4bc81b71f5fe9a07a0ab04682962e..e5da3afeb573efc264b73897170e7db96a5e3b4b 100644 (file)
@@ -169,7 +169,8 @@ static inline void vring_init(struct vring *vr, unsigned int num, uint8_t *p,
        vr->avail = (struct vring_avail *) (p +
                        num * sizeof(struct vring_desc));
        vr->used = (void *)
-       (((unsigned long) &vr->avail->ring[num] + align - 1) & ~(align - 1));
+               (((unsigned long) &vr->avail->ring[num] + sizeof(uint16_t) +
+                       align - 1) & ~(align - 1));
 }
 
 static inline unsigned int vring_size(unsigned int num, unsigned long align)
@@ -188,7 +189,8 @@ static inline unsigned int vring_size(unsigned int num, unsigned long align)
 static inline int vring_need_event(__u16 event_idx, __u16 new_idx,
                                   __u16 old_idx)
 {
-       return (new_idx - event_idx - 1) < (new_idx - old_idx);
+       return (uint16_t)(new_idx - event_idx - 1) <
+               (uint16_t)(new_idx - old_idx);
 }
 
 #ifdef __cplusplus
index f593373857b857f8558c6cacf14dc3c9cb02e5e9..17453d7d2ff23ef47d3456fc8b2c549a0a484bd5 100644 (file)
@@ -43,6 +43,7 @@
 #include <uk/plat/io.h>
 #include <virtio/virtio_ring.h>
 #include <virtio/virtqueue.h>
+#include <virtio/virtio_bus.h>
 #ifdef CONFIG_LIBUKVMEM
 #include <uk/arch/paging.h>
 #include <uk/plat/paging.h>
@@ -101,6 +102,12 @@ void virtqueue_intr_disable(struct virtqueue *vq)
        UK_ASSERT(vq);
 
        vrq = to_virtqueue_vring(vq);
+
+       if (vq->uses_event_idx) {
+               vring_used_event(&vrq->vring) =
+                       vrq->last_used_desc_idx - vrq->vring.num - 1;
+               return;
+       }
        vrq->vring.avail->flags |= (VRING_AVAIL_F_NO_INTERRUPT);
 }
 
@@ -114,24 +121,33 @@ int virtqueue_intr_enable(struct virtqueue *vq)
        vrq = to_virtqueue_vring(vq);
        /* Check if there are no more packets enabled */
        if (!virtqueue_hasdata(vq)) {
-               if (vrq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
+               if (vq->uses_event_idx) {
+                       /* TODO: This allows delaying the interrupts by a
+                        *       adjustable count of descriptors. This is could
+                        *       be useful for TXQ interrupts, which can be
+                        *       handled in a batched fashion.
+                        */
+                       vring_used_event(&vrq->vring) =
+                           vrq->last_used_desc_idx + 0;
+               } else {
                        vrq->vring.avail->flags &=
                                (~VRING_AVAIL_F_NO_INTERRUPT);
-                       /**
-                        * We enabled the interrupts. We ensure it using the
-                        * memory barrier and check if there are any further
-                        * data available in the queue. The check for data
-                        * after enabling the interrupt is to make sure we do
-                        * not miss any interrupt while transitioning to enable
-                        * interrupt. This is inline with the requirement from
-                        * virtio specification section 3.2.2
-                        */
-                       mb();
-                       /* Check if there are further descriptors */
-                       if (virtqueue_hasdata(vq)) {
-                               virtqueue_intr_disable(vq);
-                               rc = 1;
-                       }
+               }
+
+               /**
+                * We enabled the interrupts. We ensure it using the
+                * memory barrier and check if there are any further
+                * data available in the queue. The check for data
+                * after enabling the interrupt is to make sure we do
+                * not miss any interrupt while transitioning to enable
+                * interrupt. This is inline with the requirement from
+                * virtio specification section 3.2.2
+                */
+               mb();
+               /* Check if there are further descriptors */
+               if (virtqueue_hasdata(vq)) {
+                       virtqueue_intr_disable(vq);
+                       rc = 1;
                }
        } else {
                /**
@@ -186,9 +202,21 @@ static inline void virtqueue_detach_desc(struct virtqueue_vring *vrq,
 int virtqueue_notify_enabled(struct virtqueue *vq)
 {
        struct virtqueue_vring *vrq;
+       uint16_t old, new;
 
        UK_ASSERT(vq);
        vrq = to_virtqueue_vring(vq);
+       if (vq->uses_event_idx) {
+               new = vrq->vring.avail->idx;
+               /* TODO: Use the actually submitted count instead of assuming
+                *       that a single descriptor was submitted. This would be
+                *       more efficient when we would have batching implemented.
+                */
+               old = new - 1;
+
+               return vring_need_event(vring_avail_event(&vrq->vring),
+                                       new, old);
+       }
 
        return ((vrq->vring.used->flags & VRING_USED_F_NO_NOTIFY) == 0);
 }
@@ -235,6 +263,8 @@ __u64 virtqueue_feature_negotiate(__u64 feature_set)
 
        /* Allow version 1 flag */
        feature |= 1ULL << VIRTIO_F_VERSION_1;
+       /* Allow event index feature */
+       feature |= 1ULL << VIRTIO_F_EVENT_IDX;
 
        feature &= feature_set;
        return feature;
@@ -451,6 +481,8 @@ struct virtqueue *virtqueue_create(__u16 queue_id, __u16 nr_descs, __u16 align,
        vq->vdev = vdev;
        vq->vq_callback = callback;
        vq->vq_notify_host = notify;
+       vq->uses_event_idx =
+           VIRTIO_FEATURE_HAS(vdev->features, VIRTIO_F_EVENT_IDX);
        return vq;
 
 err_freevq: