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:
parent
310837de6c
commit
0687c37c5e
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue