qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation
@ 2014-08-08 15:03 Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding Eric Auger
                   ` (6 more replies)
  0 siblings, 7 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

This RFC enables machvirt to dynamically instantiate sysbus devices
from command line.

the RFC originates from Alex Graf's work
- "Dynamic sysbus device allocation support"
  http://lists.gnu.org/archive/html/qemu-ppc/2014-07/msg00047.html

The code related to dynamic sysbus device IRQ and mmio region binding
and device tree node generation, originally developped in PPC e500.c,
is moved into 2 new modules:

- hw/misc/dyn_sysbus_binding (IRQ and MMIO binding)
- hw/arm/dyn_sysbus_devtree  (dt node generation)

This makes possible to reuse it for ARM/machvirt.

Both e500 and machvirt are adapted to use those helper routines.

This RFC applies onto "sysbus: Make devices spawnable via -device"
https://www.mail-archive.com/qemu-devel@nongnu.org/msg244394.html.

---

integrated branch can be found on
git://git.linaro.org/people/eric.auger/qemu.git,
branch dyn-sysbus-v2-integ

A related discussion can be found at
https://lists.nongnu.org/archive/html/qemu-devel/2014-07/msg04065.html

For e500 the device tree generation is kept in the machine file,
according to Alex will.

For machvirt we use dyn_sysbus_devtree since the code becomes large
with the expected support of vfio devices.

Best Regards
Eric

v1 -> v2:
- device node generation no more in sysbus device but in
  dyn_sysbus_devtree
- VFIO region shrinked to 4MB and relocated in machvirt to avoid PCI
  shrink (dynamic vfio-mmio support might come latter)
- platform_bus_base removed from PlatformDevtreeData

Alexander Graf (2):
  PPC: e500: Support dynamically spawned sysbus devices
  e500: Add support for eTSEC in device tree

Eric Auger (5):
  hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding
  hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node  
      generation
  hw/arm/boot: load_dtb becomes non static
  hw/arm/virt: add new add_fdt_xxx_node functions
  hw/arm/virt: Support dynamically spawned sysbus devices

 hw/arm/Makefile.objs                 |   1 +
 hw/arm/boot.c                        |   2 +-
 hw/arm/dyn_sysbus_devtree.c          |  66 ++++++++++++++
 hw/arm/virt.c                        | 129 +++++++++++++++++++++------
 hw/misc/Makefile.objs                |   1 +
 hw/misc/dyn_sysbus_binding.c         | 163 +++++++++++++++++++++++++++++++++++
 hw/ppc/e500.c                        | 129 +++++++++++++++++++++++++++
 hw/ppc/e500.h                        |   2 +
 hw/ppc/e500plat.c                    |   9 ++
 include/hw/arm/arm.h                 |   1 +
 include/hw/arm/dyn_sysbus_devtree.h  |  18 ++++
 include/hw/misc/dyn_sysbus_binding.h |  24 ++++++
 12 files changed, 519 insertions(+), 26 deletions(-)
 create mode 100644 hw/arm/dyn_sysbus_devtree.c
 create mode 100644 hw/misc/dyn_sysbus_binding.c
 create mode 100644 include/hw/arm/dyn_sysbus_devtree.h
 create mode 100644 include/hw/misc/dyn_sysbus_binding.h

-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  2014-08-11 13:08   ` Alexander Graf
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation Eric Auger
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

This new module implements routines which help in dynamic device
binding (mmio regions, irq). They are supposed to be used by machine
files that support dynamic sysbus instantiation.

---

v1 -> v2:
- platform_devices renamed into dyn_sysbus_binding
- PlatformParams renamed into DynSysbusParams
- PlatformBusNotifier renamed into DynSysbusNotifier
- platform_bus_map_irq, platform_bus_map_mmio, sysbus_device_check,
  platform_bus_init become static
- PlatformBusInitData becomes private to the module
- page_shift becomes a member of DynSysbusParams

v1: Dynamic sysbus device allocation fully written by Alex Graf.
Those functions were initially in ppc e500 machine file. Now moved to a
separate module.
PPCE500Params is replaced by a generic struct named PlatformParams

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
 hw/misc/Makefile.objs                |   1 +
 hw/misc/dyn_sysbus_binding.c         | 163 +++++++++++++++++++++++++++++++++++
 include/hw/misc/dyn_sysbus_binding.h |  24 ++++++
 3 files changed, 188 insertions(+)
 create mode 100644 hw/misc/dyn_sysbus_binding.c
 create mode 100644 include/hw/misc/dyn_sysbus_binding.h

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 979e532..86f6243 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
 obj-$(CONFIG_ZYNQ) += zynq_slcr.o
 
 obj-$(CONFIG_PVPANIC) += pvpanic.o
