@@ -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);
@@ -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) {