From 0687c37c5eeef8580b31cc6e1202d874833ae38a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 18 Nov 2016 16:07:01 +0100 Subject: [PATCH] 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 Tested-by: Farhan Ali Tested-by: Alex Williamson Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mmio.c | 6 +++--- hw/virtio/virtio-pci.c | 9 +++------ hw/virtio/virtio.c | 22 +++++++++++++++++----- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index a30270f902..17412cb7b5 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -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) >> proxy->guest_page_shift; case VIRTIO_MMIO_INTERRUPTSTATUS: - return vdev->isr; + return atomic_read(&vdev->isr); case VIRTIO_MMIO_STATUS: return vdev->status; case VIRTIO_MMIO_HOSTFEATURESSEL: @@ -299,7 +299,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, } break; case VIRTIO_MMIO_INTERRUPTACK: - vdev->isr &= ~value; + atomic_and(&vdev->isr, ~value); virtio_update_irq(vdev); break; case VIRTIO_MMIO_STATUS: @@ -347,7 +347,7 @@ static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector) if (!vdev) { return; } - level = (vdev->isr != 0); + level = (atomic_read(&vdev->isr) != 0); DPRINTF("virtio_mmio setting IRQ %d\n", level); qemu_set_irq(proxy->irq, level); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 97b32febaf..521ba0b415 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -73,7 +73,7 @@ static void virtio_pci_notify(DeviceState *d, uint16_t vector) msix_notify(&proxy->pci_dev, vector); else { 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; case VIRTIO_PCI_ISR: /* reading from the ISR also clears it. */ - ret = vdev->isr; - vdev->isr = 0; + ret = atomic_xchg(&vdev->isr, 0); pci_irq_deassert(&proxy->pci_dev); break; case VIRTIO_MSI_CONFIG_VECTOR: @@ -1379,9 +1378,7 @@ static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr, { VirtIOPCIProxy *proxy = opaque; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - uint64_t val = vdev->isr; - - vdev->isr = 0; + uint64_t val = atomic_xchg(&vdev->isr, 0); pci_irq_deassert(&proxy->pci_dev); return val; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index b7d5828601..138a414cbe 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -945,7 +945,7 @@ void virtio_reset(void *opaque) vdev->guest_features = 0; vdev->queue_sel = 0; vdev->status = 0; - vdev->isr = 0; + atomic_set(&vdev->isr, 0); vdev->config_vector = VIRTIO_NO_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; } +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) { trace_virtio_irq(vq); - vq->vdev->isr |= 0x01; + virtio_set_isr(vq->vdev, 0x1); virtio_notify_vector(vq->vdev, vq->vector); } @@ -1355,7 +1367,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq) } trace_virtio_notify(vdev, vq); - vdev->isr |= 0x01; + virtio_set_isr(vq->vdev, 0x1); virtio_notify_vector(vdev, vq->vector); } @@ -1364,7 +1376,7 @@ void virtio_notify_config(VirtIODevice *vdev) if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) return; - vdev->isr |= 0x03; + virtio_set_isr(vdev, 0x3); vdev->generation++; 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->status = 0; - vdev->isr = 0; + atomic_set(&vdev->isr, 0); vdev->queue_sel = 0; vdev->config_vector = VIRTIO_NO_VECTOR; vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX); -- 2.11.4.GIT