+obj-y += dyn_sysbus_binding.o
diff --git a/hw/misc/dyn_sysbus_binding.c b/hw/misc/dyn_sysbus_binding.c
new file mode 100644
index 0000000..0f34f0b
--- /dev/null
+++ b/hw/misc/dyn_sysbus_binding.c
@@ -0,0 +1,163 @@
+#include "hw/misc/dyn_sysbus_binding.h"
+#include "qemu/error-report.h"
+
+typedef struct PlatformBusInitData {
+    unsigned long *used_irqs;
+    unsigned long *used_mem;
+    MemoryRegion *mem;
+    qemu_irq *irqs;
+    int device_count;
+    DynSysbusParams *params;
+} PlatformBusInitData;
+
+
+static int platform_bus_map_irq(DynSysbusParams *params,
+                                SysBusDevice *sbdev,
+                                int n, unsigned long *used_irqs,
+                                qemu_irq *platform_irqs)
+{
+    int max_irqs = params->platform_bus_num_irqs;
+    char *prop = g_strdup_printf("irq[%d]", n);
+    int irqn = object_property_get_int(OBJECT(sbdev), prop, NULL);
+
+    if (irqn == SYSBUS_DYNAMIC) {
+        /* Find the first available IRQ */
+        irqn = find_first_zero_bit(used_irqs, max_irqs);
+    }
+
+    if ((irqn >= max_irqs) || test_and_set_bit(irqn, used_irqs)) {
+        hw_error("IRQ %d is already allocated or no free IRQ left", irqn);
+    }
+
+    sysbus_connect_irq(sbdev, n, platform_irqs[irqn]);
+    object_property_set_int(OBJECT(sbdev), irqn, prop, NULL);
+
+    g_free(prop);
+    return 0;
+}
+
+static int platform_bus_map_mmio(DynSysbusParams *params,
+                                 SysBusDevice *sbdev,
+                                 int n, unsigned long *used_mem,
+                                 MemoryRegion *pmem)
+{
+    MemoryRegion *device_mem = sbdev->mmio[n].memory;
+    uint64_t size = memory_region_size(device_mem);
+    uint64_t page_size = (1 << params->page_shift);
+    uint64_t page_mask = page_size - 1;
+    uint64_t size_pages = (size + page_mask) >> params->page_shift;
+    uint64_t max_size = params->platform_bus_size;
+    uint64_t max_pages = max_size >> params->page_shift;
+    char *prop = g_strdup_printf("mmio[%d]", n);
+    hwaddr addr = object_property_get_int(OBJECT(sbdev), prop, NULL);
+    int page;
+    int i;
+
+    page = addr >> params->page_shift;
+    if (addr == SYSBUS_DYNAMIC) {
+        uint64_t size_pages_align;
+
+        /* Align the region to at least its own size granularity */
+        if (is_power_of_2(size_pages)) {
+            size_pages_align = size_pages;
+        } else {
+            size_pages_align = pow2floor(size_pages) << 1;
+        }
+
+        /* Find the first available region that fits */
+        page = bitmap_find_next_zero_area(used_mem, max_pages, 0, size_pages,
+                                          size_pages_align);
+
+        addr = (uint64_t)page << params->page_shift;
+    }
+
+    if (page >= max_pages || test_bit(page, used_mem) ||
+        (find_next_bit(used_mem, max_pages, page) < size_pages)) {
+        hw_error("Memory [%"PRIx64":%"PRIx64" is already allocated or "
+                 "no slot left", addr, size);
+    }
+
+    for (i = page; i < (page + size_pages); i++) {
+        set_bit(i, used_mem);
+    }
+
+    memory_region_add_subregion(pmem, addr, device_mem);
+    sbdev->mmio[n].addr = addr;
+    object_property_set_int(OBJECT(sbdev), addr, prop, NULL);
+
+    g_free(prop);
+    return 0;
+}
+
+static int sysbus_device_check(Object *obj, void *opaque)
+{
+    PlatformBusInitData *init = opaque;
+    Object *dev;
+    SysBusDevice *sbdev;
+    int i;
+
+    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
+    sbdev = (SysBusDevice *)dev;
+
+    if (!sbdev) {
+        /* Container, traverse it for children */
+        return object_child_foreach(obj, sysbus_device_check, opaque);
+    }
+
+    /* Connect sysbus device to virtual platform bus */
+    for (i = 0; i < sbdev->num_irq; i++) {
+        if (!sbdev->irqp[i]) {
+            /* This IRQ is an incoming IRQ, we can't wire those here */
+            continue;
+        }
+        platform_bus_map_irq(init->params, sbdev, i,
+                             init->used_irqs, init->irqs);
+    }
+
+    for (i = 0; i < sbdev->num_mmio; i++) {
+        platform_bus_map_mmio(init->params, sbdev, i,
+                              init->used_mem, init->mem);
+    }
+
+    return 0;
+}
+
+static void platform_bus_init(DynSysbusParams *params,
+                       MemoryRegion *address_space_mem,
+                       qemu_irq *mpic)
+{
+    uint64_t max_size = params->platform_bus_size;
+    uint64_t max_pages = max_size >> params->page_shift;
+    DECLARE_BITMAP(used_irqs, params->platform_bus_num_irqs);
+    DECLARE_BITMAP(used_mem, max_pages);
+    MemoryRegion *platform_region = g_new(MemoryRegion, 1);
+    Object *container;
+    PlatformBusInitData init = {
+        .used_irqs = used_irqs,
+        .used_mem = used_mem,
+        .mem = platform_region,
+        .irqs = &mpic[params->platform_bus_first_irq],
+        .params = params,
+    };
+
+    memory_region_init(platform_region, NULL, "platform devices",
+                       params->platform_bus_size);
+
+    bitmap_clear(used_irqs, 0, params->platform_bus_num_irqs);
+    bitmap_clear(used_mem, 0, max_pages);
+
+    /* Loop through all sysbus devices that were spawened outside the machine */
+    container = container_get(qdev_get_machine(), "/peripheral");
+    sysbus_device_check(container, &init);
+    container = container_get(qdev_get_machine(), "/peripheral-anon");
+    sysbus_device_check(container, &init);
+
+    memory_region_add_subregion(address_space_mem, params->platform_bus_base,
+                                platform_region);
+}
+
+void platform_bus_init_notify(Notifier *notifier, void *data)
+{
+    DynSysbusNotifier *pn = (DynSysbusNotifier *)notifier;
+    platform_bus_init(&pn->params, pn->address_space_mem, pn->mpic);
+}
diff --git a/include/hw/misc/dyn_sysbus_binding.h b/include/hw/misc/dyn_sysbus_binding.h
new file mode 100644
index 0000000..961c9c7
--- /dev/null
+++ b/include/hw/misc/dyn_sysbus_binding.h
@@ -0,0 +1,24 @@
+#ifndef HW_MISC_PLATFORM_DEVICES_H
+#define HW_MISC_PLATFORM_DEVICES_H
+
+#include "qemu-common.h"
+#include "hw/sysbus.h"
+
+typedef struct {
+    bool has_platform_bus;
+    hwaddr platform_bus_base;
+    hwaddr platform_bus_size;
+    int platform_bus_first_irq;
+    int platform_bus_num_irqs;
+    int page_shift;
+} DynSysbusParams;
+
+typedef struct DynSysbusNotifier {
+    Notifier notifier;
+    MemoryRegion *address_space_mem;
+    qemu_irq *mpic;
+    DynSysbusParams params;
+} DynSysbusNotifier;
+
+void platform_bus_init_notify(Notifier *notifier, void *data);
+#endif
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  2014-08-11 13:16   ` Alexander Graf
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 3/7] PPC: e500: Support dynamically spawned sysbus devices Eric Auger
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

This module will be used by ARM machine files to generate
device tree nodes of dynamically instantiated sysbus devices (ie.
those instantiated with -device option).

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Eric Auger <eric.auger@linaro.org>

---

v2:
- Code moved in an arch specific file to accomodate architecture
  dependent specificities.
- remove platform_bus_base from PlatformDevtreeData

v1: code originally written by Alex Graf in e500.c and reused for ARM
    [Eric Auger]
    code originally moved in hw/misc/platform_devices and device itself
---
 hw/arm/Makefile.objs                |  1 +
 hw/arm/dyn_sysbus_devtree.c         | 66 +++++++++++++++++++++++++++++++++++++
 include/hw/arm/dyn_sysbus_devtree.h | 18 ++++++++++
 3 files changed, 85 insertions(+)
 create mode 100644 hw/arm/dyn_sysbus_devtree.c
 create mode 100644 include/hw/arm/dyn_sysbus_devtree.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 6088e53..bc5e014 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -3,6 +3,7 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
 obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
 obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
 obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
+obj-y += dyn_sysbus_devtree.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-$(CONFIG_DIGIC) += digic.o
diff --git a/hw/arm/dyn_sysbus_devtree.c b/hw/arm/dyn_sysbus_devtree.c
new file mode 100644
index 0000000..56af62f
--- /dev/null
+++ b/hw/arm/dyn_sysbus_devtree.c
@@ -0,0 +1,66 @@
+#include "hw/arm/dyn_sysbus_devtree.h"
+#include "qemu/error-report.h"
+#include "sysemu/device_tree.h"
+
+int sysbus_device_create_devtree(Object *obj, void *opaque)
+{
+    PlatformDevtreeData *data = opaque;
+    Object *dev;
+    SysBusDevice *sbdev;
+    bool matched = false;
+
+    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
+    sbdev = (SysBusDevice *)dev;
+
+    if (!sbdev) {
+        /* Container, traverse it for children */
+        return object_child_foreach(obj, sysbus_device_create_devtree, data);
+    }
+
+    if (!matched) {
+        error_report("Device %s is not supported by this machine yet.",
+                     qdev_fw_name(DEVICE(dev)));
+        exit(1);
+    }
+
+    return 0;
+}
+
+void platform_bus_create_devtree(DynSysbusParams *params,
+                                 void *fdt, const char *mpic)
+{
+    gchar *node = g_strdup_printf("/platform@%"PRIx64,
+                                  params->platform_bus_base);
+    const char platcomp[] = "qemu,platform\0simple-bus";
+    PlatformDevtreeData data;
+    Object *container;
+    uint64_t addr = params->platform_bus_base;
+    uint64_t size = params->platform_bus_size;
+    int irq_start = params->platform_bus_first_irq;
+
+    /* 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);
+
+    /* Loop through all devices and create nodes for known ones */
+    data.fdt = fdt;
+    data.mpic = mpic;
+    data.irq_start = irq_start;
+    data.node = node;
+
+    container = container_get(qdev_get_machine(), "/peripheral");
+    sysbus_device_create_devtree(container, &data);
+    container = container_get(qdev_get_machine(), "/peripheral-anon");
+    sysbus_device_create_devtree(container, &data);
+
+    g_free(node);
+}
diff --git a/include/hw/arm/dyn_sysbus_devtree.h b/include/hw/arm/dyn_sysbus_devtree.h
new file mode 100644
index 0000000..808d522
--- /dev/null
+++ b/include/hw/arm/dyn_sysbus_devtree.h
@@ -0,0 +1,18 @@
+#ifndef HW_ARM_DYN_SYSBUS_DEVTREE_H
+#define HW_ARM_DYN_SYSBUS_DEVTREE_H
+
+#include "hw/misc/dyn_sysbus_binding.h"
+
+typedef struct PlatformDevtreeData {
+    void *fdt;
+    const char *mpic;
+    int irq_start;
+    const char *node;
+} PlatformDevtreeData;
+
+int sysbus_device_create_devtree(Object *obj, void *opaque);
+
+void platform_bus_create_devtree(DynSysbusParams *params,
+                                 void *fdt, const char *mpic);
+
+#endif
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 3/7] PPC: e500: Support dynamically spawned sysbus devices
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 4/7] e500: Add support for eTSEC in device tree Eric Auger
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

From: Alexander Graf <agraf@suse.de>

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 <agraf@suse.de>
Signed-off-by: Eric Auger <eric.auger@linaro.org>

---

v1 -> v2
[Eric Auger]
- use platform_bus_init_notify located in hw/misc/dyn_sysbus_binding.c
  and new DynSysbusParams that contains dynamic sysbus settings
- PPCE500Params includes a DynSysbusParams struct
- e500plat_init initializes this struct

v1
code written by Alex Graf
---
 hw/ppc/e500.c     | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ppc/e500.h     |  2 ++
 hw/ppc/e500plat.c |  9 ++++++
 3 files changed, 103 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 1a5b30d..0ee8cbf 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/misc/dyn_sysbus_binding.h"
 
 #define EPAPR_MAGIC                (0x45504150)
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
@@ -47,6 +49,8 @@
 
 #define RAM_SIZES_ALIGN            (64UL << 20)
 
+#define E500_PLATFORM_BUS_PAGE_SHIFT 12
+
 /* TODO: parameterize */
 #define MPC8544_CCSRBAR_BASE       0xE0000000ULL
 #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
@@ -122,6 +126,77 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
     }
 }
 
+typedef struct PlatformDevtreeData {
+    void *fdt;
+    const char *mpic;
+    int irq_start;
+    const char *node;
+} PlatformDevtreeData;
+
+static int sysbus_device_create_devtree(Object *obj, void *opaque)
+{
+    PlatformDevtreeData *data = opaque;
+    Object *dev;
+    SysBusDevice *sbdev;
+    bool matched = false;
+
+    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
+    sbdev = (SysBusDevice *)dev;
+
+    if (!sbdev) {
+        /* Container, traverse it for children */
+        return object_child_foreach(obj, sysbus_device_create_devtree, data);
+    }
+
+    if (!matched) {
+        error_report("Device %s is not supported by this machine yet.",
+                     qdev_fw_name(DEVICE(dev)));
+        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->dyn_sysbus_params.platform_bus_base);
+    const char platcomp[] = "qemu,platform\0simple-bus";
+    PlatformDevtreeData data;
+    Object *container;
+    uint64_t addr = params->dyn_sysbus_params.platform_bus_base;
+    uint64_t size = params->dyn_sysbus_params.platform_bus_size;
+    int irq_start = params->dyn_sysbus_params.platform_bus_first_irq;
+
+    /* 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);
+
+    /* Loop through all devices and create nodes for known ones */
+
+    data.fdt = fdt;
+    data.mpic = mpic;
+    data.irq_start = irq_start;
+    data.node = node;
+
+    container = container_get(qdev_get_machine(), "/peripheral");
+    sysbus_device_create_devtree(container, &data);
+    container = container_get(qdev_get_machine(), "/peripheral-anon");
+    sysbus_device_create_devtree(container, &data);
+
+    g_free(node);
+}
+
 static int ppce500_load_device_tree(MachineState *machine,
                                     PPCE500Params *params,
                                     hwaddr addr,
@@ -379,6 +454,10 @@ static int ppce500_load_device_tree(MachineState *machine,
     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
 
+    if (params->dyn_sysbus_params.has_platform_bus) {
+        platform_bus_create_devtree(params, fdt, mpic);
+    }
+
     params->fixup_devtree(params, fdt);
 
     if (toplevel_compat) {
@@ -769,6 +848,19 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
         cur_base = (32 * 1024 * 1024);
     }
 
+    /* Platform Devices */
+    if (params->dyn_sysbus_params.has_platform_bus) {
+        DynSysbusNotifier *notifier = g_new(DynSysbusNotifier, 1);
+        params->dyn_sysbus_params.page_shift =
+            E500_PLATFORM_BUS_PAGE_SHIFT;
+
+        notifier->notifier.notify = platform_bus_init_notify;
+        notifier->address_space_mem = address_space_mem;
+        notifier->mpic = mpic;
+        notifier->params = params->dyn_sysbus_params;
+        qemu_add_machine_init_done_notifier(&notifier->notifier);
+    }
+
     /* Load kernel. */
     if (machine->kernel_filename) {
         kernel_base = cur_base;
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 08b25fa..c191f9d 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -2,6 +2,7 @@
 #define PPCE500_H
 
 #include "hw/boards.h"
+#include "hw/misc/dyn_sysbus_binding.h"
 
 typedef struct PPCE500Params {
     int pci_first_slot;
@@ -11,6 +12,7 @@ typedef struct PPCE500Params {
     void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
 
     int mpic_version;
+    DynSysbusParams dyn_sysbus_params;
 } PPCE500Params;
 
 void ppce500_init(MachineState *machine, PPCE500Params *params);
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index 27df31d..4150a2c 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -35,6 +35,14 @@ static void e500plat_init(MachineState *machine)
         .pci_nr_slots = PCI_SLOT_MAX - 1,
         .fixup_devtree = e500plat_fixup_devtree,
         .mpic_version = OPENPIC_MODEL_FSL_MPIC_42,
+        .dyn_sysbus_params = {
+            .has_platform_bus = true,
+            .platform_bus_base = 0xf00000000ULL,
+            .platform_bus_size = (128ULL * 1024 * 1024),
+            .platform_bus_first_irq = 5,
+            .platform_bus_num_irqs = 10,
+            .page_shift = 12 /* default */
+        }
     };
 
     /* Older KVM versions don't support EPR which breaks guests when we announce
@@ -51,6 +59,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)
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 4/7] e500: Add support for eTSEC in device tree
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
                   ` (2 preceding siblings ...)
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 3/7] PPC: e500: Support dynamically spawned sysbus devices Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static Eric Auger
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

