diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/msix.c | 44 | ||||
-rw-r--r-- | hw/msix.h | 2 | ||||
-rw-r--r-- | hw/virtio-pci.c | 93 |
3 files changed, 139 insertions, 0 deletions
@@ -587,3 +587,47 @@ void msix_unuse_all_vectors(PCIDevice *dev) return; msix_free_irq_entries(dev); } + +int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque) +{ + int r; + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) + return 0; + + assert(dev->msix_mask_notifier); + assert(opaque); + assert(!dev->msix_mask_notifier_opaque[vector]); + + if (msix_is_masked(dev, vector)) { + return 0; + } + r = dev->msix_mask_notifier(dev, vector, opaque, + msix_is_masked(dev, vector)); + if (r < 0) { + return r; + } + dev->msix_mask_notifier_opaque[vector] = opaque; + return r; +} + +int msix_unset_mask_notifier(PCIDevice *dev, unsigned vector) +{ + int r = 0; + if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) + return 0; + + assert(dev->msix_mask_notifier); + assert(dev->msix_mask_notifier_opaque[vector]); + + if (msix_is_masked(dev, vector)) { + return 0; + } + r = dev->msix_mask_notifier(dev, vector, + dev->msix_mask_notifier_opaque[vector], + msix_is_masked(dev, vector)); + if (r < 0) { + return r; + } + dev->msix_mask_notifier_opaque[vector] = NULL; + return r; +} @@ -33,4 +33,6 @@ void msix_reset(PCIDevice *dev); extern int msix_supported; +int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque); +int msix_unset_mask_notifier(PCIDevice *dev, unsigned vector); #endif 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 = { |