diff options
Diffstat (limited to 'hw/virtio-pci.c')
-rw-r--r-- | hw/virtio-pci.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 359415226..59609476d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -382,11 +382,104 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, static unsigned virtio_pci_get_features(void *opaque) { +<<<<<<< HEAD unsigned ret = 0; ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC); ret |= (1 << VIRTIO_F_BAD_FEATURE); return ret; +======= + VirtIOPCIProxy *proxy = opaque; + return proxy->host_features; +} + +static void virtio_pci_guest_notifier_read(void *opaque) +{ + VirtQueue *vq = opaque; + EventNotifier *n = virtio_queue_get_guest_notifier(vq); + if (event_notifier_test_and_clear(n)) { + virtio_irq(vq); + } +} + +static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector, + void *opaque, int masked) +{ + VirtQueue *vq = opaque; + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi, + event_notifier_get_fd(notifier), + !masked); + if (r < 0) { + return (r == -ENOSYS) ? 0 : r; + } + if (masked) { + qemu_set_fd_handler(event_notifier_get_fd(notifier), + virtio_pci_guest_notifier_read, NULL, vq); + } else { + qemu_set_fd_handler(event_notifier_get_fd(notifier), + NULL, NULL, NULL); + } + return 0; +} + +static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) +{ + VirtIOPCIProxy *proxy = opaque; + VirtQueue *vq = virtio_get_queue(proxy->vdev, n); + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + + if (assign) { + int r = event_notifier_init(notifier, 0); + if (r < 0) { + return r; + } + qemu_set_fd_handler(event_notifier_get_fd(notifier), + virtio_pci_guest_notifier_read, NULL, vq); + msix_set_mask_notifier(&proxy->pci_dev, + virtio_queue_vector(proxy->vdev, n), vq); + } else { + msix_unset_mask_notifier(&proxy->pci_dev, + virtio_queue_vector(proxy->vdev, n)); + qemu_set_fd_handler(event_notifier_get_fd(notifier), + NULL, NULL, NULL); + /* Test and clear notifier before closing it, + * in case poll callback didn't have time to run. */ + virtio_pci_guest_notifier_read(vq); + event_notifier_cleanup(notifier); + } + + return 0; +} + +static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign) +{ + VirtIOPCIProxy *proxy = opaque; + VirtQueue *vq = virtio_get_queue(proxy->vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + int r; + if (assign) { + r = event_notifier_init(notifier, 1); + if (r < 0) { + return r; + } + r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier), + proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY, + n, assign); + if (r < 0) { + event_notifier_cleanup(notifier); + } + } else { + r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier), + proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY, + n, assign); + if (r < 0) { + return r; + } + event_notifier_cleanup(notifier); + } + return r; +>>>>>>> 992cc81... qemu-kvm: fix crash on reboot with vhost-net } static const VirtIOBindings virtio_pci_bindings = { |