From 53705b5f7d6100005047ae99fb9eaa29678ac4c6 Mon Sep 17 00:00:00 2001 From: Michael S. Tsirkin Date: Wed, 19 Jan 2011 11:49:33 -0200 Subject: [PATCH 11/24] kvm: test for ioeventfd support on old kernels RH-Author: Michael S. Tsirkin Message-id: <36fb20341761480bee19877d25949bc11c3219d0.1295437447.git.mst@redhat.com> Patchwork-id: 16558 O-Subject: [PATCHv4 RHEL6.1 4/8] kvm: test for ioeventfd support on old kernels Bugzilla: 633394 RH-Acked-by: Christoph Hellwig RH-Acked-by: Juan Quintela RH-Acked-by: Alex Williamson RH-Acked-by: Jes Sorensen commit d2f2b8a740c82319f9eea51ebed50815fbc3da3e Author: Stefan Hajnoczi Date: Mon Jan 10 13:50:05 2011 +0200 kvm: test for ioeventfd support on old kernels There used to be a limit of 6 KVM io bus devices in the kernel. On such a kernel, we can't use many ioeventfds for host notification since the limit is reached too easily. Add an API to test for this condition. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin Note: folded in https://patchwork.kernel.org/patch/400592/ to make it build on qemu-kvm. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=633394 --- kvm-all.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- kvm.h | 8 ++++++++ qemu-kvm.c | 2 ++ qemu-kvm.h | 1 + 4 files changed, 61 insertions(+), 1 deletions(-) Signed-off-by: Luiz Capitulino --- kvm-all.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- kvm.h | 8 ++++++++ qemu-kvm.c | 2 ++ qemu-kvm.h | 1 + 4 files changed, 61 insertions(+), 1 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 6506e90..fe03358 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -26,6 +26,11 @@ #include "gdbstub.h" #include "kvm.h" +/* This check must be after config-host.h is included */ +#ifdef CONFIG_EVENTFD +#include +#endif + #ifdef KVM_UPSTREAM /* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */ #define PAGE_SIZE TARGET_PAGE_SIZE @@ -67,6 +72,7 @@ struct KVMState #endif int irqchip_in_kernel; int pit_in_kernel; + int many_ioeventfds; }; static KVMState *kvm_state; @@ -396,8 +402,41 @@ int kvm_check_extension(KVMState *s, unsigned int extension) return ret; } -#ifdef KVM_UPSTREAM +int kvm_check_many_ioeventfds(void) +{ + /* Older kernels have a 6 device limit on the KVM io bus. Find out so we + * can avoid creating too many ioeventfds. + */ +#ifdef CONFIG_EVENTFD + int ioeventfds[7]; + int i, ret = 0; + for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) { + ioeventfds[i] = eventfd(0, EFD_CLOEXEC); + if (ioeventfds[i] < 0) { + break; + } + ret = kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, true); + if (ret < 0) { + close(ioeventfds[i]); + break; + } + } + + /* Decide whether many devices are supported or not */ + ret = i == ARRAY_SIZE(ioeventfds); + + while (i-- > 0) { + kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, false); + close(ioeventfds[i]); + } + return ret; +#else + return 0; +#endif +} + +#ifdef KVM_UPSTREAM int kvm_init(int smp_cpus) { static const char upgrade_note[] = @@ -495,6 +534,8 @@ int kvm_init(int smp_cpus) kvm_state = s; + s->many_ioeventfds = kvm_check_many_ioeventfds(); + return 0; err: @@ -886,6 +927,14 @@ int kvm_has_vcpu_events(void) return kvm_state->vcpu_events; } +int kvm_has_many_ioeventfds(void) +{ + if (!kvm_enabled()) { + return 0; + } + return kvm_state->many_ioeventfds; +} + #ifdef KVM_UPSTREAM void kvm_setup_guest_memory(void *start, size_t size) { diff --git a/kvm.h b/kvm.h index 47fc819..d93b20b 100644 --- a/kvm.h +++ b/kvm.h @@ -156,14 +156,22 @@ static inline void cpu_synchronize_state(CPUState *env) #endif +int kvm_has_many_ioeventfds(void); + #if defined(KVM_IOEVENTFD) && defined(CONFIG_KVM) int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign); +int kvm_check_many_ioeventfds(void); #else static inline int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign) { return -ENOSYS; } +static inline +int kvm_check_many_ioeventfds(void) +{ + return 0; +} #endif #if defined(KVM_IRQFD) && defined(CONFIG_KVM) diff --git a/qemu-kvm.c b/qemu-kvm.c index 90d5714..f06408b 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -2238,6 +2238,8 @@ static int kvm_create_context(void) kvm_state->vcpu_events = kvm_check_extension(kvm_state, KVM_CAP_VCPU_EVENTS); #endif + kvm_state->many_ioeventfds = kvm_check_many_ioeventfds(); + kvm_init_ap(); if (kvm_irqchip) { if (!qemu_kvm_has_gsi_routing()) { diff --git a/qemu-kvm.h b/qemu-kvm.h index 6b3e5a1..1b905f8 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -1151,6 +1151,7 @@ typedef struct KVMState { QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; #endif int irqchip_in_kernel; + int many_ioeventfds; struct kvm_context kvm_context; } KVMState; -- 1.7.4.rc1.16.gd2f15e