From patchwork Tue Nov 4 19:26:46 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 406779 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8097614009E for ; Wed, 5 Nov 2014 06:42:25 +1100 (AEDT) Received: from localhost ([::1]:42597 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xljzj-0003cr-Ji for incoming@patchwork.ozlabs.org; Tue, 04 Nov 2014 14:42:23 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36432) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xljl1-00022t-5s for qemu-devel@nongnu.org; Tue, 04 Nov 2014 14:27:22 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xljkl-00080Q-Fw for qemu-devel@nongnu.org; Tue, 04 Nov 2014 14:27:11 -0500 Received: from cantor2.suse.de ([195.135.220.15]:55978 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xljkl-0007yD-4u; Tue, 04 Nov 2014 14:26:55 -0500 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id A428DADA8; Tue, 4 Nov 2014 19:26:54 +0000 (UTC) From: Alexander Graf To: qemu-ppc@nongnu.org Date: Tue, 4 Nov 2014 20:26:46 +0100 Message-Id: <1415129211-9740-29-git-send-email-agraf@suse.de> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1415129211-9740-1-git-send-email-agraf@suse.de> References: <1415129211-9740-1-git-send-email-agraf@suse.de> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] X-Received-From: 195.135.220.15 Cc: peter.maydell@linaro.org, qemu-devel@nongnu.org Subject: [Qemu-devel] [PULL 28/33] PPC: e500: Support dynamically spawned sysbus devices 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 For e500 our approach to supporting dynamically spawned sysbus devices is to create a simple bus from the guest's point of view within which we map those devices dynamically. We allocate memory regions always within the "platform" hole in address space and map IRQs to predetermined IRQ lines that are reserved for platform device usage. This maps really nicely into device tree logic, so we can just tell the guest about our virtual simple bus in device tree as well. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/e500.h | 5 +++ hw/ppc/e500plat.c | 6 ++++ 3 files changed, 111 insertions(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index cfc46c4..123379d 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -36,6 +36,8 @@ #include "exec/address-spaces.h" #include "qemu/host-utils.h" #include "hw/pci-host/ppce500.h" +#include "qemu/error-report.h" +#include "hw/platform-bus.h" #define EPAPR_MAGIC (0x45504150) #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" @@ -152,6 +154,72 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) g_free(poweroff); } +typedef struct PlatformDevtreeData { + void *fdt; + const char *mpic; + int irq_start; + const char *node; + PlatformBusDevice *pbus; +} PlatformDevtreeData; + +static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) +{ + PlatformDevtreeData *data = opaque; + bool matched = false; + + if (!matched) { + error_report("Device %s is not supported by this machine yet.", + qdev_fw_name(DEVICE(sbdev))); + exit(1); + } + + return 0; +} + +static void platform_bus_create_devtree(PPCE500Params *params, void *fdt, + const char *mpic) +{ + gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base); + const char platcomp[] = "qemu,platform\0simple-bus"; + uint64_t addr = params->platform_bus_base; + uint64_t size = params->platform_bus_size; + int irq_start = params->platform_bus_first_irq; + PlatformBusDevice *pbus; + DeviceState *dev; + + /* Create a /platform node that we can put all devices into */ + + qemu_fdt_add_subnode(fdt, node); + qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); + + /* Our platform bus region is less than 32bit big, so 1 cell is enough for + address and size */ + qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); + qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); + + qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); + + dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); + pbus = PLATFORM_BUS_DEVICE(dev); + + /* We can only create dt nodes for dynamic devices when they're ready */ + if (pbus->done_gathering) { + PlatformDevtreeData data = { + .fdt = fdt, + .mpic = mpic, + .irq_start = irq_start, + .node = node, + .pbus = pbus, + }; + + /* Loop through all dynamic sysbus devices and create nodes for them */ + foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); + } + + g_free(node); +} + static int ppce500_load_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, @@ -413,6 +481,10 @@ static int ppce500_load_device_tree(MachineState *machine, create_dt_mpc8xxx_gpio(fdt, soc, mpic); } + if (params->has_platform_bus) { + platform_bus_create_devtree(params, fdt, mpic); + } + params->fixup_devtree(params, fdt); if (toplevel_compat) { @@ -441,6 +513,7 @@ typedef struct DeviceTreeParams { hwaddr initrd_size; hwaddr kernel_base; hwaddr kernel_size; + Notifier notifier; } DeviceTreeParams; static void ppce500_reset_device_tree(void *opaque) @@ -451,6 +524,12 @@ static void ppce500_reset_device_tree(void *opaque) false); } +static void ppce500_init_notify(Notifier *notifier, void *data) +{ + DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier); + ppce500_reset_device_tree(p); +} + static int ppce500_prep_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, @@ -469,6 +548,8 @@ static int ppce500_prep_device_tree(MachineState *machine, p->kernel_size = kernel_size; qemu_register_reset(ppce500_reset_device_tree, p); + p->notifier.notify = ppce500_init_notify; + qemu_add_machine_init_done_notifier(&p->notifier); /* Issue the device tree loader once, so that we get the size of the blob */ return ppce500_load_device_tree(machine, params, addr, initrd_base, @@ -825,6 +906,25 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) qdev_connect_gpio_out(dev, 0, poweroff_irq); } + /* Platform Bus Device */ + if (params->has_platform_bus) { + dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); + dev->id = TYPE_PLATFORM_BUS_DEVICE; + qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs); + qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + + for (i = 0; i < params->platform_bus_num_irqs; i++) { + int irqn = params->platform_bus_first_irq + i; + sysbus_connect_irq(s, i, mpic[irqn]); + } + + memory_region_add_subregion(address_space_mem, + params->platform_bus_base, + sysbus_mmio_get_region(s, 0)); + } + /* Load kernel. */ if (machine->kernel_filename) { kernel_base = cur_base; diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 83c5b8b..9f61ab2 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -12,6 +12,11 @@ typedef struct PPCE500Params { int mpic_version; bool has_mpc8xxx_gpio; + bool has_platform_bus; + hwaddr platform_bus_base; + hwaddr platform_bus_size; + int platform_bus_first_irq; + int platform_bus_num_irqs; } PPCE500Params; void ppce500_init(MachineState *machine, PPCE500Params *params); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index bafb56d..d50ae00 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -36,6 +36,11 @@ static void e500plat_init(MachineState *machine) .fixup_devtree = e500plat_fixup_devtree, .mpic_version = OPENPIC_MODEL_FSL_MPIC_42, .has_mpc8xxx_gpio = true, + .has_platform_bus = true, + .platform_bus_base = 0xf00000000ULL, + .platform_bus_size = (128ULL * 1024 * 1024), + .platform_bus_first_irq = 5, + .platform_bus_num_irqs = 10, }; /* Older KVM versions don't support EPR which breaks guests when we announce @@ -52,6 +57,7 @@ static QEMUMachine e500plat_machine = { .desc = "generic paravirt e500 platform", .init = e500plat_init, .max_cpus = 32, + .has_dynamic_sysbus = true, }; static void e500plat_machine_init(void)