aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/msix.c44
-rw-r--r--hw/msix.h2
-rw-r--r--hw/virtio-pci.c93
3 files changed, 139 insertions, 0 deletions
diff --git a/hw/msix.c b/hw/msix.c
index d117bcfaa..bbd54ec95 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -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;
+}
diff --git a/hw/msix.h b/hw/msix.h
index a9f7993c3..6b21ffb5d 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -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 = {