From patchwork Tue Oct 23 10:50:26 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 193461 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D6CB52C00F8 for ; Tue, 23 Oct 2012 21:57:40 +1100 (EST) Received: from localhost ([::1]:46275 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TQcB0-00044I-H4 for incoming@patchwork.ozlabs.org; Tue, 23 Oct 2012 06:57:38 -0400 Received: from eggs.gnu.org ([208.118.235.92]:36250) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TQcAA-0002CV-4p for qemu-devel@nongnu.org; Tue, 23 Oct 2012 06:56:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TQcA3-00063h-9V for qemu-devel@nongnu.org; Tue, 23 Oct 2012 06:56:46 -0400 Received: from 38.0.169.217.in-addr.arpa ([217.169.0.38]:46019 helo=mnementh.archaic.org.uk) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TQcA3-00063O-14 for qemu-devel@nongnu.org; Tue, 23 Oct 2012 06:56:39 -0400 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1TQc44-0000Fo-JS; Tue, 23 Oct 2012 11:50:28 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Tue, 23 Oct 2012 11:50:26 +0100 Message-Id: <1350989428-941-7-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1350989428-941-1-git-send-email-peter.maydell@linaro.org> References: <1350989428-941-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 217.169.0.38 Cc: kvm@vger.kernel.org, patches@linaro.org, Marcelo Tosatti , kvmarm@lists.cs.columbia.edu, Blue Swirl , Avi Kivity , =?UTF-8?q?Andreas=20F=C3=A4rber?= Subject: [Qemu-devel] [RFC v3 6/8] target-arm: Use MemoryListener to identify GIC base address for KVM X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org When using an in-kernel GIC with KVM, we need to tell the kernel where the GIC's memory mapped registers live. Do this by registering a MemoryListener which tracks where the board model maps the A15's private peripherals, so we can finish the GIC initialisation when the GIC is actually mapped. Signed-off-by: Peter Maydell --- target-arm/kvm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-arm/kvm_arm.h | 32 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 target-arm/kvm_arm.h diff --git a/target-arm/kvm.c b/target-arm/kvm.c index f7d2235..955983d 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -19,6 +19,7 @@ #include "qemu-timer.h" #include "sysemu.h" #include "kvm.h" +#include "kvm_arm.h" #include "cpu.h" #include "hw/arm-misc.h" @@ -62,6 +63,88 @@ int kvm_arch_init_vcpu(CPUARMState *env) return ret; } +/* We track all the KVM devices which need their memory addresses + * passing to the kernel in a list of these structures. + * When board init is complete we run through the list and + * tell the kernel the base addresses of the memory regions. + * We use a MemoryListener to track mapping and unmapping of + * the regions during board creation, so the board models don't + * need to do anything special for the KVM case. + */ +typedef struct KVMDevice { + struct kvm_device_address kda; + MemoryRegion *mr; + QSLIST_ENTRY(KVMDevice) entries; +} KVMDevice; + +static QSLIST_HEAD(kvm_devices_head, KVMDevice) kvm_devices_head; + +static void kvm_arm_devlistener_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMDevice *kd; + QSLIST_FOREACH(kd, &kvm_devices_head, entries) { + if (section->mr == kd->mr) { + kd->kda.addr = section->offset_within_address_space; + } + } +} + +static void kvm_arm_devlistener_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMDevice *kd; + QSLIST_FOREACH(kd, &kvm_devices_head, entries) { + if (section->mr == kd->mr) { + kd->kda.addr = -1; + } + } +} + +static MemoryListener devlistener = { + .region_add = kvm_arm_devlistener_add, + .region_del = kvm_arm_devlistener_del, +}; + +static void kvm_arm_machine_init_done(Notifier *notifier, void *data) +{ + KVMDevice *kd, *tkd; + memory_listener_unregister(&devlistener); + QSLIST_FOREACH_SAFE(kd, &kvm_devices_head, entries, tkd) { + if (kd->kda.addr != -1) { + if (kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ADDRESS, &kd->kda) < 0) { + fprintf(stderr, "KVM_SET_DEVICE_ADDRESS failed: %s\n", + strerror(errno)); + abort(); + } + } + g_free(kd); + } +} + +static Notifier notify = { + .notify = kvm_arm_machine_init_done, +}; + +void kvm_arm_register_device(MemoryRegion *mr, uint32_t devid) +{ + KVMDevice *kd; + + if (!kvm_irqchip_in_kernel()) { + return; + } + + if (QSLIST_EMPTY(&kvm_devices_head)) { + memory_listener_register(&devlistener, NULL); + qemu_add_machine_init_done_notifier(¬ify); + } + kd = g_new0(KVMDevice, 1); + kd->mr = mr; + kd->kda.id = devid; + kd->kda.addr = -1; + QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries); +} + typedef struct Reg { uint64_t id; int offset; diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h new file mode 100644 index 0000000..93babb2 --- /dev/null +++ b/target-arm/kvm_arm.h @@ -0,0 +1,32 @@ +/* + * QEMU KVM support -- ARM 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_ARM_H +#define QEMU_KVM_ARM_H + +#include "kvm.h" +#include "memory.h" + +/** + * kvm_arm_register_device: + * @mr: memory region for this device + * @devid: the KVM device ID + * + * Remember the memory region @mr, and when it is mapped by the + * machine model, tell the kernel that base address using the + * KVM_SET_DEVICE_ADDRESS ioctl. @devid should be the ID of + * the device as defined by KVM_SET_DEVICE_ADDRESS. + * The machine model may map and unmap the device multiple times; + * the kernel will only be told the final address at the point + * where machine init is complete. + */ +void kvm_arm_register_device(MemoryRegion *mr, uint32_t devid); + +#endif