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>
This commit is contained in:
Paolo Bonzini 2012-07-05 17:16:30 +02:00 committed by Avi Kivity
parent b1f416aa8d
commit 15b2bd1847
6 changed files with 58 additions and 27 deletions

View file

@ -496,25 +496,15 @@ static unsigned virtio_pci_get_features(void *opaque)
return proxy->host_features; 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, static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
unsigned int queue_no, unsigned int queue_no,
unsigned int vector, unsigned int vector,
MSIMessage msg) MSIMessage msg)
{ {
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
int fd, ret; int ret;
fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vq));
if (irqfd->users == 0) { if (irqfd->users == 0) {
ret = kvm_irqchip_add_msi_route(kvm_state, msg); 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++; 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 (ret < 0) {
if (--irqfd->users == 0) { if (--irqfd->users == 0) {
kvm_irqchip_release_virq(kvm_state, irqfd->virq); kvm_irqchip_release_virq(kvm_state, irqfd->virq);
@ -533,8 +523,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
return ret; return ret;
} }
qemu_set_fd_handler(fd, NULL, NULL, NULL); virtio_queue_set_guest_notifier_fd_handler(vq, true, true);
return 0; return 0;
} }
@ -543,19 +532,18 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
unsigned int vector) unsigned int vector)
{ {
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
int fd, ret; int ret;
fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vq)); ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq);
ret = kvm_irqchip_remove_irqfd(kvm_state, fd, irqfd->virq);
assert(ret == 0); assert(ret == 0);
if (--irqfd->users == 0) { if (--irqfd->users == 0) {
kvm_irqchip_release_virq(kvm_state, irqfd->virq); 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, 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) { if (r < 0) {
return r; return r;
} }
qemu_set_fd_handler(event_notifier_get_fd(notifier), virtio_queue_set_guest_notifier_fd_handler(vq, true, false);
virtio_pci_guest_notifier_read, NULL, vq);
} else { } else {
qemu_set_fd_handler(event_notifier_get_fd(notifier), virtio_queue_set_guest_notifier_fd_handler(vq, false, false);
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); event_notifier_cleanup(notifier);
} }

View file

@ -984,6 +984,30 @@ VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
return vdev->vq + 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) EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{ {
return &vq->guest_notifier; return &vq->guest_notifier;

View file

@ -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); VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
int virtio_queue_get_id(VirtQueue *vq); int virtio_queue_get_id(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(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); EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign); void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign);
void virtio_queue_notify_vq(VirtQueue *vq); void virtio_queue_notify_vq(VirtQueue *vq);

View file

@ -1163,11 +1163,21 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
return kvm_irqchip_assign_irqfd(s, fd, virq, true); 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) int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
{ {
return kvm_irqchip_assign_irqfd(s, fd, virq, false); 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) static int kvm_irqchip_create(KVMState *s)
{ {
QemuOptsList *list = qemu_find_opts("machine"); QemuOptsList *list = qemu_find_opts("machine");

View file

@ -147,7 +147,17 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
return -ENOSYS; 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) int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
{ {
return -ENOSYS; return -ENOSYS;
} }
int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
{
return -ENOSYS;
}

2
kvm.h
View file

@ -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_add_irqfd(KVMState *s, int fd, int virq);
int kvm_irqchip_remove_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 #endif