virtio/virtio-pci: Handle extra notification data

Add support to virtio-pci devices for handling the extra data sent
from the driver to the device when the VIRTIO_F_NOTIFICATION_DATA
transport feature has been negotiated.

The extra data that's passed to the virtio-pci device when this
feature is enabled varies depending on the device's virtqueue
layout.

In a split virtqueue layout, this data includes:
 - upper 16 bits: shadow_avail_idx
 - lower 16 bits: virtqueue index

In a packed virtqueue layout, this data includes:
 - upper 16 bits: 1-bit wrap counter & 15-bit shadow_avail_idx
 - lower 16 bits: virtqueue index

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
Message-Id: <20240315165557.26942-2-jonah.palmer@oracle.com>
Reviewed-by: Eugenio Pérez <eperezma@redhat.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-03-15 12:55:52 -04:00 committed by Michael S. Tsirkin
parent 9d5a807c4c
commit cf39b82860
3 changed files with 29 additions and 3 deletions

View File

@ -384,7 +384,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
VirtIOPCIProxy *proxy = opaque;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
uint16_t vector;
uint16_t vector, vq_idx;
hwaddr pa;
switch (addr) {
@ -408,8 +408,14 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
vdev->queue_sel = val;
break;
case VIRTIO_PCI_QUEUE_NOTIFY:
if (val < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, val);
vq_idx = val;
if (vq_idx < VIRTIO_QUEUE_MAX && virtio_queue_get_num(vdev, vq_idx)) {
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
VirtQueue *vq = virtio_get_queue(vdev, vq_idx);
virtio_queue_set_shadow_avail_idx(vq, val >> 16);
}
virtio_queue_notify(vdev, vq_idx);
}
break;
case VIRTIO_PCI_STATUS:

View File

@ -2264,6 +2264,24 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
}
}
void virtio_queue_set_shadow_avail_idx(VirtQueue *vq, uint16_t shadow_avail_idx)
{
if (!vq->vring.desc) {
return;
}
/*
* 16-bit data for packed VQs include 1-bit wrap counter and
* 15-bit shadow_avail_idx.
*/
if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
vq->shadow_avail_wrap_counter = (shadow_avail_idx >> 15) & 0x1;
vq->shadow_avail_idx = shadow_avail_idx & 0x7FFF;
} else {
vq->shadow_avail_idx = shadow_avail_idx;
}
}
static void virtio_queue_notify_vq(VirtQueue *vq)
{
if (vq->vring.desc && vq->handle_output) {

View File

@ -307,6 +307,8 @@ int virtio_queue_ready(VirtQueue *vq);
int virtio_queue_empty(VirtQueue *vq);
void virtio_queue_set_shadow_avail_idx(VirtQueue *vq, uint16_t idx);
/* Host binding interface. */
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);