@@ -51,6 +51,9 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
}
+ if (!(net->dev.features & (1 << VIRTIO_RING_F_PUBLISH_USED))) {
+ features &= ~(1 << VIRTIO_RING_F_PUBLISH_USED);
+ }
features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
return features;
}
@@ -64,6 +67,9 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features)
if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
}
+ if (features & (1 << VIRTIO_RING_F_PUBLISH_USED)) {
+ net->dev.acked_features |= (1 << VIRTIO_RING_F_PUBLISH_USED);
+ }
}
static int vhost_net_get_fd(VLANClientState *backend)
@@ -71,6 +71,7 @@ struct VirtQueue
target_phys_addr_t pa;
uint16_t last_avail_idx;
int inuse;
+ int num_notify;
uint16_t vector;
void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
VirtIODevice *vdev;
@@ -139,6 +140,11 @@ static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
return lduw_phys(pa);
}
+static inline uint16_t vring_last_used_idx(VirtQueue *vq)
+{
+ return vring_avail_ring(vq, vq->vring.num);
+}
+
static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
{
target_phys_addr_t pa;
@@ -234,6 +240,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
wmb();
vring_used_idx_increment(vq, count);
vq->inuse -= count;
+ vq->num_notify += count;
}
void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
@@ -603,6 +610,14 @@ void virtio_irq(VirtQueue *vq)
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
{
+ /* Do not notify if guest did not yet see the last update. */
+ if ((vdev->guest_features & (1 << VIRTIO_RING_F_PUBLISH_USED)) &&
+ vring_last_used_idx(vq) !=
+ (uint16_t)(vring_used_idx(vq) + vq->num_notify))
+ return;
+
+ vq->num_notify = 0;
+
/* Always notify when queue is empty (when feature acknowledge) */
if ((vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT) &&
(!(vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) ||
@@ -43,6 +43,8 @@
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
/* We support indirect buffer descriptors */
#define VIRTIO_RING_F_INDIRECT_DESC 28
+/* The Guest publishes last-seen used index at the end of the avail ring. */
+#define VIRTIO_RING_F_PUBLISH_USED 29
/* A guest should never accept this. It implies negotiation is broken. */
#define VIRTIO_F_BAD_FEATURE 30
@@ -189,6 +191,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev);
void virtio_net_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
+ DEFINE_PROP_BIT("publish_used", _state, _field, \
+ VIRTIO_RING_F_PUBLISH_USED, true), \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
VIRTIO_RING_F_INDIRECT_DESC, true)