vhost: support virtqueue interrupt/notification suppression

The driver can suppress interrupt when VIRTIO_F_EVENT_IDX feature bit is
negotiated. The driver set vring flags to 0, and MAY use used_event in
available ring to advise device interrupt util reach an index specified
by used_event. The device ignore the lower bit of vring flags, and send
an interrupt when index reach used_event.

The device can suppress notification in a manner analogous to the ways
driver suppress interrupt. The device manipulates flags or avail_event in
the used ring in the same way the driver manipulates flags or used_event in
available ring.

Signed-off-by: Junjie Chen <junjie.j.chen@intel.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Tested-by: Lei Yao <lei.a.yao@intel.com>
Acked-by: Yuanhan Liu <yliu@fridaylinux.org>
This commit is contained in:
Junjie Chen 2018-01-09 06:03:48 -05:00 committed by Ferruh Yigit
parent 6a59d64719
commit e37ff95440
3 changed files with 43 additions and 9 deletions

View File

@ -509,7 +509,7 @@ rte_vhost_vring_call(int vid, uint16_t vring_idx)
if (!vq)
return -1;
vhost_vring_call(vq);
vhost_vring_call(dev, vq);
return 0;
}

View File

@ -74,6 +74,8 @@ struct vhost_virtqueue {
uint16_t last_avail_idx;
uint16_t last_used_idx;
/* Last used index we notify to front end. */
uint16_t signalled_used;
#define VIRTIO_INVALID_EVENTFD (-1)
#define VIRTIO_UNINITIALIZED_EVENTFD (-2)
@ -185,6 +187,7 @@ struct vhost_msg {
(1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
(1ULL << VIRTIO_NET_F_GUEST_UFO) | \
(1ULL << VIRTIO_RING_F_INDIRECT_DESC) | \
(1ULL << VIRTIO_RING_F_EVENT_IDX) | \
(1ULL << VIRTIO_NET_F_MTU) | \
(1ULL << VIRTIO_F_IOMMU_PLATFORM))
@ -370,16 +373,47 @@ vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
return __vhost_iova_to_vva(dev, vq, iova, size, perm);
}
#define vhost_used_event(vr) \
(*(volatile uint16_t*)&(vr)->avail->ring[(vr)->size])
/*
* The following is used with VIRTIO_RING_F_EVENT_IDX.
* Assuming a given event_idx value from the other size, if we have
* just incremented index from old to new_idx, should we trigger an
* event?
*/
static __rte_always_inline int
vhost_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
{
return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old);
}
static __rte_always_inline void
vhost_vring_call(struct vhost_virtqueue *vq)
vhost_vring_call(struct virtio_net *dev, struct vhost_virtqueue *vq)
{
/* Flush used->idx update before we read avail->flags. */
rte_mb();
/* Kick the guest if necessary. */
if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
&& (vq->callfd >= 0))
eventfd_write(vq->callfd, (eventfd_t)1);
/* Don't kick guest if we don't reach index specified by guest. */
if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
uint16_t old = vq->signalled_used;
uint16_t new = vq->last_used_idx;
LOG_DEBUG(VHOST_DATA, "%s: used_event_idx=%d, old=%d, new=%d\n",
__func__,
vhost_used_event(vq),
old, new);
if (vhost_need_event(vhost_used_event(vq), new, old)
&& (vq->callfd >= 0)) {
vq->signalled_used = vq->last_used_idx;
eventfd_write(vq->callfd, (eventfd_t) 1);
}
} else {
/* Kick the guest if necessary. */
if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
&& (vq->callfd >= 0))
eventfd_write(vq->callfd, (eventfd_t)1);
}
}
#endif /* _VHOST_NET_CDEV_H_ */

View File

@ -384,7 +384,7 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,
offsetof(struct vring_used, idx),
sizeof(vq->used->idx));
vhost_vring_call(vq);
vhost_vring_call(dev, vq);
out:
if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
vhost_user_iotlb_rd_unlock(vq);
@ -671,7 +671,7 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
if (likely(vq->shadow_used_idx)) {
flush_shadow_used_ring(dev, vq);
vhost_vring_call(vq);
vhost_vring_call(dev, vq);
}
out:
@ -1075,7 +1075,7 @@ update_used_idx(struct virtio_net *dev, struct vhost_virtqueue *vq,
vq->used->idx += count;
vhost_log_used_vring(dev, vq, offsetof(struct vring_used, idx),
sizeof(vq->used->idx));
vhost_vring_call(vq);
vhost_vring_call(dev, vq);
}
static __rte_always_inline struct zcopy_mbuf *