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
This commit is contained in:
Anthony Liguori 2012-08-13 09:25:48 -05:00
commit d517872ec2
13 changed files with 170 additions and 27 deletions

14
configure vendored
View File

@ -3563,15 +3563,23 @@ if test "$linux" = "yes" ; then
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

3
cpus.c
View File

@ -70,7 +70,8 @@ static bool cpu_thread_is_idle(CPUArchState *env)
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;

View File

@ -94,7 +94,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level)
{
int delivered;
delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
delivered = kvm_set_irq(kvm_state, irq, level);
apic_report_irq_delivered(delivered);
}

View File

@ -82,7 +82,7 @@ static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
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);
}

View File

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

View File

@ -627,7 +627,7 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
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 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
}
/* 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));

View File

@ -100,6 +100,10 @@ struct KVMState
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 @@ static void kvm_handle_interrupt(CPUArchState *env, int mask)
}
}
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 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
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 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
struct kvm_irq_routing_entry kroute;
int virq;
if (!kvm_irqchip_in_kernel()) {
if (!kvm_gsi_routing_enabled()) {
return -ENOSYS;
}
@ -1125,7 +1129,7 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
.flags = assign ? 0 : KVM_IRQFD_FLAG_DEASSIGN,
};
if (!kvm_irqchip_in_kernel()) {
if (!kvm_irqfds_enabled()) {
return -ENOSYS;
}
@ -1201,12 +1205,36 @@ static int kvm_irqchip_create(KVMState *s)
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 @@ int kvm_init(void)
const KVMCapabilityInfo *missing_cap;
int ret;
int i;
int max_vcpus;
s = g_malloc0(sizeof(KVMState));
@ -1256,6 +1285,14 @@ int kvm_init(void)
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 @@ int kvm_has_gsi_routing(void)
#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

View File

@ -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 @@ int kvm_has_many_ioeventfds(void)
return 0;
}
int kvm_allows_irq0_override(void)
{
return 1;
}
int kvm_has_pit_state2(void)
{
return 0;

60
kvm.h
View File

@ -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_pit_state2(void);
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 @@ int kvm_arch_on_sigbus(int code, void *addr);
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);

View File

@ -3,6 +3,7 @@ obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
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

18
target-i386/kvm-stub.c Normal file
View File

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

View File

@ -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_async_pf_en;
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 @@ void kvm_arch_init_irq_routing(KVMState *s)
*/
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;
}

16
target-i386/kvm_i386.h Normal file
View File

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