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:
parent
6a59d64719
commit
e37ff95440
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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 *
|
||||
|
Loading…
Reference in New Issue
Block a user