virtio: access ISR atomically

This will be needed once dataplane will be able to set it outside
the big QEMU lock.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: Farhan Ali <alifm@linux.vnet.ibm.com>
Tested-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Paolo Bonzini 2016-11-18 16:07:01 +01:00 committed by Michael S. Tsirkin
parent 310837de6c
commit 0687c37c5e
3 changed files with 23 additions and 14 deletions

View file

@ -191,7 +191,7 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
return virtio_queue_get_addr(vdev, vdev->queue_sel) return virtio_queue_get_addr(vdev, vdev->queue_sel)
>> proxy->guest_page_shift; >> proxy->guest_page_shift;
case VIRTIO_MMIO_INTERRUPTSTATUS: case VIRTIO_MMIO_INTERRUPTSTATUS:
return vdev->isr; return atomic_read(&vdev->isr);
case VIRTIO_MMIO_STATUS: case VIRTIO_MMIO_STATUS:
return vdev->status; return vdev->status;
case VIRTIO_MMIO_HOSTFEATURESSEL: case VIRTIO_MMIO_HOSTFEATURESSEL:
@ -299,7 +299,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
} }
break; break;
case VIRTIO_MMIO_INTERRUPTACK: case VIRTIO_MMIO_INTERRUPTACK:
vdev->isr &= ~value; atomic_and(&vdev->isr, ~value);
virtio_update_irq(vdev); virtio_update_irq(vdev);
break; break;
case VIRTIO_MMIO_STATUS: case VIRTIO_MMIO_STATUS:
@ -347,7 +347,7 @@ static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
if (!vdev) { if (!vdev) {
return; return;
} }
level = (vdev->isr != 0); level = (atomic_read(&vdev->isr) != 0);
DPRINTF("virtio_mmio setting IRQ %d\n", level); DPRINTF("virtio_mmio setting IRQ %d\n", level);
qemu_set_irq(proxy->irq, level); qemu_set_irq(proxy->irq, level);
} }

View file

@ -73,7 +73,7 @@ static void virtio_pci_notify(DeviceState *d, uint16_t vector)
msix_notify(&proxy->pci_dev, vector); msix_notify(&proxy->pci_dev, vector);
else { else {
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
pci_set_irq(&proxy->pci_dev, vdev->isr & 1); pci_set_irq(&proxy->pci_dev, atomic_read(&vdev->isr) & 1);
} }
} }
@ -449,8 +449,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
break; break;
case VIRTIO_PCI_ISR: case VIRTIO_PCI_ISR:
/* reading from the ISR also clears it. */ /* reading from the ISR also clears it. */
ret = vdev->isr; ret = atomic_xchg(&vdev->isr, 0);
vdev->isr = 0;
pci_irq_deassert(&proxy->pci_dev); pci_irq_deassert(&proxy->pci_dev);
break; break;
case VIRTIO_MSI_CONFIG_VECTOR: case VIRTIO_MSI_CONFIG_VECTOR:
@ -1379,9 +1378,7 @@ static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
{ {
VirtIOPCIProxy *proxy = opaque; VirtIOPCIProxy *proxy = opaque;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
uint64_t val = vdev->isr; uint64_t val = atomic_xchg(&vdev->isr, 0);
vdev->isr = 0;
pci_irq_deassert(&proxy->pci_dev); pci_irq_deassert(&proxy->pci_dev);
return val; return val;

View file

@ -945,7 +945,7 @@ void virtio_reset(void *opaque)
vdev->guest_features = 0; vdev->guest_features = 0;
vdev->queue_sel = 0; vdev->queue_sel = 0;
vdev->status = 0; vdev->status = 0;
vdev->isr = 0; atomic_set(&vdev->isr, 0);
vdev->config_vector = VIRTIO_NO_VECTOR; vdev->config_vector = VIRTIO_NO_VECTOR;
virtio_notify_vector(vdev, vdev->config_vector); virtio_notify_vector(vdev, vdev->config_vector);
@ -1318,10 +1318,22 @@ void virtio_del_queue(VirtIODevice *vdev, int n)
vdev->vq[n].vring.num_default = 0; vdev->vq[n].vring.num_default = 0;
} }
static void virtio_set_isr(VirtIODevice *vdev, int value)
{
uint8_t old = atomic_read(&vdev->isr);
/* Do not write ISR if it does not change, so that its cacheline remains
* shared in the common case where the guest does not read it.
*/
if ((old & value) != value) {
atomic_or(&vdev->isr, value);
}
}
void virtio_irq(VirtQueue *vq) void virtio_irq(VirtQueue *vq)
{ {
trace_virtio_irq(vq); trace_virtio_irq(vq);
vq->vdev->isr |= 0x01; virtio_set_isr(vq->vdev, 0x1);
virtio_notify_vector(vq->vdev, vq->vector); virtio_notify_vector(vq->vdev, vq->vector);
} }
@ -1355,7 +1367,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
} }
trace_virtio_notify(vdev, vq); trace_virtio_notify(vdev, vq);
vdev->isr |= 0x01; virtio_set_isr(vq->vdev, 0x1);
virtio_notify_vector(vdev, vq->vector); virtio_notify_vector(vdev, vq->vector);
} }
@ -1364,7 +1376,7 @@ void virtio_notify_config(VirtIODevice *vdev)
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
return; return;
vdev->isr |= 0x03; virtio_set_isr(vdev, 0x3);
vdev->generation++; vdev->generation++;
virtio_notify_vector(vdev, vdev->config_vector); virtio_notify_vector(vdev, vdev->config_vector);
} }
@ -1895,7 +1907,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
vdev->device_id = device_id; vdev->device_id = device_id;
vdev->status = 0; vdev->status = 0;
vdev->isr = 0; atomic_set(&vdev->isr, 0);
vdev->queue_sel = 0; vdev->queue_sel = 0;
vdev->config_vector = VIRTIO_NO_VECTOR; vdev->config_vector = VIRTIO_NO_VECTOR;
vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX); vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX);