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;
}
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;
int ret;
fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vq));
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);
}

View File

@ -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;

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);
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);

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);
}
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");

View File

@ -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;
}

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_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