Re: [Qemu-devel] [PATCH 1/7] hw/misc/platform_devices: helpers for dynamic instantiation of platform devices
On 07/08/2014 03:43 PM, Alexander Graf wrote: On 07.07.14 09:08, Eric Auger wrote: This new module implements routines which help in dynamic instantiation of sysbus devices. Machine files can use those generic routines. --- Dynamic sysbus device allocation fully written by Alex Graf. [Eric Auger] 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 ag...@suse.de Signed-off-by: Eric Auger eric.au...@linaro.org --- hw/misc/Makefile.objs | 1 + hw/misc/platform_devices.c | 217 + include/hw/misc/platform_devices.h | 61 +++ 3 files changed, 279 insertions(+) create mode 100644 hw/misc/platform_devices.c create mode 100644 include/hw/misc/platform_devices.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e47fea8..d081606 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-y += platform_devices.o diff --git a/hw/misc/platform_devices.c b/hw/misc/platform_devices.c new file mode 100644 index 000..96ab272 --- /dev/null +++ b/hw/misc/platform_devices.c @@ -0,0 +1,217 @@ +#include hw/misc/platform_devices.h +#include hw/sysbus.h +#include qemu/error-report.h + +#define PAGE_SHIFT 12 + +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(PlatformParams *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); +} Device trees are pretty platform (and even machine) specific. Just to give you an example - the interrupt specifier on most e500 systems really is 4 cells big: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt#n80 | Interrupt specifiers consists of 4 cells encoded as follows: 1st-cell interrupt-number Identifies the interrupt source. The meaning depends on the type of interrupt. Note: If the interrupt-type cell is undefined (i.e. #interrupt-cells = 2), this cell should be interpreted the same as for interrupt-type 0-- i.e. an external or normal SoC device interrupt. 2nd-cell level-sense information, encoded as follows: 0 = low-to-high edge triggered 1 = active low level-sensitive 2 = active high level-sensitive 3 = high-to-low edge triggered 3rd-cell interrupt-type The following types are supported: 0 = external or normal SoC device interrupt The interrupt-number cell contains the
Re: [Qemu-devel] [PATCH 1/7] hw/misc/platform_devices: helpers for dynamic instantiation of platform devices
On 23.07.14 16:58, Eric Auger wrote: On 07/08/2014 03:43 PM, Alexander Graf wrote: On 07.07.14 09:08, Eric Auger wrote: This new module implements routines which help in dynamic instantiation of sysbus devices. Machine files can use those generic routines. --- Dynamic sysbus device allocation fully written by Alex Graf. [Eric Auger] 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 ag...@suse.de Signed-off-by: Eric Auger eric.au...@linaro.org --- hw/misc/Makefile.objs | 1 + hw/misc/platform_devices.c | 217 + include/hw/misc/platform_devices.h | 61 +++ 3 files changed, 279 insertions(+) create mode 100644 hw/misc/platform_devices.c create mode 100644 include/hw/misc/platform_devices.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e47fea8..d081606 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-y += platform_devices.o diff --git a/hw/misc/platform_devices.c b/hw/misc/platform_devices.c new file mode 100644 index 000..96ab272 --- /dev/null +++ b/hw/misc/platform_devices.c @@ -0,0 +1,217 @@ +#include hw/misc/platform_devices.h +#include hw/sysbus.h +#include qemu/error-report.h + +#define PAGE_SHIFT 12 + +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(PlatformParams *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); +} Device trees are pretty platform (and even machine) specific. Just to give you an example - the interrupt specifier on most e500 systems really is 4 cells big: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt#n80 | Interrupt specifiers consists of 4 cells encoded as follows: 1st-cell interrupt-number Identifies the interrupt source. The meaning depends on the type of interrupt. Note: If the interrupt-type cell is undefined (i.e. #interrupt-cells = 2), this cell should be interpreted the same as for interrupt-type 0-- i.e. an external or normal SoC device interrupt. 2nd-cell level-sense information, encoded as follows: 0 = low-to-high edge triggered 1 = active low level-sensitive 2 = active high level-sensitive 3 = high-to-low edge triggered 3rd-cell interrupt-type The following types are supported: 0 = external or normal SoC device interrupt The interrupt-number cell contains the SoC device interrupt number. The type-specific
Re: [Qemu-devel] [PATCH 1/7] hw/misc/platform_devices: helpers for dynamic instantiation of platform devices
On 07.07.14 09:08, Eric Auger wrote: This new module implements routines which help in dynamic instantiation of sysbus devices. Machine files can use those generic routines. --- Dynamic sysbus device allocation fully written by Alex Graf. [Eric Auger] 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 ag...@suse.de Signed-off-by: Eric Auger eric.au...@linaro.org --- hw/misc/Makefile.objs | 1 + hw/misc/platform_devices.c | 217 + include/hw/misc/platform_devices.h | 61 +++ 3 files changed, 279 insertions(+) create mode 100644 hw/misc/platform_devices.c create mode 100644 include/hw/misc/platform_devices.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e47fea8..d081606 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-y += platform_devices.o diff --git a/hw/misc/platform_devices.c b/hw/misc/platform_devices.c new file mode 100644 index 000..96ab272 --- /dev/null +++ b/hw/misc/platform_devices.c @@ -0,0 +1,217 @@ +#include hw/misc/platform_devices.h +#include hw/sysbus.h +#include qemu/error-report.h + +#define PAGE_SHIFT 12 + +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(PlatformParams *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); +} Device trees are pretty platform (and even machine) specific. Just to give you an example - the interrupt specifier on most e500 systems really is 4 cells big: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt#n80 | Interrupt specifiers consists of 4 cells encoded as follows: 1st-cell interrupt-number Identifies the interrupt source. The meaning depends on the type of interrupt. Note: If the interrupt-type cell is undefined (i.e. #interrupt-cells = 2), this cell should be interpreted the same as for interrupt-type 0-- i.e. an external or normal SoC device interrupt. 2nd-cell level-sense information, encoded as follows: 0 = low-to-high edge triggered 1 = active low level-sensitive 2 = active high level-sensitive 3 = high-to-low edge triggered 3rd-cell interrupt-type The following types are supported: 0 = external or normal SoC device interrupt The interrupt-number cell contains the SoC device interrupt number. The type-specific cell is undefined. The interrupt-number is derived from the MPIC a
[Qemu-devel] [PATCH 1/7] hw/misc/platform_devices: helpers for dynamic instantiation of platform devices
This new module implements routines which help in dynamic instantiation of sysbus devices. Machine files can use those generic routines. --- Dynamic sysbus device allocation fully written by Alex Graf. [Eric Auger] 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 ag...@suse.de Signed-off-by: Eric Auger eric.au...@linaro.org --- hw/misc/Makefile.objs | 1 + hw/misc/platform_devices.c | 217 + include/hw/misc/platform_devices.h | 61 +++ 3 files changed, 279 insertions(+) create mode 100644 hw/misc/platform_devices.c create mode 100644 include/hw/misc/platform_devices.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index e47fea8..d081606 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-y += platform_devices.o diff --git a/hw/misc/platform_devices.c b/hw/misc/platform_devices.c new file mode 100644 index 000..96ab272 --- /dev/null +++ b/hw/misc/platform_devices.c @@ -0,0 +1,217 @@ +#include hw/misc/platform_devices.h +#include hw/sysbus.h +#include qemu/error-report.h + +#define PAGE_SHIFT 12 + +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(PlatformParams *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); +} + +int platform_bus_map_irq(PlatformParams *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; +} + +int platform_bus_map_mmio(PlatformParams *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 PAGE_SHIFT); +uint64_t page_mask = page_size - 1; +uint64_t size_pages = (size + page_mask) PAGE_SHIFT; +uint64_t max_size = params-platform_bus_size; +uint64_t max_pages = max_size 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