* [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
* 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 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
* [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
* 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 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
* [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(¬ifier->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
* 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 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
* [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(¬ifier->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