From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NzMal-0008JD-Sh for qemu-devel@nongnu.org; Wed, 07 Apr 2010 00:10:15 -0400 Received: from [140.186.70.92] (port=34683 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NzMaj-0008HS-E6 for qemu-devel@nongnu.org; Wed, 07 Apr 2010 00:10:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1NzMah-0001n2-Oh for qemu-devel@nongnu.org; Wed, 07 Apr 2010 00:10:13 -0400 Received: from mail-pz0-f204.google.com ([209.85.222.204]:37776) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1NzMah-0001mu-E7 for qemu-devel@nongnu.org; Wed, 07 Apr 2010 00:10:11 -0400 Received: by pzk42 with SMTP id 42so139118pzk.4 for ; Tue, 06 Apr 2010 21:10:10 -0700 (PDT) Sender: Grant Likely From: Grant Likely Date: Tue, 06 Apr 2010 22:10:08 -0600 Message-ID: <20100407041007.20274.1368.stgit@angua> In-Reply-To: <20100407040129.20274.44284.stgit@angua> References: <20100407040129.20274.44284.stgit@angua> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [RFC PATCH 2/7] devicetree: auto-populate the device tree with qdev data List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, devicetree-discuss@lists.ozlabs.org, jeremy.kerr@canonical.com This patch adds hooks to the qemu device model to auto-generate device tree nodes from the registered qemu devices, and calls the device tree populate hook when booting ARM platforms. Signed-off-by: Grant Likely --- hw/arm_boot.c | 3 ++ hw/qdev.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/qdev.h | 8 +++++ 3 files changed, 102 insertions(+), 0 deletions(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 740a446..33c7356 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -13,6 +13,7 @@ #include "sysemu.h" #include "loader.h" #include "elf.h" +#include "qdev.h" #ifdef CONFIG_FDT #include "device_tree.h" @@ -211,6 +212,8 @@ static int load_dtb(target_phys_addr_t addr, struct arm_boot_info *binfo) } qemu_free(filename); + qdev_fdt_populate(fdt); + rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); if (rc < 0) diff --git a/hw/qdev.c b/hw/qdev.c index d19d531..b177c3d 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -748,3 +748,94 @@ void do_device_del(Monitor *mon, const QDict *qdict) } qdev_unplug(dev); } + +#ifdef CONFIG_FDT +#include +static int qbus_fdt_add_bus(void *fdt, BusState *bus, int dev_offset); +static int qdev_fdt_add_device(void *fdt, DeviceState *dev, int bus_offset) +{ + BusState *child; + int dev_offset, rc; + char name[sizeof(dev->info->name) + 9]; + static int unique = 0; + + sprintf(name, "%s@%x", dev->info->name, unique++); + dev_offset = fdt_add_subnode(fdt, bus_offset, name); + if (dev_offset < 0) { + qemu_error("Couldn't add FDT node for device %s\n", dev->info->name); + return dev_offset; + } + + rc = fdt_setprop_cell(fdt, dev_offset, "phandle", (uint64_t)dev); + if (rc < 0) { + qemu_error("Could not add phandle property to device %s\n", + dev->info->name); + return rc; + } + + if (dev->info->fdt_populate) { + int rc = dev->info->fdt_populate(dev, fdt, dev_offset); + if (rc < 0) { + qemu_error("dev->info->fdt_populate() failed on %s\n", + dev->info->name); + return rc; + } + } + + QLIST_FOREACH(child, &dev->child_bus, sibling) { + int rc = qbus_fdt_add_bus(fdt, child, dev_offset); + if (rc < 0) { + qemu_error("qbus_fdt_add_bus() failed on dev:%s bus:%s\n", + dev->info->name, child->info->name); + return rc; + } + } + + return dev_offset; +} + +static int qbus_fdt_add_bus(void *fdt, BusState *bus, int dev_offset) +{ + struct DeviceState *dev; + int bus_offset; + + bus_offset = fdt_add_subnode(fdt, dev_offset, bus->name); + if (bus_offset < 0) { + qemu_error("Couldn't add FDT node for bus %s\n", bus->name); + return bus_offset; + } + + if (bus->info->fdt_populate) { + int rc = bus->info->fdt_populate(bus, fdt, bus_offset); + if (rc < 0) { + qemu_error("bus->info->fdt_populate() failed on %s\n", + bus->info->name); + return rc; + } + } + + QLIST_FOREACH(dev, &bus->children, sibling) { + int rc = qdev_fdt_add_device(fdt, dev, bus_offset); + if (rc < 0) { + qemu_error("qbus_fdt_add_device() failed on bus:%s dev:%s\n", + bus->info->name, dev->info->name); + return rc; + } + } + + return bus_offset; +} + +int qdev_fdt_populate(void *fdt) +{ + int offset = fdt_path_offset(fdt, "/"); + if (offset < 0) + return offset; + + if (main_system_bus) + qbus_fdt_add_bus(fdt, main_system_bus, offset); + + return offset; +} +#endif /* CONFIG_FDT */ + diff --git a/hw/qdev.h b/hw/qdev.h index 41642ee..d549d43 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -43,10 +43,12 @@ struct DeviceState { }; typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent); +typedef int (*bus_fdt_populatefn)(BusState *bus, void *fdt, int offset); struct BusInfo { const char *name; size_t size; bus_dev_printfn print_dev; + bus_fdt_populatefn fdt_populate; Property *props; }; @@ -119,6 +121,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name); typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info); typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); +typedef int (*qdev_fdt_populatefn)(DeviceState *dev, void *fdt, int offset); struct DeviceInfo { const char *name; @@ -130,6 +133,7 @@ struct DeviceInfo { /* callbacks */ qdev_resetfn reset; + qdev_fdt_populatefn fdt_populate; /* device state */ const VMStateDescription *vmsd; @@ -272,4 +276,8 @@ void qdev_prop_set_compat(DeviceState *dev); /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ extern struct BusInfo system_bus_info; +#ifdef CONFIG_FDT +int qdev_fdt_populate(void *fdt); +#endif + #endif