aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-07-05 17:16:30 +0200
committerAvi Kivity <avi@redhat.com>2012-07-12 14:08:11 +0300
commit15b2bd1847239fe0b4a1041b69a631741d2e273a (patch)
tree36b395a7ea3642442e9f45ec4280013ca56ae033
parentb1f416aa8d870fab71030abc9401cfc77b948e8e (diff)
virtio: move common irqfd handling out of virtio-pci
All transports can use the same event handler for the irqfd, though the exact mechanics of the assignment will be specific. Note that there are three states: handled by the kernel, handled in userspace, disabled. This also lets virtio use event_notifier_set_handler. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--hw/virtio-pci.c37
-rw-r--r--hw/virtio.c24
-rw-r--r--hw/virtio.h2
-rw-r--r--kvm-all.c10
-rw-r--r--kvm-stub.c10
-rw-r--r--kvm.h2
6 files changed, 58 insertions, 27 deletions
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 36770fd8f7..a66c946f48 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -496,25 +496,15 @@ static unsigned virtio_pci_get_features(void *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 kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
unsigned int queue_no,
unsigned int vector,
MSIMessage msg)
{
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+ EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- int fd, ret;
-
- fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vq));
+ int ret;
if (irqfd->users == 0) {
ret = kvm_irqchip_add_msi_route(kvm_state, msg);
@@ -525,7 +515,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
}
irqfd->users++;
- ret = kvm_irqchip_add_irqfd(kvm_state, fd, irqfd->virq);
+ ret = kvm_irqchip_add_irq_notifier(kvm_state, n, irqfd->virq);
if (ret < 0) {
if (--irqfd->users == 0) {
kvm_irqchip_release_virq(kvm_state, irqfd->virq);
@@ -533,8 +523,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
return ret;
}
- qemu_set_fd_handler(fd, NULL, NULL, NULL);
-
+ virtio_queue_set_guest_notifier_fd_handler(vq, true, true);
return 0;
}
@@ -543,19 +532,18 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
unsigned int vector)
{
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+ EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- int fd, ret;
-
- fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vq));
+ int ret;
- ret = kvm_irqchip_remove_irqfd(kvm_state, fd, irqfd->virq);
+ ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq);
assert(ret == 0);
if (--irqfd->users == 0) {
kvm_irqchip_release_virq(kvm_state, irqfd->virq);
}
- qemu_set_fd_handler(fd, virtio_pci_guest_notifier_read, NULL, vq);
+ virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
}
static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector,
@@ -617,14 +605,9 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
if (r < 0) {
return r;
}
- qemu_set_fd_handler(event_notifier_get_fd(notifier),
- virtio_pci_guest_notifier_read, NULL, vq);
+ virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
} else {
- 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);
+ virtio_queue_set_guest_notifier_fd_handler(vq, false, false);
event_notifier_cleanup(notifier);
}
diff --git a/hw/virtio.c b/hw/virtio.c
index 197edf00f4..d146f86f13 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -984,6 +984,30 @@ VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
return vdev->vq + n;
}
+static void virtio_queue_guest_notifier_read(EventNotifier *n)
+{
+ VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
+ if (event_notifier_test_and_clear(n)) {
+ virtio_irq(vq);
+ }
+}
+
+void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
+ bool with_irqfd)
+{
+ if (assign && !with_irqfd) {
+ event_notifier_set_handler(&vq->guest_notifier,
+ virtio_queue_guest_notifier_read);
+ } else {
+ event_notifier_set_handler(&vq->guest_notifier, NULL);
+ }
+ if (!assign) {
+ /* Test and clear notifier before closing it,
+ * in case poll callback didn't have time to run. */
+ virtio_queue_guest_notifier_read(&vq->guest_notifier);
+ }
+}
+
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{
return &vq->guest_notifier;
diff --git a/hw/virtio.h b/hw/virtio.h
index 294948519c..96f4dbb8d9 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -231,6 +231,8 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
int virtio_queue_get_id(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
+void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
+ bool with_irqfd);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign);
void virtio_queue_notify_vq(VirtQueue *vq);
diff --git a/kvm-all.c b/kvm-all.c
index 5a386b45f9..add24a14a9 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1163,11 +1163,21 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
return kvm_irqchip_assign_irqfd(s, fd, virq, true);
}
+int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq)
+{
+ return kvm_irqchip_add_irqfd(s, event_notifier_get_fd(n), virq);
+}
+
int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
{
return kvm_irqchip_assign_irqfd(s, fd, virq, false);
}
+int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
+{
+ return kvm_irqchip_remove_irqfd(s, event_notifier_get_fd(n), virq);
+}
+
static int kvm_irqchip_create(KVMState *s)
{
QemuOptsList *list = qemu_find_opts("machine");
diff --git a/kvm-stub.c b/kvm-stub.c
index ec9a36454d..d23b11c020 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -147,7 +147,17 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
return -ENOSYS;
}
+int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq)
+{
+ return -ENOSYS;
+}
+
int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
{
return -ENOSYS;
}
+
+int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
+{
+ return -ENOSYS;
+}
diff --git a/kvm.h b/kvm.h
index 9c7b0ea6ae..99003f459a 100644
--- a/kvm.h
+++ b/kvm.h
@@ -218,4 +218,6 @@ void kvm_irqchip_release_virq(KVMState *s, int virq);
int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq);
int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq);
+int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq);
+int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq);
#endif