From: Alexander Graf <agraf@suse.de>

This patch adds support to expose eTSEC devices in the dynamically created
guest facing device tree. This allows us to expose eTSEC devices into guests
without changes in the machine file.

Because we can now tell the guest about eTSEC devices this patch allows the
user to specify eTSEC devices via -device at all.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/ppc/e500.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 0ee8cbf..7a23245 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -38,6 +38,7 @@
 #include "hw/pci-host/ppce500.h"
 #include "qemu/error-report.h"
 #include "hw/misc/dyn_sysbus_binding.h"
+#include "hw/net/fsl_etsec/etsec.h"
 
 #define EPAPR_MAGIC                (0x45504150)
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
@@ -133,6 +134,37 @@ typedef struct PlatformDevtreeData {
     const char *node;
 } PlatformDevtreeData;
 
+static int create_devtree_etsec(eTSEC *etsec, PlatformDevtreeData *data)
+{
+    Object *obj = OBJECT(etsec);
+    uint64_t mmio0 = object_property_get_int(obj, "mmio[0]", NULL);
+    uint64_t irq0 = object_property_get_int(obj, "irq[0]", NULL);
+    uint64_t irq1 = object_property_get_int(obj, "irq[1]", NULL);
+    uint64_t irq2 = object_property_get_int(obj, "irq[2]", NULL);
+    gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
+    gchar *group = g_strdup_printf("%s/queue-group", node);
+    void *fdt = data->fdt;
+
+    qemu_fdt_add_subnode(fdt, node);
+    qemu_fdt_setprop_string(fdt, node, "device_type", "network");
+    qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
+    qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
+    qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
+    qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
+
+    qemu_fdt_add_subnode(fdt, group);
+    qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
+    qemu_fdt_setprop_cells(fdt, group, "interrupts",
+        data->irq_start + irq0, 0x2,
+        data->irq_start + irq1, 0x2,
+        data->irq_start + irq2, 0x2);
+
+    g_free(node);
+    g_free(group);
+
+    return 0;
+}
+
 static int sysbus_device_create_devtree(Object *obj, void *opaque)
 {
     PlatformDevtreeData *data = opaque;
@@ -148,6 +180,11 @@ static int sysbus_device_create_devtree(Object *obj, void *opaque)
         return object_child_foreach(obj, sysbus_device_create_devtree, data);
     }
 
+    if (object_dynamic_cast(obj, TYPE_ETSEC_COMMON)) {
+        create_devtree_etsec(ETSEC_COMMON(dev), data);
+        matched = true;
+    }
+
     if (!matched) {
         error_report("Device %s is not supported by this machine yet.",
                      qdev_fw_name(DEVICE(dev)));
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
                   ` (3 preceding siblings ...)
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 4/7] e500: Add support for eTSEC in device tree Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  2014-08-11 13:10   ` Alexander Graf
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 6/7] hw/arm/virt: add new add_fdt_xxx_node functions Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 7/7] hw/arm/virt: Support dynamically spawned sysbus devices Eric Auger
  6 siblings, 1 reply; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

load_dtb will be used by machvirt for dynamic instantiation of
platform devices

Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
 hw/arm/boot.c        | 2 +-
 include/hw/arm/arm.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 1241761..53b43e8 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -312,7 +312,7 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
     }
 }
 
