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:
parent
9d5a807c4c
commit
cf39b82860
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user