virtio: virtqueue_ordered_fill - VIRTIO_F_IN_ORDER support

Add VIRTIO_F_IN_ORDER feature support for the virtqueue_fill operation.

The goal of the virtqueue_ordered_fill operation when the
VIRTIO_F_IN_ORDER feature has been negotiated is to search for this
now-used element, set its length, and mark the element as filled in
the VirtQueue's used_elems array.

By marking the element as filled, it will indicate that this element has
been processed and is ready to be flushed, so long as the element is
in-order.

Reviewed-by: Eugenio Pérez <eperezma@redhat.com>
Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
Message-Id: <20240710125522.4168043-4-jonah.palmer@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Jonah Palmer 2024-07-10 08:55:16 -04:00 committed by Michael S. Tsirkin
parent 2256e8482b
commit b44135daa3

View File

@ -872,6 +872,46 @@ static void virtqueue_packed_fill(VirtQueue *vq, const VirtQueueElement *elem,
vq->used_elems[idx].ndescs = elem->ndescs;
}
static void virtqueue_ordered_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len)
{
unsigned int i, steps, max_steps;
i = vq->used_idx % vq->vring.num;
steps = 0;
/*
* We shouldn't need to increase 'i' by more than the distance
* between used_idx and last_avail_idx.
*/
max_steps = (vq->last_avail_idx - vq->used_idx) % vq->vring.num;
/* Search for element in vq->used_elems */
while (steps <= max_steps) {
/* Found element, set length and mark as filled */
if (vq->used_elems[i].index == elem->index) {
vq->used_elems[i].len = len;
vq->used_elems[i].in_order_filled = true;
break;
}
i += vq->used_elems[i].ndescs;
steps += vq->used_elems[i].ndescs;
if (i >= vq->vring.num) {
i -= vq->vring.num;
}
}
/*
* We should be able to find a matching VirtQueueElement in
* used_elems. If we don't, this is an error.
*/
if (steps >= max_steps) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: %s cannot fill buffer id %u\n",
__func__, vq->vdev->name, elem->index);
}
}
static void virtqueue_packed_fill_desc(VirtQueue *vq,
const VirtQueueElement *elem,
unsigned int idx,
@ -922,7 +962,9 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
return;
}
if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_IN_ORDER)) {
virtqueue_ordered_fill(vq, elem, len);
} else if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
virtqueue_packed_fill(vq, elem, len, idx);
} else {
virtqueue_split_fill(vq, elem, len, idx);