-static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
+int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
 {
     void *fdt = NULL;
     int size, rc;
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index cbbf4ca..fe58dc0 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -68,6 +68,7 @@ struct arm_boot_info {
     hwaddr entry;
 };
 void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
+int load_dtb(hwaddr addr, const struct arm_boot_info *binfo);
 
 /* Multiplication factor to convert from system clock ticks to qemu timer
    ticks.  */
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 6/7] hw/arm/virt: add new add_fdt_xxx_node functions
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
                   ` (4 preceding siblings ...)
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 7/7] hw/arm/virt: Support dynamically spawned sysbus devices Eric Auger
  6 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

Create new functions:
- add_fdt_uart_node
- add_fdt_rtc_node
- add_fdt_virtio_nodes

They will be used for dynamic sysbus instantiation.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
 hw/arm/virt.c | 67 +++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 44 insertions(+), 23 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 66103c2..1a18a5a 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -337,18 +337,15 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
     fdt_add_gic_node(vbi);
 }
 
-static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
+static void fdt_add_uart_node(const VirtBoardInfo *vbi)
 {
-    char *nodename;
     hwaddr base = vbi->memmap[VIRT_UART].base;
     hwaddr size = vbi->memmap[VIRT_UART].size;
     int irq = vbi->irqmap[VIRT_UART];
     const char compat[] = "arm,pl011\0arm,primecell";
     const char clocknames[] = "uartclk\0apb_pclk";
+    char *nodename = g_strdup_printf("/pl011@%" PRIx64, base);
 
-    sysbus_create_simple("pl011", base, pic[irq]);
-
-    nodename = g_strdup_printf("/pl011@%" PRIx64, base);
     qemu_fdt_add_subnode(vbi->fdt, nodename);
     /* Note that we can't use setprop_string because of the embedded NUL */
     qemu_fdt_setprop(vbi->fdt, nodename, "compatible",
@@ -365,17 +362,23 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
     g_free(nodename);
 }
 
-static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
+static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
+{
+    hwaddr base = vbi->memmap[VIRT_UART].base;
+    int irq = vbi->irqmap[VIRT_UART];
+
+    sysbus_create_simple("pl011", base, pic[irq]);
+    fdt_add_uart_node(vbi);
+}
+
+static void fdt_add_rtc_node(const VirtBoardInfo *vbi)
 {
-    char *nodename;
     hwaddr base = vbi->memmap[VIRT_RTC].base;
     hwaddr size = vbi->memmap[VIRT_RTC].size;
     int irq = vbi->irqmap[VIRT_RTC];
     const char compat[] = "arm,pl031\0arm,primecell";
+    char *nodename = g_strdup_printf("/pl031@%" PRIx64, base);
 
-    sysbus_create_simple("pl031", base, pic[irq]);
-
-    nodename = g_strdup_printf("/pl031@%" PRIx64, base);
     qemu_fdt_add_subnode(vbi->fdt, nodename);
     qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat));
     qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
@@ -388,22 +391,20 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
     g_free(nodename);
 }
 
-static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
+static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
 {
-    int i;
-    hwaddr size = vbi->memmap[VIRT_MMIO].size;
+    hwaddr base = vbi->memmap[VIRT_RTC].base;
+    int irq = vbi->irqmap[VIRT_RTC];
 
-    /* Note that we have to create the transports in forwards order
-     * so that command line devices are inserted lowest address first,
-     * and then add dtb nodes in reverse order so that they appear in
-     * the finished device tree lowest address first.
-     */
-    for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
-        int irq = vbi->irqmap[VIRT_MMIO] + i;
-        hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
+    sysbus_create_simple("pl031", base, pic[irq]);
 
-        sysbus_create_simple("virtio-mmio", base, pic[irq]);
-    }
+    fdt_add_rtc_node(vbi);
+}
+
+static void fdt_add_virtio_nodes(const VirtBoardInfo *vbi)
+{
+    int i;
+    hwaddr size = vbi->memmap[VIRT_MMIO].size;
 
     for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
         char *nodename;
@@ -423,6 +424,26 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
     }
 }
 
+static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
+{
+    int i;
+    hwaddr size = vbi->memmap[VIRT_MMIO].size;
+
+    /* Note that we have to create the transports in forwards order
+     * so that command line devices are inserted lowest address first,
+     * and then add dtb nodes in reverse order so that they appear in
+     * the finished device tree lowest address first.
+     */
+    for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
+        int irq = vbi->irqmap[VIRT_MMIO] + i;
+        hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
+
+        sysbus_create_simple("virtio-mmio", base, pic[irq]);
+    }
+
+    fdt_add_virtio_nodes(vbi);
+}
+
 static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
 {
     const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [RFC v2 7/7] hw/arm/virt: Support dynamically spawned sysbus devices
  2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
                   ` (5 preceding siblings ...)
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 6/7] hw/arm/virt: add new add_fdt_xxx_node functions Eric Auger
@ 2014-08-08 15:03 ` Eric Auger
  6 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-08 15:03 UTC (permalink / raw)
  To: eric.auger, christoffer.dall, qemu-devel, kim.phillips, a.rigo
  Cc: peter.maydell, eric.auger, patches, will.deacon, agraf,
	stuart.yoder, Bharat.Bhushan, alex.williamson, a.motakis, kvmarm

Allows sysbus devices to be instantiated from command line by
using -device option

---

v1 -> v2:
- remove useless vfio-platform.h include file
- s/MACHVIRT_PLATFORM_HOLE/MACHVIRT_PLATFORM_SIZE
- use dyn_sysbus_binding and dyn_sysbus_devtree
- dynamic sysbus platform buse size shrinked to 4MB and
  moved between RTC and MMIO

v1:

Inspired from what Alex Graf did in ppc e500
https://lists.gnu.org/archive/html/qemu-ppc/2014-07/msg00012.html

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
 hw/arm/virt.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1a18a5a..06f4fad 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -40,6 +40,8 @@
 #include "exec/address-spaces.h"
 #include "qemu/bitops.h"
 #include "qemu/error-report.h"
+#include "hw/misc/dyn_sysbus_binding.h"
+#include "hw/arm/dyn_sysbus_devtree.h"
 
 #define NUM_VIRTIO_TRANSPORTS 32
 
@@ -57,6 +59,14 @@
 #define GIC_FDT_IRQ_PPI_CPU_START 8
 #define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
 
+#define MACHVIRT_PLATFORM_BASE         0x9400000
+#define MACHVIRT_PLATFORM_SIZE         (4ULL * 1024 * 1024) /* 4 MB */
+#define MACHVIRT_PLATFORM_PAGE_SHIFT   12
+#define MACHVIRT_PLATFORM_SIZE_PAGES   (MACHVIRT_PLATFORM_SIZE >> \
+                                    MACHVIRT_PLATFORM_PAGE_SHIFT)
+#define MACHVIRT_PLATFORM_FIRST_IRQ    48
+#define MACHVIRT_PLATFORM_NUM_IRQS     20
+
 enum {
     VIRT_FLASH,
     VIRT_MEM,
@@ -66,6 +76,7 @@ enum {
     VIRT_UART,
     VIRT_MMIO,
     VIRT_RTC,
+    VIRT_PLATFORM,
 };
 
 typedef struct MemMapEntry {
@@ -105,16 +116,27 @@ static const MemMapEntry a15memmap[] = {
     [VIRT_GIC_CPU] =    { 0x08010000, 0x00010000 },
     [VIRT_UART] =       { 0x09000000, 0x00001000 },
     [VIRT_RTC] =        { 0x09010000, 0x00001000 },
+    [VIRT_PLATFORM] = {MACHVIRT_PLATFORM_BASE , MACHVIRT_PLATFORM_SIZE},
     [VIRT_MMIO] =       { 0x0a000000, 0x00000200 },
     /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
     /* 0x10000000 .. 0x40000000 reserved for PCI */
-    [VIRT_MEM] =        { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
+    [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
 };
 
 static const int a15irqmap[] = {
     [VIRT_UART] = 1,
     [VIRT_RTC] = 2,
     [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
+    [VIRT_PLATFORM] = MACHVIRT_PLATFORM_FIRST_IRQ,
+};
+
+static DynSysbusParams dyn_sysbus_platform_params = {
+    .has_platform_bus = true,
+    .platform_bus_base = MACHVIRT_PLATFORM_BASE,
+    .platform_bus_size = MACHVIRT_PLATFORM_SIZE,
+    .platform_bus_first_irq = MACHVIRT_PLATFORM_FIRST_IRQ,
+    .platform_bus_num_irqs = MACHVIRT_PLATFORM_NUM_IRQS,
+    .page_shift = MACHVIRT_PLATFORM_PAGE_SHIFT,
 };
 
 static VirtBoardInfo machines[] = {
@@ -444,6 +466,18 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
     fdt_add_virtio_nodes(vbi);
 }
 
+static void machvirt_prep_device_tree(VirtBoardInfo *vbi)
+{
+    create_fdt(vbi);
+    fdt_add_timer_nodes(vbi);
+    fdt_add_cpu_nodes(vbi);
+    fdt_add_psci_node(vbi);
+    fdt_add_gic_node(vbi);
+    fdt_add_uart_node(vbi);
+    fdt_add_rtc_node(vbi);
+    fdt_add_virtio_nodes(vbi);
+}
+
 static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
 {
     const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@@ -452,14 +486,28 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
     return board->fdt;
 }
 
+static void machvirt_reset_device_tree(void *opaque)
+{
+    VirtBoardInfo *board = (VirtBoardInfo *)opaque;
+    struct arm_boot_info *info = &board->bootinfo;
+    hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + info->initrd_size,
+                                     4096);
+    machvirt_prep_device_tree(board);
+    platform_bus_create_devtree(&dyn_sysbus_platform_params,
+                                board->fdt, "/intc");
+
+    load_dtb(dtb_start, info);
+}
+
 static void machvirt_init(MachineState *machine)
 {
-    qemu_irq pic[NUM_IRQS];
+    qemu_irq *pic = g_new(qemu_irq, NUM_IRQS);
     MemoryRegion *sysmem = get_system_memory();
     int n;
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     const char *cpu_model = machine->cpu_model;
     VirtBoardInfo *vbi;
+    DynSysbusNotifier *notifier;
 
     if (!cpu_model) {
         cpu_model = "cortex-a15";
@@ -533,6 +581,13 @@ static void machvirt_init(MachineState *machine)
      */
     create_virtio_devices(vbi, pic);
 
+    notifier = g_new(DynSysbusNotifier, 1);
+    notifier->notifier.notify = platform_bus_init_notify;
+    notifier->address_space_mem = sysmem;
+    notifier->mpic = pic;
+    notifier->params = dyn_sysbus_platform_params;
+    qemu_add_machine_init_done_notifier(&notifier->notifier);
+
     vbi->bootinfo.ram_size = machine->ram_size;
     vbi->bootinfo.kernel_filename = machine->kernel_filename;
     vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
@@ -542,6 +597,8 @@ static void machvirt_init(MachineState *machine)
     vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
     vbi->bootinfo.get_dtb = machvirt_dtb;
     arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
+
+    qemu_register_reset(machvirt_reset_device_tree, vbi);
 }
 
 static QEMUMachine machvirt_a15_machine = {
@@ -549,6 +606,7 @@ static QEMUMachine machvirt_a15_machine = {
     .desc = "ARM Virtual Machine",
     .init = machvirt_init,
     .max_cpus = 4,
+    .has_dynamic_sysbus = true,
 };
 
 static void machvirt_machine_init(void)
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding Eric Auger
@ 2014-08-11 13:08   ` Alexander Graf
  2014-08-11 13:16     ` Eric Auger
  0 siblings, 1 reply; 14+ messages in thread
From: Alexander Graf @ 2014-08-11 13:08 UTC (permalink / raw)
  To: Eric Auger, eric.auger, christoffer.dall, qemu-devel,
	kim.phillips, a.rigo
  Cc: peter.maydell, patches, will.deacon, stuart.yoder, Bharat.Bhushan,
	alex.williamson, a.motakis, kvmarm


On 08.08.14 17:03, Eric Auger wrote:
> This new module implements routines which help in dynamic device
> binding (mmio regions, irq). They are supposed to be used by machine
> files that support dynamic sysbus instantiation.
>
> ---
>
> v1 -> v2:
> - platform_devices renamed into dyn_sysbus_binding
> - PlatformParams renamed into DynSysbusParams
> - PlatformBusNotifier renamed into DynSysbusNotifier
> - platform_bus_map_irq, platform_bus_map_mmio, sysbus_device_check,
>    platform_bus_init become static
> - PlatformBusInitData becomes private to the module
> - page_shift becomes a member of DynSysbusParams
>
> v1: Dynamic sysbus device allocation fully written by Alex Graf.
> Those functions were initially in ppc e500 machine file. Now moved to a
> separate module.
> PPCE500Params is replaced by a generic struct named PlatformParams
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> ---
>   hw/misc/Makefile.objs                |   1 +
>   hw/misc/dyn_sysbus_binding.c         | 163 +++++++++++++++++++++++++++++++++++
>   include/hw/misc/dyn_sysbus_binding.h |  24 ++++++
>   3 files changed, 188 insertions(+)
>   create mode 100644 hw/misc/dyn_sysbus_binding.c
>   create mode 100644 include/hw/misc/dyn_sysbus_binding.h
>
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 979e532..86f6243 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
>   obj-$(CONFIG_ZYNQ) += zynq_slcr.o
>   
>   obj-$(CONFIG_PVPANIC) += pvpanic.o
> +obj-y += dyn_sysbus_binding.o
> diff --git a/hw/misc/dyn_sysbus_binding.c b/hw/misc/dyn_sysbus_binding.c
> new file mode 100644
> index 0000000..0f34f0b
> --- /dev/null
> +++ b/hw/misc/dyn_sysbus_binding.c
> @@ -0,0 +1,163 @@

This file is missing a license header.

> +#include "hw/misc/dyn_sysbus_binding.h"
> +#include "qemu/error-report.h"
> +
> +typedef struct PlatformBusInitData {
> +    unsigned long *used_irqs;
> +    unsigned long *used_mem;
> +    MemoryRegion *mem;
> +    qemu_irq *irqs;
> +    int device_count;
> +    DynSysbusParams *params;
> +} PlatformBusInitData;
> +
> +
> +static int platform_bus_map_irq(DynSysbusParams *params,
> +                                SysBusDevice *sbdev,
> +                                int n, unsigned long *used_irqs,
> +                                qemu_irq *platform_irqs)
> +{
> +    int max_irqs = params->platform_bus_num_irqs;
> +    char *prop = g_strdup_printf("irq[%d]", n);
> +    int irqn = object_property_get_int(OBJECT(sbdev), prop, NULL);
> +
> +    if (irqn == SYSBUS_DYNAMIC) {
> +        /* Find the first available IRQ */
> +        irqn = find_first_zero_bit(used_irqs, max_irqs);
> +    }
> +
> +    if ((irqn >= max_irqs) || test_and_set_bit(irqn, used_irqs)) {
> +        hw_error("IRQ %d is already allocated or no free IRQ left", irqn);
> +    }
> +
> +    sysbus_connect_irq(sbdev, n, platform_irqs[irqn]);
> +    object_property_set_int(OBJECT(sbdev), irqn, prop, NULL);
> +
> +    g_free(prop);
> +    return 0;
> +}
> +
> +static int platform_bus_map_mmio(DynSysbusParams *params,
> +                                 SysBusDevice *sbdev,
> +                                 int n, unsigned long *used_mem,
> +                                 MemoryRegion *pmem)
> +{
> +    MemoryRegion *device_mem = sbdev->mmio[n].memory;
> +    uint64_t size = memory_region_size(device_mem);
> +    uint64_t page_size = (1 << params->page_shift);
> +    uint64_t page_mask = page_size - 1;
> +    uint64_t size_pages = (size + page_mask) >> params->page_shift;
> +    uint64_t max_size = params->platform_bus_size;
> +    uint64_t max_pages = max_size >> params->page_shift;
> +    char *prop = g_strdup_printf("mmio[%d]", n);
> +    hwaddr addr = object_property_get_int(OBJECT(sbdev), prop, NULL);
> +    int page;
> +    int i;
> +
> +    page = addr >> params->page_shift;
> +    if (addr == SYSBUS_DYNAMIC) {
> +        uint64_t size_pages_align;
> +
> +        /* Align the region to at least its own size granularity */
> +        if (is_power_of_2(size_pages)) {
> +            size_pages_align = size_pages;
> +        } else {
> +            size_pages_align = pow2floor(size_pages) << 1;
> +        }
> +
> +        /* Find the first available region that fits */
> +        page = bitmap_find_next_zero_area(used_mem, max_pages, 0, size_pages,
> +                                          size_pages_align);
> +
> +        addr = (uint64_t)page << params->page_shift;
> +    }
> +
> +    if (page >= max_pages || test_bit(page, used_mem) ||
> +        (find_next_bit(used_mem, max_pages, page) < size_pages)) {
> +        hw_error("Memory [%"PRIx64":%"PRIx64" is already allocated or "
> +                 "no slot left", addr, size);
> +    }
> +
> +    for (i = page; i < (page + size_pages); i++) {
> +        set_bit(i, used_mem);
> +    }
> +
> +    memory_region_add_subregion(pmem, addr, device_mem);
> +    sbdev->mmio[n].addr = addr;
> +    object_property_set_int(OBJECT(sbdev), addr, prop, NULL);
> +
> +    g_free(prop);
> +    return 0;
> +}
> +
> +static int sysbus_device_check(Object *obj, void *opaque)
> +{
> +    PlatformBusInitData *init = opaque;
> +    Object *dev;
> +    SysBusDevice *sbdev;
> +    int i;
> +
> +    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
> +    sbdev = (SysBusDevice *)dev;
> +
> +    if (!sbdev) {
> +        /* Container, traverse it for children */
> +        return object_child_foreach(obj, sysbus_device_check, opaque);
> +    }
> +
> +    /* Connect sysbus device to virtual platform bus */
> +    for (i = 0; i < sbdev->num_irq; i++) {
> +        if (!sbdev->irqp[i]) {
> +            /* This IRQ is an incoming IRQ, we can't wire those here */
> +            continue;
> +        }
> +        platform_bus_map_irq(init->params, sbdev, i,
> +                             init->used_irqs, init->irqs);
> +    }
> +
> +    for (i = 0; i < sbdev->num_mmio; i++) {
> +        platform_bus_map_mmio(init->params, sbdev, i,
> +                              init->used_mem, init->mem);
> +    }
> +
> +    return 0;
> +}
> +
> +static void platform_bus_init(DynSysbusParams *params,
> +                       MemoryRegion *address_space_mem,
> +                       qemu_irq *mpic)

You probably don't want to call it "mpic" in generic code - you're using 
a GIC after all on ARM.

Also I think it'd be better if you actually transform my patch set into 
the generic variant. That way I can push mine upstream and then your 
patch set makes that copy generic.


Alex

> +{
> +    uint64_t max_size = params->platform_bus_size;
> +    uint64_t max_pages = max_size >> params->page_shift;
> +    DECLARE_BITMAP(used_irqs, params->platform_bus_num_irqs);
> +    DECLARE_BITMAP(used_mem, max_pages);
> +    MemoryRegion *platform_region = g_new(MemoryRegion, 1);
> +    Object *container;
> +    PlatformBusInitData init = {
> +        .used_irqs = used_irqs,
> +        .used_mem = used_mem,
> +        .mem = platform_region,
> +        .irqs = &mpic[params->platform_bus_first_irq],
> +        .params = params,
> +    };
> +
> +    memory_region_init(platform_region, NULL, "platform devices",
> +                       params->platform_bus_size);
> +
> +    bitmap_clear(used_irqs, 0, params->platform_bus_num_irqs);
> +    bitmap_clear(used_mem, 0, max_pages);
> +
> +    /* Loop through all sysbus devices that were spawened outside the machine */
> +    container = container_get(qdev_get_machine(), "/peripheral");
> +    sysbus_device_check(container, &init);
> +    container = container_get(qdev_get_machine(), "/peripheral-anon");
> +    sysbus_device_check(container, &init);
> +
> +    memory_region_add_subregion(address_space_mem, params->platform_bus_base,
> +                                platform_region);
> +}
> +
> +void platform_bus_init_notify(Notifier *notifier, void *data)
> +{
> +    DynSysbusNotifier *pn = (DynSysbusNotifier *)notifier;
> +    platform_bus_init(&pn->params, pn->address_space_mem, pn->mpic);
> +}
> diff --git a/include/hw/misc/dyn_sysbus_binding.h b/include/hw/misc/dyn_sysbus_binding.h
> new file mode 100644
> index 0000000..961c9c7
> --- /dev/null
> +++ b/include/hw/misc/dyn_sysbus_binding.h
> @@ -0,0 +1,24 @@
> +#ifndef HW_MISC_PLATFORM_DEVICES_H
> +#define HW_MISC_PLATFORM_DEVICES_H
> +
> +#include "qemu-common.h"
> +#include "hw/sysbus.h"
> +
> +typedef struct {
> +    bool has_platform_bus;
> +    hwaddr platform_bus_base;
> +    hwaddr platform_bus_size;
> +    int platform_bus_first_irq;
> +    int platform_bus_num_irqs;
> +    int page_shift;
> +} DynSysbusParams;
> +
> +typedef struct DynSysbusNotifier {
> +    Notifier notifier;
> +    MemoryRegion *address_space_mem;
> +    qemu_irq *mpic;
> +    DynSysbusParams params;
> +} DynSysbusNotifier;
> +
> +void platform_bus_init_notify(Notifier *notifier, void *data);
> +#endif

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static Eric Auger
@ 2014-08-11 13:10   ` Alexander Graf
  2014-08-11 13:18     ` Eric Auger
  0 siblings, 1 reply; 14+ messages in thread
From: Alexander Graf @ 2014-08-11 13:10 UTC (permalink / raw)
  To: Eric Auger, eric.auger, christoffer.dall, qemu-devel,
	kim.phillips, a.rigo
  Cc: peter.maydell, patches, will.deacon, stuart.yoder, Bharat.Bhushan,
	alex.williamson, a.motakis, kvmarm


On 08.08.14 17:03, Eric Auger wrote:
> load_dtb will be used by machvirt for dynamic instantiation of
> platform devices
>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> ---
>   hw/arm/boot.c        | 2 +-
>   include/hw/arm/arm.h | 1 +
>   2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
> index 1241761..53b43e8 100644
> --- a/hw/arm/boot.c
> +++ b/hw/arm/boot.c
> @@ -312,7 +312,7 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
>       }
>   }
>   
> -static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
> +int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)

Please rename it arm_load_dtb then.


Alex

>   {
>       void *fdt = NULL;
>       int size, rc;
> diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
> index cbbf4ca..fe58dc0 100644
> --- a/include/hw/arm/arm.h
> +++ b/include/hw/arm/arm.h
> @@ -68,6 +68,7 @@ struct arm_boot_info {
>       hwaddr entry;
>   };
>   void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
> +int load_dtb(hwaddr addr, const struct arm_boot_info *binfo);
>   
>   /* Multiplication factor to convert from system clock ticks to qemu timer
>      ticks.  */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation
  2014-08-08 15:03 ` [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation Eric Auger
@ 2014-08-11 13:16   ` Alexander Graf
  2014-08-11 13:17     ` Eric Auger
  0 siblings, 1 reply; 14+ messages in thread
From: Alexander Graf @ 2014-08-11 13:16 UTC (permalink / raw)
  To: Eric Auger, eric.auger, christoffer.dall, qemu-devel,
	kim.phillips, a.rigo
  Cc: peter.maydell, patches, will.deacon, stuart.yoder, Bharat.Bhushan,
	alex.williamson, a.motakis, kvmarm


On 08.08.14 17:03, Eric Auger wrote:
> This module will be used by ARM machine files to generate
> device tree nodes of dynamically instantiated sysbus devices (ie.
> those instantiated with -device option).
>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>
> ---
>
> v2:
> - Code moved in an arch specific file to accomodate architecture
>    dependent specificities.
> - remove platform_bus_base from PlatformDevtreeData
>
> v1: code originally written by Alex Graf in e500.c and reused for ARM
>      [Eric Auger]
>      code originally moved in hw/misc/platform_devices and device itself
> ---
>   hw/arm/Makefile.objs                |  1 +
>   hw/arm/dyn_sysbus_devtree.c         | 66 +++++++++++++++++++++++++++++++++++++
>   include/hw/arm/dyn_sysbus_devtree.h | 18 ++++++++++
>   3 files changed, 85 insertions(+)
>   create mode 100644 hw/arm/dyn_sysbus_devtree.c
>   create mode 100644 include/hw/arm/dyn_sysbus_devtree.h
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 6088e53..bc5e014 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -3,6 +3,7 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
>   obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
>   obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
>   obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
> +obj-y += dyn_sysbus_devtree.o
>   
>   obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
>   obj-$(CONFIG_DIGIC) += digic.o
> diff --git a/hw/arm/dyn_sysbus_devtree.c b/hw/arm/dyn_sysbus_devtree.c
> new file mode 100644
> index 0000000..56af62f
> --- /dev/null
> +++ b/hw/arm/dyn_sysbus_devtree.c
> @@ -0,0 +1,66 @@
> +#include "hw/arm/dyn_sysbus_devtree.h"
> +#include "qemu/error-report.h"
> +#include "sysemu/device_tree.h"
> +
> +int sysbus_device_create_devtree(Object *obj, void *opaque)
> +{
> +    PlatformDevtreeData *data = opaque;
> +    Object *dev;
> +    SysBusDevice *sbdev;
> +    bool matched = false;
> +
> +    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
> +    sbdev = (SysBusDevice *)dev;
> +
> +    if (!sbdev) {
> +        /* Container, traverse it for children */
> +        return object_child_foreach(obj, sysbus_device_create_devtree, data);
> +    }
> +
> +    if (!matched) {
> +        error_report("Device %s is not supported by this machine yet.",
> +                     qdev_fw_name(DEVICE(dev)));
> +        exit(1);
> +    }
> +
> +    return 0;
> +}
> +
> +void platform_bus_create_devtree(DynSysbusParams *params,
> +                                 void *fdt, const char *mpic)
> +{
> +    gchar *node = g_strdup_printf("/platform@%"PRIx64,
> +                                  params->platform_bus_base);
> +    const char platcomp[] = "qemu,platform\0simple-bus";
> +    PlatformDevtreeData data;
> +    Object *container;
> +    uint64_t addr = params->platform_bus_base;
> +    uint64_t size = params->platform_bus_size;
> +    int irq_start = params->platform_bus_first_irq;
> +
> +    /* 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);
> +
> +    /* Loop through all devices and create nodes for known ones */
> +    data.fdt = fdt;
> +    data.mpic = mpic;
> +    data.irq_start = irq_start;
> +    data.node = node;
> +
> +    container = container_get(qdev_get_machine(), "/peripheral");
> +    sysbus_device_create_devtree(container, &data);
> +    container = container_get(qdev_get_machine(), "/peripheral-anon");
> +    sysbus_device_create_devtree(container, &data);
> +
> +    g_free(node);
> +}
> diff --git a/include/hw/arm/dyn_sysbus_devtree.h b/include/hw/arm/dyn_sysbus_devtree.h
> new file mode 100644
> index 0000000..808d522
> --- /dev/null
> +++ b/include/hw/arm/dyn_sysbus_devtree.h
> @@ -0,0 +1,18 @@
> +#ifndef HW_ARM_DYN_SYSBUS_DEVTREE_H
> +#define HW_ARM_DYN_SYSBUS_DEVTREE_H
> +
> +#include "hw/misc/dyn_sysbus_binding.h"
> +
> +typedef struct PlatformDevtreeData {
> +    void *fdt;
> +    const char *mpic;
> +    int irq_start;
> +    const char *node;
> +} PlatformDevtreeData;
> +
> +int sysbus_device_create_devtree(Object *obj, void *opaque);
> +
> +void platform_bus_create_devtree(DynSysbusParams *params,
> +                                 void *fdt, const char *mpic);

These functions live in hw/arm and thus should have names that indicate 
they are arm specific.


Alex

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding
  2014-08-11 13:08   ` Alexander Graf
@ 2014-08-11 13:16     ` Eric Auger
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-11 13:16 UTC (permalink / raw)
  To: Alexander Graf, eric.auger, christoffer.dall, qemu-devel,
	kim.phillips, a.rigo
  Cc: peter.maydell, patches, will.deacon, stuart.yoder, Bharat.Bhushan,
	alex.williamson, a.motakis, kvmarm

On 08/11/2014 03:08 PM, Alexander Graf wrote:
> 
> On 08.08.14 17:03, Eric Auger wrote:
>> This new module implements routines which help in dynamic device
>> binding (mmio regions, irq). They are supposed to be used by machine
>> files that support dynamic sysbus instantiation.
>>
>> ---
>>
>> v1 -> v2:
>> - platform_devices renamed into dyn_sysbus_binding
>> - PlatformParams renamed into DynSysbusParams
>> - PlatformBusNotifier renamed into DynSysbusNotifier
>> - platform_bus_map_irq, platform_bus_map_mmio, sysbus_device_check,
>>    platform_bus_init become static
>> - PlatformBusInitData becomes private to the module
>> - page_shift becomes a member of DynSysbusParams
>>
>> v1: Dynamic sysbus device allocation fully written by Alex Graf.
>> Those functions were initially in ppc e500 machine file. Now moved to a
>> separate module.
>> PPCE500Params is replaced by a generic struct named PlatformParams
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>   hw/misc/Makefile.objs                |   1 +
>>   hw/misc/dyn_sysbus_binding.c         | 163
>> +++++++++++++++++++++++++++++++++++
>>   include/hw/misc/dyn_sysbus_binding.h |  24 ++++++
>>   3 files changed, 188 insertions(+)
>>   create mode 100644 hw/misc/dyn_sysbus_binding.c
>>   create mode 100644 include/hw/misc/dyn_sysbus_binding.h
>>
>> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
>> index 979e532..86f6243 100644
>> --- a/hw/misc/Makefile.objs
>> +++ b/hw/misc/Makefile.objs
>> @@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
>>   obj-$(CONFIG_ZYNQ) += zynq_slcr.o
>>     obj-$(CONFIG_PVPANIC) += pvpanic.o
>> +obj-y += dyn_sysbus_binding.o
>> diff --git a/hw/misc/dyn_sysbus_binding.c b/hw/misc/dyn_sysbus_binding.c
>> new file mode 100644
>> index 0000000..0f34f0b
>> --- /dev/null
>> +++ b/hw/misc/dyn_sysbus_binding.c
>> @@ -0,0 +1,163 @@
> 
> This file is missing a license header.
OK
> 
>> +#include "hw/misc/dyn_sysbus_binding.h"
>> +#include "qemu/error-report.h"
>> +
>> +typedef struct PlatformBusInitData {
>> +    unsigned long *used_irqs;
>> +    unsigned long *used_mem;
>> +    MemoryRegion *mem;
>> +    qemu_irq *irqs;
>> +    int device_count;
>> +    DynSysbusParams *params;
>> +} PlatformBusInitData;
>> +
>> +
>> +static int platform_bus_map_irq(DynSysbusParams *params,
>> +                                SysBusDevice *sbdev,
>> +                                int n, unsigned long *used_irqs,
>> +                                qemu_irq *platform_irqs)
>> +{
>> +    int max_irqs = params->platform_bus_num_irqs;
>> +    char *prop = g_strdup_printf("irq[%d]", n);
>> +    int irqn = object_property_get_int(OBJECT(sbdev), prop, NULL);
>> +
>> +    if (irqn == SYSBUS_DYNAMIC) {
>> +        /* Find the first available IRQ */
>> +        irqn = find_first_zero_bit(used_irqs, max_irqs);
>> +    }
>> +
>> +    if ((irqn >= max_irqs) || test_and_set_bit(irqn, used_irqs)) {
>> +        hw_error("IRQ %d is already allocated or no free IRQ left",
>> irqn);
>> +    }
>> +
>> +    sysbus_connect_irq(sbdev, n, platform_irqs[irqn]);
>> +    object_property_set_int(OBJECT(sbdev), irqn, prop, NULL);
>> +
>> +    g_free(prop);
>> +    return 0;
>> +}
>> +
>> +static int platform_bus_map_mmio(DynSysbusParams *params,
>> +                                 SysBusDevice *sbdev,
>> +                                 int n, unsigned long *used_mem,
>> +                                 MemoryRegion *pmem)
>> +{
>> +    MemoryRegion *device_mem = sbdev->mmio[n].memory;
>> +    uint64_t size = memory_region_size(device_mem);
>> +    uint64_t page_size = (1 << params->page_shift);
>> +    uint64_t page_mask = page_size - 1;
>> +    uint64_t size_pages = (size + page_mask) >> params->page_shift;
>> +    uint64_t max_size = params->platform_bus_size;
>> +    uint64_t max_pages = max_size >> params->page_shift;
>> +    char *prop = g_strdup_printf("mmio[%d]", n);
>> +    hwaddr addr = object_property_get_int(OBJECT(sbdev), prop, NULL);
>> +    int page;
>> +    int i;
>> +
>> +    page = addr >> params->page_shift;
>> +    if (addr == SYSBUS_DYNAMIC) {
>> +        uint64_t size_pages_align;
>> +
>> +        /* Align the region to at least its own size granularity */
>> +        if (is_power_of_2(size_pages)) {
>> +            size_pages_align = size_pages;
>> +        } else {
>> +            size_pages_align = pow2floor(size_pages) << 1;
>> +        }
>> +
>> +        /* Find the first available region that fits */
>> +        page = bitmap_find_next_zero_area(used_mem, max_pages, 0,
>> size_pages,
>> +                                          size_pages_align);
>> +
>> +        addr = (uint64_t)page << params->page_shift;
>> +    }
>> +
>> +    if (page >= max_pages || test_bit(page, used_mem) ||
>> +        (find_next_bit(used_mem, max_pages, page) < size_pages)) {
>> +        hw_error("Memory [%"PRIx64":%"PRIx64" is already allocated or "
>> +                 "no slot left", addr, size);
>> +    }
>> +
>> +    for (i = page; i < (page + size_pages); i++) {
>> +        set_bit(i, used_mem);
>> +    }
>> +
>> +    memory_region_add_subregion(pmem, addr, device_mem);
>> +    sbdev->mmio[n].addr = addr;
>> +    object_property_set_int(OBJECT(sbdev), addr, prop, NULL);
>> +
>> +    g_free(prop);
>> +    return 0;
>> +}
>> +
>> +static int sysbus_device_check(Object *obj, void *opaque)
>> +{
>> +    PlatformBusInitData *init = opaque;
>> +    Object *dev;
>> +    SysBusDevice *sbdev;
>> +    int i;
>> +
>> +    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
>> +    sbdev = (SysBusDevice *)dev;
>> +
>> +    if (!sbdev) {
>> +        /* Container, traverse it for children */
>> +        return object_child_foreach(obj, sysbus_device_check, opaque);
>> +    }
>> +
>> +    /* Connect sysbus device to virtual platform bus */
>> +    for (i = 0; i < sbdev->num_irq; i++) {
>> +        if (!sbdev->irqp[i]) {
>> +            /* This IRQ is an incoming IRQ, we can't wire those here */
>> +            continue;
>> +        }
>> +        platform_bus_map_irq(init->params, sbdev, i,
>> +                             init->used_irqs, init->irqs);
>> +    }
>> +
>> +    for (i = 0; i < sbdev->num_mmio; i++) {
>> +        platform_bus_map_mmio(init->params, sbdev, i,
>> +                              init->used_mem, init->mem);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void platform_bus_init(DynSysbusParams *params,
>> +                       MemoryRegion *address_space_mem,
>> +                       qemu_irq *mpic)
> 
> You probably don't want to call it "mpic" in generic code - you're using
> a GIC after all on ARM.
yes, will change that
> 
> Also I think it'd be better if you actually transform my patch set into
> the generic variant. That way I can push mine upstream and then your
> patch set makes that copy generic.
OK I will do that

thanks

Eric
> 
> 
> Alex
> 
>> +{
>> +    uint64_t max_size = params->platform_bus_size;
>> +    uint64_t max_pages = max_size >> params->page_shift;
>> +    DECLARE_BITMAP(used_irqs, params->platform_bus_num_irqs);
>> +    DECLARE_BITMAP(used_mem, max_pages);
>> +    MemoryRegion *platform_region = g_new(MemoryRegion, 1);
>> +    Object *container;
>> +    PlatformBusInitData init = {
>> +        .used_irqs = used_irqs,
>> +        .used_mem = used_mem,
>> +        .mem = platform_region,
>> +        .irqs = &mpic[params->platform_bus_first_irq],
>> +        .params = params,
>> +    };
>> +
>> +    memory_region_init(platform_region, NULL, "platform devices",
>> +                       params->platform_bus_size);
>> +
>> +    bitmap_clear(used_irqs, 0, params->platform_bus_num_irqs);
>> +    bitmap_clear(used_mem, 0, max_pages);
>> +
>> +    /* Loop through all sysbus devices that were spawened outside the
>> machine */
>> +    container = container_get(qdev_get_machine(), "/peripheral");
>> +    sysbus_device_check(container, &init);
>> +    container = container_get(qdev_get_machine(), "/peripheral-anon");
>> +    sysbus_device_check(container, &init);
>> +
>> +    memory_region_add_subregion(address_space_mem,
>> params->platform_bus_base,
>> +                                platform_region);
>> +}
>> +
>> +void platform_bus_init_notify(Notifier *notifier, void *data)
>> +{
>> +    DynSysbusNotifier *pn = (DynSysbusNotifier *)notifier;
>> +    platform_bus_init(&pn->params, pn->address_space_mem, pn->mpic);
>> +}
>> diff --git a/include/hw/misc/dyn_sysbus_binding.h
>> b/include/hw/misc/dyn_sysbus_binding.h
>> new file mode 100644
>> index 0000000..961c9c7
>> --- /dev/null
>> +++ b/include/hw/misc/dyn_sysbus_binding.h
>> @@ -0,0 +1,24 @@
>> +#ifndef HW_MISC_PLATFORM_DEVICES_H
>> +#define HW_MISC_PLATFORM_DEVICES_H
>> +
>> +#include "qemu-common.h"
>> +#include "hw/sysbus.h"
>> +
>> +typedef struct {
>> +    bool has_platform_bus;
>> +    hwaddr platform_bus_base;
>> +    hwaddr platform_bus_size;
>> +    int platform_bus_first_irq;
>> +    int platform_bus_num_irqs;
>> +    int page_shift;
>> +} DynSysbusParams;
>> +
>> +typedef struct DynSysbusNotifier {
>> +    Notifier notifier;
>> +    MemoryRegion *address_space_mem;
>> +    qemu_irq *mpic;
>> +    DynSysbusParams params;
>> +} DynSysbusNotifier;
>> +
>> +void platform_bus_init_notify(Notifier *notifier, void *data);
>> +#endif
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation
  2014-08-11 13:16   ` Alexander Graf
@ 2014-08-11 13:17     ` Eric Auger
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-11 13:17 UTC (permalink / raw)
  To: Alexander Graf, eric.auger, christoffer.dall, qemu-devel,
	kim.phillips, a.rigo
  Cc: peter.maydell, patches, will.deacon, stuart.yoder, Bharat.Bhushan,
	alex.williamson, a.motakis, kvmarm

On 08/11/2014 03:16 PM, Alexander Graf wrote:
> 
> On 08.08.14 17:03, Eric Auger wrote:
>> This module will be used by ARM machine files to generate
>> device tree nodes of dynamically instantiated sysbus devices (ie.
>> those instantiated with -device option).
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>
>> ---
>>
>> v2:
>> - Code moved in an arch specific file to accomodate architecture
>>    dependent specificities.
>> - remove platform_bus_base from PlatformDevtreeData
>>
>> v1: code originally written by Alex Graf in e500.c and reused for ARM
>>      [Eric Auger]
>>      code originally moved in hw/misc/platform_devices and device itself
>> ---
>>   hw/arm/Makefile.objs                |  1 +
>>   hw/arm/dyn_sysbus_devtree.c         | 66
>> +++++++++++++++++++++++++++++++++++++
>>   include/hw/arm/dyn_sysbus_devtree.h | 18 ++++++++++
>>   3 files changed, 85 insertions(+)
>>   create mode 100644 hw/arm/dyn_sysbus_devtree.c
>>   create mode 100644 include/hw/arm/dyn_sysbus_devtree.h
>>
>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>> index 6088e53..bc5e014 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -3,6 +3,7 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
>>   obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
>>   obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
>>   obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
>> +obj-y += dyn_sysbus_devtree.o
>>     obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
>>   obj-$(CONFIG_DIGIC) += digic.o
>> diff --git a/hw/arm/dyn_sysbus_devtree.c b/hw/arm/dyn_sysbus_devtree.c
>> new file mode 100644
>> index 0000000..56af62f
>> --- /dev/null
>> +++ b/hw/arm/dyn_sysbus_devtree.c
>> @@ -0,0 +1,66 @@
>> +#include "hw/arm/dyn_sysbus_devtree.h"
>> +#include "qemu/error-report.h"
>> +#include "sysemu/device_tree.h"
>> +
>> +int sysbus_device_create_devtree(Object *obj, void *opaque)
>> +{
>> +    PlatformDevtreeData *data = opaque;
>> +    Object *dev;
>> +    SysBusDevice *sbdev;
>> +    bool matched = false;
>> +
>> +    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
>> +    sbdev = (SysBusDevice *)dev;
>> +
>> +    if (!sbdev) {
>> +        /* Container, traverse it for children */
>> +        return object_child_foreach(obj,
>> sysbus_device_create_devtree, data);
>> +    }
>> +
>> +    if (!matched) {
>> +        error_report("Device %s is not supported by this machine yet.",
>> +                     qdev_fw_name(DEVICE(dev)));
>> +        exit(1);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +void platform_bus_create_devtree(DynSysbusParams *params,
>> +                                 void *fdt, const char *mpic)
>> +{
>> +    gchar *node = g_strdup_printf("/platform@%"PRIx64,
>> +                                  params->platform_bus_base);
>> +    const char platcomp[] = "qemu,platform\0simple-bus";
>> +    PlatformDevtreeData data;
>> +    Object *container;
>> +    uint64_t addr = params->platform_bus_base;
>> +    uint64_t size = params->platform_bus_size;
>> +    int irq_start = params->platform_bus_first_irq;
>> +
>> +    /* 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);
>> +
>> +    /* Loop through all devices and create nodes for known ones */
>> +    data.fdt = fdt;
>> +    data.mpic = mpic;
>> +    data.irq_start = irq_start;
>> +    data.node = node;
>> +
>> +    container = container_get(qdev_get_machine(), "/peripheral");
>> +    sysbus_device_create_devtree(container, &data);
>> +    container = container_get(qdev_get_machine(), "/peripheral-anon");
>> +    sysbus_device_create_devtree(container, &data);
>> +
>> +    g_free(node);
>> +}
>> diff --git a/include/hw/arm/dyn_sysbus_devtree.h
>> b/include/hw/arm/dyn_sysbus_devtree.h
>> new file mode 100644
>> index 0000000..808d522
>> --- /dev/null
>> +++ b/include/hw/arm/dyn_sysbus_devtree.h
>> @@ -0,0 +1,18 @@
>> +#ifndef HW_ARM_DYN_SYSBUS_DEVTREE_H
>> +#define HW_ARM_DYN_SYSBUS_DEVTREE_H
>> +
>> +#include "hw/misc/dyn_sysbus_binding.h"
>> +
>> +typedef struct PlatformDevtreeData {
>> +    void *fdt;
>> +    const char *mpic;
>> +    int irq_start;
>> +    const char *node;
>> +} PlatformDevtreeData;
>> +
>> +int sysbus_device_create_devtree(Object *obj, void *opaque);
>> +
>> +void platform_bus_create_devtree(DynSysbusParams *params,
>> +                                 void *fdt, const char *mpic);
> 
> These functions live in hw/arm and thus should have names that indicate
> they are arm specific.
OK thanks

Eric
> 
> 
> Alex
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static
  2014-08-11 13:10   ` Alexander Graf
@ 2014-08-11 13:18     ` Eric Auger
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Auger @ 2014-08-11 13:18 UTC (permalink / raw)
  To: Alexander Graf, eric.auger, christoffer.dall, qemu-devel,
	kim.phillips, a.rigo
  Cc: peter.maydell, patches, will.deacon, stuart.yoder, Bharat.Bhushan,
	alex.williamson, a.motakis, kvmarm

On 08/11/2014 03:10 PM, Alexander Graf wrote:
> 
> On 08.08.14 17:03, Eric Auger wrote:
>> load_dtb will be used by machvirt for dynamic instantiation of
>> platform devices
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> ---
>>   hw/arm/boot.c        | 2 +-
>>   include/hw/arm/arm.h | 1 +
>>   2 files changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/arm/boot.c b/hw/arm/boot.c
>> index 1241761..53b43e8 100644
>> --- a/hw/arm/boot.c
>> +++ b/hw/arm/boot.c
>> @@ -312,7 +312,7 @@ static void set_kernel_args_old(const struct
>> arm_boot_info *info)
>>       }
>>   }
>>   -static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
>> +int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
> 
> Please rename it arm_load_dtb then.
OK
thanks

Eric
> 
> 
> Alex
> 
>>   {
>>       void *fdt = NULL;
>>       int size, rc;
>> diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
>> index cbbf4ca..fe58dc0 100644
>> --- a/include/hw/arm/arm.h
>> +++ b/include/hw/arm/arm.h
>> @@ -68,6 +68,7 @@ struct arm_boot_info {
>>       hwaddr entry;
>>   };
>>   void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
>> +int load_dtb(hwaddr addr, const struct arm_boot_info *binfo);
>>     /* Multiplication factor to convert from system clock ticks to
>> qemu timer
>>      ticks.  */
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2014-08-11 13:19 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-08 15:03 [Qemu-devel] [RFC v2 0/7] machvirt dynamic sysbus device instantiation Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 1/7] hw/misc/dyn_sysbus_binding: helpers for sysbus device dynamic binding Eric Auger
2014-08-11 13:08   ` Alexander Graf
2014-08-11 13:16     ` Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 2/7] hw/arm/dyn_sysbus_devtree: helpers for sysbus device dynamic dt node generation Eric Auger
2014-08-11 13:16   ` Alexander Graf
2014-08-11 13:17     ` Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 3/7] PPC: e500: Support dynamically spawned sysbus devices Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 4/7] e500: Add support for eTSEC in device tree Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 5/7] hw/arm/boot: load_dtb becomes non static Eric Auger
2014-08-11 13:10   ` Alexander Graf
2014-08-11 13:18     ` Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 6/7] hw/arm/virt: add new add_fdt_xxx_node functions Eric Auger
2014-08-08 15:03 ` [Qemu-devel] [RFC v2 7/7] hw/arm/virt: Support dynamically spawned sysbus devices Eric Auger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).