Merge remote-tracking branch 'qemu-kvm/uq/master' into staging * qemu-kvm/uq/master: kvm: Add documentation comment for kvm_irqchip_in_kernel() kvm: Decouple 'GSI routing' from 'kernel irqchip' kvm: Decouple 'MSI routing via irqfds' from 'kernel irqchip' kvm: Decouple 'irqfds usable' from 'kernel irqchip' kvm: Move kvm_allows_irq0_override() to target-i386, fix return type kvm: Rename kvm_irqchip_set_irq() to kvm_set_irq() kvm: Decouple 'async interrupt delivery' from 'kernel irqchip' configure: Don't implicitly hardcode list of KVM architectures kvm: Check if smp_cpus exceeds max cpus supported by kvm
diff --git a/configure b/configure index f0dbc03..97b69a0 100755 --- a/configure +++ b/configure
@@ -3563,15 +3563,23 @@ mkdir -p linux-headers case "$cpu" in i386|x86_64) - symlink "$source_path/linux-headers/asm-x86" linux-headers/asm + linux_arch=x86 ;; ppcemb|ppc|ppc64) - symlink "$source_path/linux-headers/asm-powerpc" linux-headers/asm + linux_arch=powerpc ;; s390x) - symlink "$source_path/linux-headers/asm-s390" linux-headers/asm + linux_arch=s390 + ;; + *) + # For most CPUs the kernel architecture name and QEMU CPU name match. + linux_arch="$cpu" ;; esac + # For non-KVM architectures we will not have asm headers + if [ -e "$source_path/linux-headers/asm-$linux_arch" ]; then + symlink "$source_path/linux-headers/asm-$linux_arch" linux-headers/asm + fi fi for target in $target_list; do
diff --git a/cpus.c b/cpus.c index 3de2e27..e476a3c 100644 --- a/cpus.c +++ b/cpus.c
@@ -70,7 +70,8 @@ if (env->stopped || !runstate_is_running()) { return true; } - if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) { + if (!env->halted || qemu_cpu_has_work(env) || + kvm_async_interrupts_enabled()) { return false; } return true;
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c index 94d1b9a..1e24cd4 100644 --- a/hw/kvm/i8259.c +++ b/hw/kvm/i8259.c
@@ -94,7 +94,7 @@ { int delivered; - delivered = kvm_irqchip_set_irq(kvm_state, irq, level); + delivered = kvm_set_irq(kvm_state, irq, level); apic_report_irq_delivered(delivered); }
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c index 3ae3175..6c3b8fe 100644 --- a/hw/kvm/ioapic.c +++ b/hw/kvm/ioapic.c
@@ -82,7 +82,7 @@ KVMIOAPICState *s = opaque; int delivered; - delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level); + delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level); apic_report_irq_delivered(delivered); }
diff --git a/hw/pc.c b/hw/pc.c index 81c391c..e8bcfc0 100644 --- a/hw/pc.c +++ b/hw/pc.c
@@ -42,6 +42,7 @@ #include "sysbus.h" #include "sysemu.h" #include "kvm.h" +#include "kvm_i386.h" #include "xen.h" #include "blockdev.h" #include "hw/block-common.h"
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 125eded..5e6e09e 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c
@@ -627,7 +627,7 @@ int r, n; /* Must unset vector notifier while guest notifier is still assigned */ - if (kvm_irqchip_in_kernel() && !assign) { + if (kvm_msi_via_irqfd_enabled() && !assign) { msix_unset_vector_notifiers(&proxy->pci_dev); g_free(proxy->vector_irqfd); proxy->vector_irqfd = NULL; @@ -645,7 +645,7 @@ } /* Must set vector notifier after guest notifier has been assigned */ - if (kvm_irqchip_in_kernel() && assign) { + if (kvm_msi_via_irqfd_enabled() && assign) { proxy->vector_irqfd = g_malloc0(sizeof(*proxy->vector_irqfd) * msix_nr_vectors_allocated(&proxy->pci_dev));
diff --git a/kvm-all.c b/kvm-all.c index 2148b20..34b02c1 100644 --- a/kvm-all.c +++ b/kvm-all.c
@@ -100,6 +100,10 @@ KVMState *kvm_state; bool kvm_kernel_irqchip; +bool kvm_async_interrupts_allowed; +bool kvm_irqfds_allowed; +bool kvm_msi_via_irqfd_allowed; +bool kvm_gsi_routing_allowed; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -852,18 +856,18 @@ } } -int kvm_irqchip_set_irq(KVMState *s, int irq, int level) +int kvm_set_irq(KVMState *s, int irq, int level) { struct kvm_irq_level event; int ret; - assert(kvm_irqchip_in_kernel()); + assert(kvm_async_interrupts_enabled()); event.level = level; event.irq = irq; ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event); if (ret < 0) { - perror("kvm_set_irqchip_line"); + perror("kvm_set_irq"); abort(); } @@ -1088,7 +1092,7 @@ assert(route->kroute.type == KVM_IRQ_ROUTING_MSI); - return kvm_irqchip_set_irq(s, route->kroute.gsi, 1); + return kvm_set_irq(s, route->kroute.gsi, 1); } int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) @@ -1096,7 +1100,7 @@ struct kvm_irq_routing_entry kroute; int virq; - if (!kvm_irqchip_in_kernel()) { + if (!kvm_gsi_routing_enabled()) { return -ENOSYS; } @@ -1125,7 +1129,7 @@ .flags = assign ? 0 : KVM_IRQFD_FLAG_DEASSIGN, }; - if (!kvm_irqchip_in_kernel()) { + if (!kvm_irqfds_enabled()) { return -ENOSYS; } @@ -1201,12 +1205,36 @@ s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS; } kvm_kernel_irqchip = true; + /* If we have an in-kernel IRQ chip then we must have asynchronous + * interrupt delivery (though the reverse is not necessarily true) + */ + kvm_async_interrupts_allowed = true; kvm_init_irq_routing(s); return 0; } +static int kvm_max_vcpus(KVMState *s) +{ + int ret; + + /* Find number of supported CPUs using the recommended + * procedure from the kernel API documentation to cope with + * older kernels that may be missing capabilities. + */ + ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS); + if (ret) { + return ret; + } + ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS); + if (ret) { + return ret; + } + + return 4; +} + int kvm_init(void) { static const char upgrade_note[] = @@ -1216,6 +1244,7 @@ const KVMCapabilityInfo *missing_cap; int ret; int i; + int max_vcpus; s = g_malloc0(sizeof(KVMState)); @@ -1256,6 +1285,14 @@ goto err; } + max_vcpus = kvm_max_vcpus(s); + if (smp_cpus > max_vcpus) { + ret = -EINVAL; + fprintf(stderr, "Number of SMP cpus requested (%d) exceeds max cpus " + "supported by KVM (%d)\n", smp_cpus, max_vcpus); + goto err; + } + s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0); if (s->vmfd < 0) { #ifdef TARGET_S390X @@ -1667,11 +1704,6 @@ #endif } -int kvm_allows_irq0_override(void) -{ - return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing(); -} - void *kvm_vmalloc(ram_addr_t size) { #ifdef TARGET_S390X
diff --git a/kvm-stub.c b/kvm-stub.c index d23b11c..94c9ea1 100644 --- a/kvm-stub.c +++ b/kvm-stub.c
@@ -19,6 +19,10 @@ KVMState *kvm_state; bool kvm_kernel_irqchip; +bool kvm_async_interrupts_allowed; +bool kvm_irqfds_allowed; +bool kvm_msi_via_irqfd_allowed; +bool kvm_gsi_routing_allowed; int kvm_init_vcpu(CPUArchState *env) { @@ -71,11 +75,6 @@ return 0; } -int kvm_allows_irq0_override(void) -{ - return 1; -} - int kvm_has_pit_state2(void) { return 0;
diff --git a/kvm.h b/kvm.h index 2617dd5..5b8f588 100644 --- a/kvm.h +++ b/kvm.h
@@ -24,13 +24,69 @@ extern int kvm_allowed; extern bool kvm_kernel_irqchip; +extern bool kvm_async_interrupts_allowed; +extern bool kvm_irqfds_allowed; +extern bool kvm_msi_via_irqfd_allowed; +extern bool kvm_gsi_routing_allowed; #if defined CONFIG_KVM || !defined NEED_CPU_H #define kvm_enabled() (kvm_allowed) +/** + * kvm_irqchip_in_kernel: + * + * Returns: true if the user asked us to create an in-kernel + * irqchip via the "kernel_irqchip=on" machine option. + * What this actually means is architecture and machine model + * specific: on PC, for instance, it means that the LAPIC, + * IOAPIC and PIT are all in kernel. This function should never + * be used from generic target-independent code: use one of the + * following functions or some other specific check instead. + */ #define kvm_irqchip_in_kernel() (kvm_kernel_irqchip) + +/** + * kvm_async_interrupts_enabled: + * + * Returns: true if we can deliver interrupts to KVM + * asynchronously (ie by ioctl from any thread at any time) + * rather than having to do interrupt delivery synchronously + * (where the vcpu must be stopped at a suitable point first). + */ +#define kvm_async_interrupts_enabled() (kvm_async_interrupts_allowed) + +/** + * kvm_irqfds_enabled: + * + * Returns: true if we can use irqfds to inject interrupts into + * a KVM CPU (ie the kernel supports irqfds and we are running + * with a configuration where it is meaningful to use them). + */ +#define kvm_irqfds_enabled() (kvm_irqfds_allowed) + +/** + * kvm_msi_via_irqfd_enabled: + * + * Returns: true if we can route a PCI MSI (Message Signaled Interrupt) + * to a KVM CPU via an irqfd. This requires that the kernel supports + * this and that we're running in a configuration that permits it. + */ +#define kvm_msi_via_irqfd_enabled() (kvm_msi_via_irqfd_allowed) + +/** + * kvm_gsi_routing_enabled: + * + * Returns: true if GSI routing is enabled (ie the kernel supports + * it and we're running in a configuration that permits it). + */ +#define kvm_gsi_routing_enabled() (kvm_gsi_routing_allowed) + #else #define kvm_enabled() (0) #define kvm_irqchip_in_kernel() (false) +#define kvm_async_interrupts_enabled() (false) +#define kvm_irqfds_enabled() (false) +#define kvm_msi_via_irqfd_enabled() (false) +#define kvm_gsi_routing_allowed() (false) #endif struct kvm_run; @@ -62,8 +118,6 @@ int kvm_has_many_ioeventfds(void); int kvm_has_gsi_routing(void); -int kvm_allows_irq0_override(void); - #ifdef NEED_CPU_H int kvm_init_vcpu(CPUArchState *env); @@ -133,7 +187,7 @@ void kvm_arch_init_irq_routing(KVMState *s); -int kvm_irqchip_set_irq(KVMState *s, int irq, int level); +int kvm_set_irq(KVMState *s, int irq, int level); int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg); void kvm_irqchip_add_irq_route(KVMState *s, int gsi, int irqchip, int pin);
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs index 683fd59..0715f58 100644 --- a/target-i386/Makefile.objs +++ b/target-i386/Makefile.objs
@@ -3,6 +3,7 @@ obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o obj-$(CONFIG_KVM) += kvm.o hyperv.o +obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-$(CONFIG_LINUX_USER) += ioport-user.o obj-$(CONFIG_BSD_USER) += ioport-user.o
diff --git a/target-i386/kvm-stub.c b/target-i386/kvm-stub.c new file mode 100644 index 0000000..11429c4 --- /dev/null +++ b/target-i386/kvm-stub.c
@@ -0,0 +1,18 @@ +/* + * QEMU KVM x86 specific function stubs + * + * Copyright Linaro Limited 2012 + * + * Author: Peter Maydell <peter.maydell@linaro.org> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "qemu-common.h" +#include "kvm_i386.h" + +bool kvm_allows_irq0_override(void) +{ + return 1; +}
diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 4cfb3fa..696b14a 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c
@@ -23,6 +23,7 @@ #include "qemu-common.h" #include "sysemu.h" #include "kvm.h" +#include "kvm_i386.h" #include "cpu.h" #include "gdbstub.h" #include "host-utils.h" @@ -65,6 +66,11 @@ static bool has_msr_misc_enable; static int lm_capable_kernel; +bool kvm_allows_irq0_override(void) +{ + return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing(); +} + static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max) { struct kvm_cpuid2 *cpuid; @@ -2041,4 +2047,11 @@ */ no_hpet = 1; } + /* We know at this point that we're using the in-kernel + * irqchip, so we can use irqfds, and on x86 we know + * we can use msi via irqfd and GSI routing. + */ + kvm_irqfds_allowed = true; + kvm_msi_via_irqfd_allowed = true; + kvm_gsi_routing_allowed = true; }
diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h new file mode 100644 index 0000000..b82bbf4 --- /dev/null +++ b/target-i386/kvm_i386.h
@@ -0,0 +1,16 @@ +/* + * QEMU KVM support -- x86 specific functions. + * + * Copyright (c) 2012 Linaro Limited + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_I386_H +#define QEMU_KVM_I386_H + +bool kvm_allows_irq0_override(void); + +#endif