All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support
@ 2014-09-24 15:22 Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 1/7] sysbus: Add dynamic sysbus device search Alexander Graf
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

Platforms without ISA and/or PCI have had a seriously hard time in the dynamic
device creation world of QEMU. Devices on these were modeled as SysBus devices
which can only be instantiated in machine files, not through -device.

Why is that so?

For Sysbus devices we didn't know who should be responsible for mapping them
when the machine file didn't do it. Turns out, the machine file is the perfect
place to map them even when it doesn't create them :).

This patch set enables machine files to declare sysbus device creation via the
-device command line option as possible. With this we can (in the machine file)
map sysbus devices to whatever the machine thinks is fitting.

Some times users do want to specify manually where to map a device. This is
very useful when you want to have stable offsets in memory and irq space.
This patch set adds support for "user mapping hints" that the machine can use
to map a device at a certain location.

As example this patch set only enables the eTSEC device on the e500plat machine
type. This device was not possible to get added to the machine at all.

  $ qemu-system-ppc -nographic -M ppce500 -device eTSEC,netdev=nd \
                    -netdev user,id=nd

The idea can easily be extended to any sysbus device on any machine type though.
Everything that a machine has to do is spawn a "platform-bus-device" and generate
the correct device tree for the guest to see the new devices.


This patch set is based on previous ideas and discussions, most notably:

  https://lists.gnu.org/archive/html/qemu-devel/2013-07/msg03614.html
  https://lists.gnu.org/archive/html/qemu-devel/2014-06/msg00849.html
  https://lists.gnu.org/archive/html/qemu-ppc/2014-07/msg00047.html

In this incarnation, it also depends on Peter Crosthwaite's IRQ QOMification:

  https://lists.nongnu.org/archive/html/qemu-devel/2014-08/msg02387.html

So if you just want something to run, try this git branch:

  https://github.com/agraf/qemu.git sysbus-hints-v3


v1 -> v2:

  - new patch: qom: Move property helpers to own file
  - reworked patch: qom: Expose property helpers for get/set of integers
  - new patch: qom: Add generic object property g_free helper
  - new patch: PPC: Fix default config ordering and add eTSEC for ppc64
  - Rename DECLARE_INTEGER_VISITOR to DECLARE_PROP_SET_GET
  - Make macro take name and type arguments, enabling generation of "bool"
    types later
  - make irq and pio properties uint64
  - ensure qom exposed pointers don't change due to realloc
  - fix sysbus_pass_irq
  - make properties write-once, not write-before-realize
  - make props only available via qom, no state pointers left
  - use bool in MachineClass rather than property
  - access sysbus properties via qom
  - move platform bus definitions to params
  - move platform bus to 36bit address space
  - make naming more consistent
  - remove device_type from platform bus dt node
  - remove id field in dt generation
  - fix device name (base on reg for value after @)
  - use qom properties to fetch mmio and irq props
  - remove useless interrupt-parent
  - make interrupts level triggered

v2 -> v3:

  - switch from qom property hints to implicit map evaluation
  - new patch: sysbus: Add dynamic sysbus device search
  - new patch: sysbus: Expose IRQ enumeration helpers
  - new patch: sysbus: Expose MMIO enumeration helper
  - new patch: sysbus: Add new platform bus helper device
  - dropped QOM rework patches
  - base on QOMified IRQs
  - rework dynamic sysbus device search
  - add notifier for device tree regeneration 

Alexander Graf (7):
  sysbus: Add dynamic sysbus device search
  sysbus: Make devices spawnable via -device
  sysbus: Expose IRQ enumeration helpers
  sysbus: Expose MMIO enumeration helper
  sysbus: Add new platform bus helper device
  PPC: e500: Support dynamically spawned sysbus devices
  e500: Add support for eTSEC in device tree

 hw/core/Makefile.objs     |   1 +
 hw/core/machine.c         |  34 +++++++
 hw/core/platform-bus.c    | 253 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/core/qdev.c            |  11 ++
 hw/core/sysbus.c          |  79 +++++++++++++--
 hw/ppc/e500.c             | 143 ++++++++++++++++++++++++++
 hw/ppc/e500.h             |   5 +
 hw/ppc/e500plat.c         |   6 ++
 include/hw/boards.h       |   8 +-
 include/hw/platform-bus.h |  57 +++++++++++
 include/hw/qdev-core.h    |   1 +
 include/hw/sysbus.h       |   9 ++
 vl.c                      |   1 +
 13 files changed, 599 insertions(+), 9 deletions(-)
 create mode 100644 hw/core/platform-bus.c
 create mode 100644 include/hw/platform-bus.h

-- 
1.8.1.4

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

* [Qemu-devel] [PATCH v3 1/7] sysbus: Add dynamic sysbus device search
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 2/7] sysbus: Make devices spawnable via -device Alexander Graf
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

Sysbus devices can be spawned by C code or dynamically via the command line.
In the latter case, we need to be able to find the dynamically created devices
to do things with them.

This patch adds a search helper that makes it easy to look for dynamically
spawned sysbus devices.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/core/sysbus.c    | 45 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/sysbus.h |  5 +++++
 2 files changed, 50 insertions(+)

diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index e55c3c1..19437e6 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -24,6 +24,51 @@
 static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *sysbus_get_fw_dev_path(DeviceState *dev);
 
+typedef struct SysBusFind {
+    void *opaque;
+    FindSysbusDeviceFunc *func;
+} SysBusFind;
+
+/* Run func() for every sysbus device, traverse the tree for everything else */
+static int find_sysbus_device(Object *obj, void *opaque)
+{
+    SysBusFind *find = opaque;
+    Object *dev;
+    SysBusDevice *sbdev;
+
+    dev = object_dynamic_cast(obj, TYPE_SYS_BUS_DEVICE);
+    sbdev = (SysBusDevice *)dev;
+
+    if (!sbdev) {
+        /* Container, traverse it for children */
+        return object_child_foreach(obj, find_sysbus_device, opaque);
+    }
+
+    find->func(sbdev, find->opaque);
+
+    return 0;
+}
+
+/*
+ * Loop through all dynamically created sysbus devices and call
+ * func() for each instance.
+ */
+void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
+{
+    Object *container;
+    SysBusFind find = {
+        .func = func,
+        .opaque = opaque,
+    };
+
+    /* Loop through all sysbus devices that were spawened outside the machine */
+    container = container_get(qdev_get_machine(), "/peripheral");
+    find_sysbus_device(container, &find);
+    container = container_get(qdev_get_machine(), "/peripheral-anon");
+    find_sysbus_device(container, &find);
+}
+
+
 static void system_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 470e2e5..6c618e6 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -58,6 +58,8 @@ struct SysBusDevice {
     pio_addr_t pio[QDEV_MAX_PIO];
 };
 
+typedef int FindSysbusDeviceFunc(SysBusDevice *sbdev, void *opaque);
+
 void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
 MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
 void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
@@ -73,6 +75,9 @@ void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
                    MemoryRegion *mem);
 MemoryRegion *sysbus_address_space(SysBusDevice *dev);
 
+/* Call func for every dynamically created sysbus device in the system */
+void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque);
+
 /* Legacy helper function for creating devices.  */
 DeviceState *sysbus_create_varargs(const char *name,
                                  hwaddr addr, ...);
-- 
1.8.1.4

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

* [Qemu-devel] [PATCH v3 2/7] sysbus: Make devices spawnable via -device
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 1/7] sysbus: Add dynamic sysbus device search Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-24 15:37   ` Paolo Bonzini
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 3/7] sysbus: Expose IRQ enumeration helpers Alexander Graf
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

Now that we can properly map sysbus devices that haven't been connected to
something forcefully by C code, we can allow the -device command line option
to spawn them.

For machines that don't implement dynamic sysbus assignment in their board
files we add a new bool "has_dynamic_sysbus" to the machine class.
When that property is false (default), we bail out when we see dynamically
spawned sysbus devices, like we did before.

Signed-off-by: Alexander Graf <agraf@suse.de>

---

v1 -> v2:

  - use bool in MachineClass rather than property

v2 -> v3:

  - use search helper
---
 hw/core/machine.c   | 34 ++++++++++++++++++++++++++++++++++
 hw/core/sysbus.c    |  7 -------
 include/hw/boards.h |  8 ++++++--
 vl.c                |  1 +
 4 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index 7f3418c..653d030 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -12,6 +12,9 @@
 
 #include "hw/boards.h"
 #include "qapi/visitor.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
 
 static char *machine_get_accel(Object *obj, Error **errp)
 {
@@ -257,8 +260,35 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp)
     ms->iommu = value;
 }
 
+static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
+{
+    error_report("Device '%s' can not be handled by this machine",
+                 qdev_fw_name(DEVICE(sbdev)));
+    exit(1);
+}
+
+static void machine_init_notify(Notifier *notifier, void *data)
+{
+    Object *machine = qdev_get_machine();
+    ObjectClass *oc = object_get_class(machine);
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    if (mc->has_dynamic_sysbus) {
+        /* Our machine can handle dynamic sysbus devices, we're all good */
+        return;
+    }
+
+    /*
+     * Loop through all dynamically created devices and check whether there
+     * are sysbus devices among them. If there are, error out.
+     */
+    foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
+}
+
 static void machine_initfn(Object *obj)
 {
+    MachineState *ms = MACHINE(obj);
+
     object_property_add_str(obj, "accel",
                             machine_get_accel, machine_set_accel, NULL);
     object_property_add_bool(obj, "kernel-irqchip",
@@ -303,6 +333,10 @@ static void machine_initfn(Object *obj)
     object_property_add_bool(obj, "iommu",
                              machine_get_iommu,
                              machine_set_iommu, NULL);
+
+    /* Register notifier when init is done for sysbus sanity checks */
+    ms->sysbus_notifier.notify = machine_init_notify;
+    qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
 }
 
 static void machine_finalize(Object *obj)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 19437e6..7bfe381 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -283,13 +283,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = sysbus_device_init;
     k->bus_type = TYPE_SYSTEM_BUS;
-    /*
-     * device_add plugs devices into suitable bus.  For "real" buses,
-     * that actually connects the device.  For sysbus, the connections
-     * need to be made separately, and device_add can't do that.  The
-     * device would be left unconnected, and could not possibly work.
-     */
-    k->cannot_instantiate_with_device_add_yet = true;
 }
 
 static const TypeInfo sysbus_device_type_info = {
diff --git a/include/hw/boards.h b/include/hw/boards.h
index dfb6718..12e77ea 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -35,7 +35,8 @@ struct QEMUMachine {
         use_sclp:1,
         no_floppy:1,
         no_cdrom:1,
-        no_sdcard:1;
+        no_sdcard:1,
+        has_dynamic_sysbus:1;
     int is_default;
     const char *default_machine_opts;
     const char *default_boot_order;
@@ -93,7 +94,8 @@ struct MachineClass {
         use_sclp:1,
         no_floppy:1,
         no_cdrom:1,
-        no_sdcard:1;
+        no_sdcard:1,
+        has_dynamic_sysbus:1;
     int is_default;
     const char *default_machine_opts;
     const char *default_boot_order;
@@ -110,6 +112,8 @@ struct MachineClass {
 struct MachineState {
     /*< private >*/
     Object parent_obj;
+    Notifier sysbus_notifier;
+
     /*< public >*/
 
     char *accel;
diff --git a/vl.c b/vl.c
index dbdca59..0540db4 100644
--- a/vl.c
+++ b/vl.c
@@ -1591,6 +1591,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
     mc->no_floppy = qm->no_floppy;
     mc->no_cdrom = qm->no_cdrom;
     mc->no_sdcard = qm->no_sdcard;
+    mc->has_dynamic_sysbus = qm->has_dynamic_sysbus;
     mc->is_default = qm->is_default;
     mc->default_machine_opts = qm->default_machine_opts;
     mc->default_boot_order = qm->default_boot_order;
-- 
1.8.1.4

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

* [Qemu-devel] [PATCH v3 3/7] sysbus: Expose IRQ enumeration helpers
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 1/7] sysbus: Add dynamic sysbus device search Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 2/7] sysbus: Make devices spawnable via -device Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 4/7] sysbus: Expose MMIO enumeration helper Alexander Graf
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

Sysbus devices can get their IRQ lines connected to other devices. It is
possible to figure out which IRQ line a connection is on and whether a sysbus
device even provides an IRQ connector at a specific offset.

This patch exposes helpers to make this information publicly accessible. We
will need it for the platform bus dynamic sysbus enumeration.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/core/qdev.c         | 11 +++++++++++
 hw/core/sysbus.c       | 21 +++++++++++++++++++++
 include/hw/qdev-core.h |  1 +
 include/hw/sysbus.h    |  3 +++
 4 files changed, 36 insertions(+)

diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 1cdd052..c9b7a68 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -411,6 +411,17 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
     g_free(propname);
 }
 
+qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n)
+{
+    char *propname = g_strdup_printf("%s[%d]",
+                                     name ? name : "unnamed-gpio-out", n);
+
+    qemu_irq ret = (qemu_irq)object_property_get_link(OBJECT(dev), propname,
+                                                      NULL);
+
+    return ret;
+}
+
 /* disconnect a GPIO ouput, returning the disconnected input (if any) */
 
 static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev,
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 7bfe381..945dec5 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -84,6 +84,27 @@ static const TypeInfo system_bus_info = {
     .class_init = system_bus_class_init,
 };
 
+/* Check whether an IRQ source exists */
+bool sysbus_has_irq(SysBusDevice *dev, int n)
+{
+    char *prop = g_strdup_printf("%s[%d]", SYSBUS_DEVICE_GPIO_IRQ, n);
+    ObjectProperty *r;
+
+    r = object_property_find(OBJECT(dev), prop, NULL);
+    return (r != NULL);
+}
+
+bool sysbus_is_irq_connected(SysBusDevice *dev, int n)
+{
+    return !!sysbus_get_connected_irq(dev, n);
+}
+
+qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n)
+{
+    DeviceState *d = DEVICE(dev);
+    return qdev_get_gpio_out_connector(d, SYSBUS_DEVICE_GPIO_IRQ, n);
+}
+
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
 {
     qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 77b193b..b0eaee8 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -273,6 +273,7 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
 void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
 void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
                                  qemu_irq pin);
+qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
 qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
                                  const char *name, int n);
 
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 6c618e6..6b3d336 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -67,7 +67,10 @@ void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
 void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
 
 
+bool sysbus_has_irq(SysBusDevice *dev, int n);
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
+bool sysbus_is_irq_connected(SysBusDevice *dev, int n);
+qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n);
 void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
 void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
                              int priority);
-- 
1.8.1.4

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

* [Qemu-devel] [PATCH v3 4/7] sysbus: Expose MMIO enumeration helper
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
                   ` (2 preceding siblings ...)
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 3/7] sysbus: Expose IRQ enumeration helpers Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device Alexander Graf
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

Sysbus devices have a range of MMIO regions they expose. The exact number
of regions is device specific and internal information to the device model.

Expose whether a region exists via a public interface. That way our platform
bus enumeration code can dynamically determine how many regions exist.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/core/sysbus.c    | 6 ++++++
 include/hw/sysbus.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 945dec5..84af593 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -110,6 +110,12 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
     qdev_connect_gpio_out_named(DEVICE(dev), SYSBUS_DEVICE_GPIO_IRQ, n, irq);
 }
 
+/* Check whether an MMIO region exists */
+bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n)
+{
+    return (n < dev->num_mmio);
+}
+
 static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
                                    bool may_overlap, int priority)
 {
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 6b3d336..d76dfee 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -68,6 +68,7 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
 
 
 bool sysbus_has_irq(SysBusDevice *dev, int n);
+bool sysbus_has_mmio(SysBusDevice *dev, unsigned int n);
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
 bool sysbus_is_irq_connected(SysBusDevice *dev, int n);
 qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n);
-- 
1.8.1.4

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

* [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
                   ` (3 preceding siblings ...)
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 4/7] sysbus: Expose MMIO enumeration helper Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-26 12:05   ` Paolo Bonzini
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 6/7] PPC: e500: Support dynamically spawned sysbus devices Alexander Graf
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

We need to support spawning of sysbus devices dynamically via the command line.
The easiest way to represent these dynamically spawned devices in the guest's
memory and IRQ layout is by preallocating some space for dynamic sysbus devices.

This is what the "platform bus" device does. It is a sysbus device that exports
a configurably sized MMIO region and a configurable number of IRQ lines. When
this device encounters sysbus devices that have been dynamically created and not
manually wired up, it dynamically connects them to its own pool of resources.

The machine model can then loop through all of these devices and create a guest
configuration (device tree) to make them visible to the guest.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/core/Makefile.objs     |   1 +
 hw/core/platform-bus.c    | 253 ++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/platform-bus.h |  57 +++++++++++
 3 files changed, 311 insertions(+)
 create mode 100644 hw/core/platform-bus.c
 create mode 100644 include/hw/platform-bus.h

diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 17845df..9dce1bc 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -14,3 +14,4 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o
 common-obj-$(CONFIG_SOFTMMU) += null-machine.o
 common-obj-$(CONFIG_SOFTMMU) += loader.o
 common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
+common-obj-$(CONFIG_SOFTMMU) += platform-bus.o
diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c
new file mode 100644
index 0000000..0f052b3
--- /dev/null
+++ b/hw/core/platform-bus.c
@@ -0,0 +1,253 @@
+/*
+ *  Platform Bus device to support dynamic Sysbus devices
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/platform-bus.h"
+#include "monitor/monitor.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+
+
+/*
+ * Returns the PlatformBus IRQ number for a SysBusDevice irq number or -1 if
+ * the IRQ is not mapped on this Platform bus.
+ */
+int platform_bus_get_irqn(PlatformBusDevice *pbus, SysBusDevice *sbdev,
+                          int n)
+{
+    qemu_irq sbirq = sysbus_get_connected_irq(sbdev, n);
+    int i;
+
+    for (i = 0; i < pbus->num_irqs; i++) {
+        if (pbus->irqs[i] == sbirq) {
+            return i;
+        }
+    }
+
+    /* IRQ not mapped on platform bus */
+    return -1;
+}
+
+/*
+ * Returns the PlatformBus MMIO region offset for Region n of a SysBusDevice or
+ * -1 if the region is not mapped on this Platform bus.
+ */
+hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
+                                  int n)
+{
+    MemoryRegion *pbus_mr = &pbus->mmio;
+    MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
+    Object *pbus_mr_obj = OBJECT(pbus_mr);
+    Object *parent_mr;
+
+    if (!memory_region_is_mapped(sbdev_mr)) {
+        /* Region is not mapped? */
+        return -1;
+    }
+
+    parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
+
+    assert(parent_mr);
+    if (parent_mr != pbus_mr_obj) {
+        /* MMIO region is not mapped on platform bus */
+        return -1;
+    }
+
+    return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
+}
+
+static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque)
+{
+    PlatformBusDevice *pbus = opaque;
+    qemu_irq sbirq;
+    int n, i;
+
+    for (n = 0; ; n++) {
+        if (!sysbus_has_irq(sbdev, n)) {
+            break;
+        }
+
+        sbirq = sysbus_get_connected_irq(sbdev, n);
+        for (i = 0; i < pbus->num_irqs; i++) {
+            if (pbus->irqs[i] == sbirq) {
+                bitmap_set(pbus->used_irqs, i, 1);
+                break;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Loop through all sysbus devices and look for unassigned IRQ lines as well as
+ * unassociated MMIO regions. Connect them to the platform bus if available.
+ */
+static void plaform_bus_refresh_irqs(PlatformBusDevice *pbus)
+{
+    bitmap_zero(pbus->used_irqs, pbus->num_irqs);
+    foreach_dynamic_sysbus_device(platform_bus_count_irqs, pbus);
+    pbus->done_gathering = true;
+}
+
+static int platform_bus_map_irq(PlatformBusDevice *pbus, SysBusDevice *sbdev,
+                                int n)
+{
+    int max_irqs = pbus->num_irqs;
+    int irqn;
+
+    if (sysbus_is_irq_connected(sbdev, n)) {
+        /* IRQ is already mapped, nothing to do */
+        return 0;
+    }
+
+    irqn = find_first_zero_bit(pbus->used_irqs, max_irqs);
+    if (irqn >= max_irqs) {
+        hw_error("Platform Bus: Can not fit IRQ line");
+        return -1;
+    }
+
+    set_bit(irqn, pbus->used_irqs);
+    sysbus_connect_irq(sbdev, n, pbus->irqs[irqn]);
+
+    return 0;
+}
+
+static int platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
+                                 int n)
+{
+    MemoryRegion *sbdev_mr = sysbus_mmio_get_region(sbdev, n);
+    uint64_t size = memory_region_size(sbdev_mr);
+    uint64_t alignment = (1ULL << (63 - clz64(size + size - 1)));
+    uint64_t off;
+    bool found_region = false;
+
+    if (memory_region_is_mapped(sbdev_mr)) {
+        /* Region is already mapped, nothing to do */
+        return 0;
+    }
+
+    /*
+     * Look for empty space in the MMIO space that is naturally aligned with
+     * the target device's memory region
+     */
+    for (off = 0; off < pbus->mmio_size; off += alignment) {
+        if (!memory_region_find(&pbus->mmio, off, size).mr) {
+            found_region = true;
+            break;
+        }
+    }
+
+    if (!found_region) {
+        hw_error("Platform Bus: Can not fit MMIO region of size %"PRIx64, size);
+    }
+
+    /* Map the device's region into our Platform Bus MMIO space */
+    memory_region_add_subregion(&pbus->mmio, off, sbdev_mr);
+
+    return 0;
+}
+
+/*
+ * For each sysbus device, look for unassigned IRQ lines as well as
+ * unassociated MMIO regions. Connect them to the platform bus if available.
+ */
+static int link_sysbus_device(SysBusDevice *sbdev, void *opaque)
+{
+    PlatformBusDevice *pbus = opaque;
+    int i;
+
+    for (i = 0; sysbus_has_irq(sbdev, i); i++) {
+        platform_bus_map_irq(pbus, sbdev, i);
+    }
+
+    for (i = 0; sysbus_has_mmio(sbdev, i); i++) {
+        platform_bus_map_mmio(pbus, sbdev, i);
+    }
+
+    return 0;
+}
+
+static void platform_bus_init_notify(Notifier *notifier, void *data)
+{
+    PlatformBusDevice *pb = container_of(notifier, PlatformBusDevice, notifier);
+
+    /*
+     * Generate a bitmap of used IRQ lines, as the user might have specified
+     * them on the command line.
+     */
+    plaform_bus_refresh_irqs(pb);
+
+    foreach_dynamic_sysbus_device(link_sysbus_device, pb);
+}
+
+static void platform_bus_realize(DeviceState *dev, Error **errp)
+{
+    PlatformBusDevice *pbus;
+    SysBusDevice *d;
+    int i;
+
+    d = SYS_BUS_DEVICE(dev);
+    pbus = PLATFORM_BUS_DEVICE(dev);
+
+    memory_region_init(&pbus->mmio, NULL, "platform bus", pbus->mmio_size);
+    sysbus_init_mmio(d, &pbus->mmio);
+
+    pbus->used_irqs = bitmap_new(pbus->num_irqs);
+    pbus->irqs = g_new0(qemu_irq, pbus->num_irqs);
+    for (i = 0; i < pbus->num_irqs; i++) {
+        sysbus_init_irq(d, &pbus->irqs[i]);
+    }
+
+    /*
+     * Register notifier that allows us to gather dangling devices once the
+     * machine is completely assembled
+     */
+    pbus->notifier.notify = platform_bus_init_notify;
+    qemu_add_machine_init_done_notifier(&pbus->notifier);
+}
+
+static Property platform_bus_properties[] = {
+    DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
+    DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void platform_bus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = platform_bus_realize;
+    dc->props = platform_bus_properties;
+}
+
+static const TypeInfo platform_bus_info = {
+    .name          = TYPE_PLATFORM_BUS_DEVICE,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PlatformBusDevice),
+    .class_init    = platform_bus_class_init,
+};
+
+static void platform_bus_register_types(void)
+{
+    type_register_static(&platform_bus_info);
+}
+
+type_init(platform_bus_register_types)
diff --git a/include/hw/platform-bus.h b/include/hw/platform-bus.h
new file mode 100644
index 0000000..bd42b83
--- /dev/null
+++ b/include/hw/platform-bus.h
@@ -0,0 +1,57 @@
+#ifndef HW_PLATFORM_BUS_H
+#define HW_PLATFORM_BUS_H 1
+
+/*
+ *  Platform Bus device to support dynamic Sysbus devices
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+
+typedef struct PlatformBusDevice PlatformBusDevice;
+
+#define TYPE_PLATFORM_BUS_DEVICE "platform-bus-device"
+#define PLATFORM_BUS_DEVICE(obj) \
+     OBJECT_CHECK(PlatformBusDevice, (obj), TYPE_PLATFORM_BUS_DEVICE)
+#define PLATFORM_BUS_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PlatformBusDeviceClass, (klass), TYPE_PLATFORM_BUS_DEVICE)
+#define PLATFORM_BUS_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PlatformBusDeviceClass, (obj), TYPE_PLATFORM_BUS_DEVICE)
+
+struct PlatformBusDevice {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    Notifier notifier;
+    bool done_gathering;
+
+    /*< public >*/
+    uint32_t mmio_size;
+    MemoryRegion mmio;
+
+    uint32_t num_irqs;
+    qemu_irq *irqs;
+    unsigned long *used_irqs;
+};
+
+int platform_bus_get_irqn(PlatformBusDevice *platform_bus, SysBusDevice *sbdev,
+                          int n);
+hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev,
+                                  int n);
+
+#endif /* !HW_PLATFORM_BUS_H */
-- 
1.8.1.4

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

* [Qemu-devel] [PATCH v3 6/7] PPC: e500: Support dynamically spawned sysbus devices
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
                   ` (4 preceding siblings ...)
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 7/7] e500: Add support for eTSEC in device tree Alexander Graf
  2014-09-24 15:40 ` [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Paolo Bonzini
  7 siblings, 0 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

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>

---

v1 -> v2:

  - access sysbus properties via qom
  - move platform bus definitions to params
  - move platform bus to 36bit address space
  - make naming more consistent
  - remove device_type from platform bus dt node
  - remove id field in dt generation

v2 -> v3:

  - use platform bus device, remove our own allocation
  - use sysbus search helper
  - add notifier for device tree regeneration
---
 hw/ppc/e500.c     | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ppc/e500.h     |   5 +++
 hw/ppc/e500plat.c |   6 ++++
 3 files changed, 111 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 16c85ef..f16bab7 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -36,6 +36,8 @@
 #include "exec/address-spaces.h"
 #include "qemu/host-utils.h"
 #include "hw/pci-host/ppce500.h"
+#include "qemu/error-report.h"
+#include "hw/platform-bus.h"
 
 #define EPAPR_MAGIC                (0x45504150)
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
@@ -122,6 +124,72 @@ 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;
+    PlatformBusDevice *pbus;
+} PlatformDevtreeData;
+
+static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
+{
+    PlatformDevtreeData *data = opaque;
+    bool matched = false;
+
+    if (!matched) {
+        error_report("Device %s is not supported by this machine yet.",
+                     qdev_fw_name(DEVICE(sbdev)));
+        exit(1);
+    }
+
+    return 0;
+}
+
+static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
+                                        const char *mpic)
+{
+    gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
+    const char platcomp[] = "qemu,platform\0simple-bus";
+    uint64_t addr = params->platform_bus_base;
+    uint64_t size = params->platform_bus_size;
+    int irq_start = params->platform_bus_first_irq;
+    PlatformBusDevice *pbus;
+    DeviceState *dev;
+
+    /* Create a /platform node that we can put all devices into */
+
+    qemu_fdt_add_subnode(fdt, node);
+    qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
+
+    /* Our platform bus region is less than 32bit big, so 1 cell is enough for
+       address and size */
+    qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
+    qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
+    qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
+
+    qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
+
+    dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
+    pbus = PLATFORM_BUS_DEVICE(dev);
+
+    /* We can only create dt nodes for dynamic devices when they're ready */
+    if (pbus->done_gathering) {
+        PlatformDevtreeData data = {
+            .fdt = fdt,
+            .mpic = mpic,
+            .irq_start = irq_start,
+            .node = node,
+            .pbus = pbus,
+        };
+
+        /* Loop through all dynamic sysbus devices and create nodes for them */
+        foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
+    }
+
+    g_free(node);
+}
+
 static int ppce500_load_device_tree(MachineState *machine,
                                     PPCE500Params *params,
                                     hwaddr addr,
@@ -379,6 +447,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->has_platform_bus) {
+        platform_bus_create_devtree(params, fdt, mpic);
+    }
+
     params->fixup_devtree(params, fdt);
 
     if (toplevel_compat) {
@@ -407,6 +479,7 @@ typedef struct DeviceTreeParams {
     hwaddr initrd_size;
     hwaddr kernel_base;
     hwaddr kernel_size;
+    Notifier notifier;
 } DeviceTreeParams;
 
 static void ppce500_reset_device_tree(void *opaque)
@@ -417,6 +490,12 @@ static void ppce500_reset_device_tree(void *opaque)
                              false);
 }
 
+static void ppce500_init_notify(Notifier *notifier, void *data)
+{
+    DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
+    ppce500_reset_device_tree(p);
+}
+
 static int ppce500_prep_device_tree(MachineState *machine,
                                     PPCE500Params *params,
                                     hwaddr addr,
@@ -435,6 +514,8 @@ static int ppce500_prep_device_tree(MachineState *machine,
     p->kernel_size = kernel_size;
 
     qemu_register_reset(ppce500_reset_device_tree, p);
+    p->notifier.notify = ppce500_init_notify;
+    qemu_add_machine_init_done_notifier(&p->notifier);
 
     /* Issue the device tree loader once, so that we get the size of the blob */
     return ppce500_load_device_tree(machine, params, addr, initrd_base,
@@ -769,6 +850,25 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
         cur_base = (32 * 1024 * 1024);
     }
 
+    /* Platform Bus Device */
+    if (params->has_platform_bus) {
+        dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
+        dev->id = TYPE_PLATFORM_BUS_DEVICE;
+        qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
+        qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
+        qdev_init_nofail(dev);
+        s = SYS_BUS_DEVICE(dev);
+
+        for (i = 0; i < params->platform_bus_num_irqs; i++) {
+            int irqn = params->platform_bus_first_irq + i;
+            sysbus_connect_irq(s, i, mpic[irqn]);
+        }
+
+        memory_region_add_subregion(address_space_mem,
+                                    params->platform_bus_base,
+                                    sysbus_mmio_get_region(s, 0));
+    }
+
     /* Load kernel. */
     if (machine->kernel_filename) {
         kernel_base = cur_base;
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 08b25fa..f1b2766 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -11,6 +11,11 @@ typedef struct PPCE500Params {
     void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
 
     int mpic_version;
+    bool has_platform_bus;
+    hwaddr platform_bus_base;
+    hwaddr platform_bus_size;
+    int platform_bus_first_irq;
+    int platform_bus_num_irqs;
 } PPCE500Params;
 
 void ppce500_init(MachineState *machine, PPCE500Params *params);
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index 27df31d..befe1d1 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -35,6 +35,11 @@ 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,
+        .has_platform_bus = true,
+        .platform_bus_base = 0xf00000000ULL,
+        .platform_bus_size = (128ULL * 1024 * 1024),
+        .platform_bus_first_irq = 5,
+        .platform_bus_num_irqs = 10,
     };
 
     /* Older KVM versions don't support EPR which breaks guests when we announce
@@ -51,6 +56,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.1.4

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

* [Qemu-devel] [PATCH v3 7/7] e500: Add support for eTSEC in device tree
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
                   ` (5 preceding siblings ...)
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 6/7] PPC: e500: Support dynamically spawned sysbus devices Alexander Graf
@ 2014-09-24 15:22 ` Alexander Graf
  2014-09-24 15:40 ` [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Paolo Bonzini
  7 siblings, 0 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-24 15:22 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

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>

---

v1 -> v2:

  - fix device name (base on reg for value after @)
  - use qom properties to fetch mmio and irq props
  - remove useless interrupt-parent
  - make interrupts level triggered

v2 -> v3:

  - use new platform bus APIs
---
 hw/ppc/e500.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index f16bab7..22cfeac 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/platform-bus.h"
+#include "hw/net/fsl_etsec/etsec.h"
 
 #define EPAPR_MAGIC                (0x45504150)
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
@@ -132,11 +133,53 @@ typedef struct PlatformDevtreeData {
     PlatformBusDevice *pbus;
 } PlatformDevtreeData;
 
+static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
+{
+    eTSEC *etsec = ETSEC_COMMON(sbdev);
+    PlatformBusDevice *pbus = data->pbus;
+    hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+    int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
+    int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
+    int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
+    gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
+    gchar *group = g_strdup_printf("%s/queue-group", node);
+    void *fdt = data->fdt;
+
+    assert((int64_t)mmio0 >= 0);
+    assert(irq0 >= 0);
+    assert(irq1 >= 0);
+    assert(irq2 >= 0);
+
+    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(SysBusDevice *sbdev, void *opaque)
 {
     PlatformDevtreeData *data = opaque;
     bool matched = false;
 
+    if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
+        create_devtree_etsec(sbdev, data);
+        matched = true;
+    }
+
     if (!matched) {
         error_report("Device %s is not supported by this machine yet.",
                      qdev_fw_name(DEVICE(sbdev)));
-- 
1.8.1.4

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

* Re: [Qemu-devel] [PATCH v3 2/7] sysbus: Make devices spawnable via -device
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 2/7] sysbus: Make devices spawnable via -device Alexander Graf
@ 2014-09-24 15:37   ` Paolo Bonzini
  2014-09-25 13:17     ` [Qemu-devel] [PATCH v4 " Alexander Graf
  0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2014-09-24 15:37 UTC (permalink / raw)
  To: Alexander Graf, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber

Il 24/09/2014 17:22, Alexander Graf ha scritto:
> +static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
> +{
> +    error_report("Device '%s' can not be handled by this machine",
> +                 qdev_fw_name(DEVICE(sbdev)));
> +    exit(1);
> +}

The firmware name is usually somewhat opaque.  Maybe use the class name,
and use

'-device %s' cannot be handled by this machine

?  (Note "cannot" is a single word.  "can not be handled" means that the
machine may or may not handle it).

Paolo

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

* Re: [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support
  2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
                   ` (6 preceding siblings ...)
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 7/7] e500: Add support for eTSEC in device tree Alexander Graf
@ 2014-09-24 15:40 ` Paolo Bonzini
  7 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2014-09-24 15:40 UTC (permalink / raw)
  To: Alexander Graf, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber

Il 24/09/2014 17:22, Alexander Graf ha scritto:
> The idea can easily be extended to any sysbus device on any machine type though.
> Everything that a machine has to do is spawn a "platform-bus-device" and generate
> the correct device tree for the guest to see the new devices.

I like this a lot. :)

Paolo

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

* [Qemu-devel] [PATCH v4 2/7] sysbus: Make devices spawnable via -device
  2014-09-24 15:37   ` Paolo Bonzini
@ 2014-09-25 13:17     ` Alexander Graf
  0 siblings, 0 replies; 16+ messages in thread
From: Alexander Graf @ 2014-09-25 13:17 UTC (permalink / raw)
  To: qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, pbonzini, afaerber

Now that we can properly map sysbus devices that haven't been connected to
something forcefully by C code, we can allow the -device command line option
to spawn them.

For machines that don't implement dynamic sysbus assignment in their board
files we add a new bool "has_dynamic_sysbus" to the machine class.
When that property is false (default), we bail out when we see dynamically
spawned sysbus devices, like we did before.

Signed-off-by: Alexander Graf <agraf@suse.de>

---

v1 -> v2:

  - use bool in MachineClass rather than property

v2 -> v3:

  - use search helper

v3 -> v4:

  - reword error message

diff --git a/hw/core/machine.c b/hw/core/machine.c
index 7f3418c..19d3e3a 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -12,6 +12,9 @@
 
 #include "hw/boards.h"
 #include "qapi/visitor.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
 
 static char *machine_get_accel(Object *obj, Error **errp)
 {
@@ -257,8 +260,35 @@ static void machine_set_iommu(Object *obj, bool value, Error **errp)
     ms->iommu = value;
 }
 
+static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque)
+{
+    error_report("Option '-device %s' cannot be handled by this machine",
+                 object_class_get_name(object_get_class(OBJECT(sbdev))));
+    exit(1);
+}
+
+static void machine_init_notify(Notifier *notifier, void *data)
+{
+    Object *machine = qdev_get_machine();
+    ObjectClass *oc = object_get_class(machine);
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    if (mc->has_dynamic_sysbus) {
+        /* Our machine can handle dynamic sysbus devices, we're all good */
+        return;
+    }
+
+    /*
+     * Loop through all dynamically created devices and check whether there
+     * are sysbus devices among them. If there are, error out.
+     */
+    foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
+}
+
 static void machine_initfn(Object *obj)
 {
+    MachineState *ms = MACHINE(obj);
+
     object_property_add_str(obj, "accel",
                             machine_get_accel, machine_set_accel, NULL);
     object_property_add_bool(obj, "kernel-irqchip",
@@ -303,6 +333,10 @@ static void machine_initfn(Object *obj)
     object_property_add_bool(obj, "iommu",
                              machine_get_iommu,
                              machine_set_iommu, NULL);
+
+    /* Register notifier when init is done for sysbus sanity checks */
+    ms->sysbus_notifier.notify = machine_init_notify;
+    qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
 }
 
 static void machine_finalize(Object *obj)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 19437e6..7bfe381 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -283,13 +283,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = sysbus_device_init;
     k->bus_type = TYPE_SYSTEM_BUS;
-    /*
-     * device_add plugs devices into suitable bus.  For "real" buses,
-     * that actually connects the device.  For sysbus, the connections
-     * need to be made separately, and device_add can't do that.  The
-     * device would be left unconnected, and could not possibly work.
-     */
-    k->cannot_instantiate_with_device_add_yet = true;
 }
 
 static const TypeInfo sysbus_device_type_info = {
diff --git a/include/hw/boards.h b/include/hw/boards.h
index dfb6718..12e77ea 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -35,7 +35,8 @@ struct QEMUMachine {
         use_sclp:1,
         no_floppy:1,
         no_cdrom:1,
-        no_sdcard:1;
+        no_sdcard:1,
+        has_dynamic_sysbus:1;
     int is_default;
     const char *default_machine_opts;
     const char *default_boot_order;
@@ -93,7 +94,8 @@ struct MachineClass {
         use_sclp:1,
         no_floppy:1,
         no_cdrom:1,
-        no_sdcard:1;
+        no_sdcard:1,
+        has_dynamic_sysbus:1;
     int is_default;
     const char *default_machine_opts;
     const char *default_boot_order;
@@ -110,6 +112,8 @@ struct MachineClass {
 struct MachineState {
     /*< private >*/
     Object parent_obj;
+    Notifier sysbus_notifier;
+
     /*< public >*/
 
     char *accel;
diff --git a/vl.c b/vl.c
index dbdca59..0540db4 100644
--- a/vl.c
+++ b/vl.c
@@ -1591,6 +1591,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
     mc->no_floppy = qm->no_floppy;
     mc->no_cdrom = qm->no_cdrom;
     mc->no_sdcard = qm->no_sdcard;
+    mc->has_dynamic_sysbus = qm->has_dynamic_sysbus;
     mc->is_default = qm->is_default;
     mc->default_machine_opts = qm->default_machine_opts;
     mc->default_boot_order = qm->default_boot_order;

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

* Re: [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device
  2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device Alexander Graf
@ 2014-09-26 12:05   ` Paolo Bonzini
  2014-09-26 12:26     ` Alexander Graf
  0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2014-09-26 12:05 UTC (permalink / raw)
  To: Alexander Graf, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber

Il 24/09/2014 17:22, Alexander Graf ha scritto:
> +    if (!memory_region_is_mapped(sbdev_mr)) {
> +        /* Region is not mapped? */
> +        return -1;
> +    }
> +
> +    parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
> +
> +    assert(parent_mr);
> +    if (parent_mr != pbus_mr_obj) {
> +        /* MMIO region is not mapped on platform bus */
> +        return -1;
> +    }
> +
> +    return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);

I think this should try going through the parent recursively until
reaching NULL (which would fail) or pbus_mr_obj.

Paolo

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

* Re: [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device
  2014-09-26 12:05   ` Paolo Bonzini
@ 2014-09-26 12:26     ` Alexander Graf
  2014-09-26 12:44       ` Paolo Bonzini
  0 siblings, 1 reply; 16+ messages in thread
From: Alexander Graf @ 2014-09-26 12:26 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber

On 09/26/2014 02:05 PM, Paolo Bonzini wrote:
> Il 24/09/2014 17:22, Alexander Graf ha scritto:
>> +    if (!memory_region_is_mapped(sbdev_mr)) {
>> +        /* Region is not mapped? */
>> +        return -1;
>> +    }
>> +
>> +    parent_mr = object_property_get_link(OBJECT(sbdev_mr), "container", NULL);
>> +
>> +    assert(parent_mr);
>> +    if (parent_mr != pbus_mr_obj) {
>> +        /* MMIO region is not mapped on platform bus */
>> +        return -1;
>> +    }
>> +
>> +    return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL);
> I think this should try going through the parent recursively until
> reaching NULL (which would fail) or pbus_mr_obj.

Are you sure? Imagine one sysbus device includes another. We only want 
to look at the region the lowest sysbus device exposes, no?


Alex

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

* Re: [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device
  2014-09-26 12:26     ` Alexander Graf
@ 2014-09-26 12:44       ` Paolo Bonzini
  2014-09-29  8:24         ` Alexander Graf
  0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2014-09-26 12:44 UTC (permalink / raw)
  To: Alexander Graf, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber

Il 26/09/2014 14:26, Alexander Graf ha scritto:
> 
> Are you sure? Imagine one sysbus device includes another. We only want
> to look at the region the lowest sysbus device exposes, no?

IIUC this function is used to build the device tree.  Say you have 2
consecutive memory regions and the device tree requires separate "reg"
entries for them.  But because they are consecutive (or perhaps because
you have a PCI version of the same device that sticks them in a single
BAR) you use a single MMIO area at the sysbus level.

In that case, you will use platform_bus_get_mmio_addr on the two inner
regions, not the outer one.

BTW, I think you will never have one sysbus device including another.
The contained device would be busless (similar to the "naked" 8250
device in hw/char/serial.c, except perhaps QOMified).

Paolo

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

* Re: [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device
  2014-09-26 12:44       ` Paolo Bonzini
@ 2014-09-29  8:24         ` Alexander Graf
  2014-09-29  8:30           ` Paolo Bonzini
  0 siblings, 1 reply; 16+ messages in thread
From: Alexander Graf @ 2014-09-29  8:24 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber



On 26.09.14 14:44, Paolo Bonzini wrote:
> Il 26/09/2014 14:26, Alexander Graf ha scritto:
>>
>> Are you sure? Imagine one sysbus device includes another. We only want
>> to look at the region the lowest sysbus device exposes, no?
> 
> IIUC this function is used to build the device tree.

Yes, it's used to figure out the map of "start of region x of my device"
to "offset y in the platform bus mmio space".

> Say you have 2
> consecutive memory regions and the device tree requires separate "reg"
> entries for them.  But because they are consecutive (or perhaps because
> you have a PCI version of the same device that sticks them in a single
> BAR) you use a single MMIO area at the sysbus level.
> 
> In that case, you will use platform_bus_get_mmio_addr on the two inner
> regions, not the outer one.

In that case, you will use platform_bus_get_mmio_addr on the outer
region because that's what the device model exposes. The parameter to
this function that tells us which region we want is the "mmio region
number" that sysbus exposes.

If in device tree there are 2 reg properties, the device tree assembling
code has to do the conversion from sysbus granularity to device tree
granularity :).

> 
> BTW, I think you will never have one sysbus device including another.
> The contained device would be busless (similar to the "naked" 8250
> device in hw/char/serial.c, except perhaps QOMified).

Yeah, I agree :).


Alex

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

* Re: [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device
  2014-09-29  8:24         ` Alexander Graf
@ 2014-09-29  8:30           ` Paolo Bonzini
  0 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2014-09-29  8:30 UTC (permalink / raw)
  To: Alexander Graf, qemu-ppc
  Cc: peter.maydell, peter.crosthwaite, eric.auger, qemu-devel,
	sean.stalley, afaerber

Il 29/09/2014 10:24, Alexander Graf ha scritto:
> 
> 
> On 26.09.14 14:44, Paolo Bonzini wrote:
>> Il 26/09/2014 14:26, Alexander Graf ha scritto:
>>>
>>> Are you sure? Imagine one sysbus device includes another. We only want
>>> to look at the region the lowest sysbus device exposes, no?
>>
>> IIUC this function is used to build the device tree.
> 
> Yes, it's used to figure out the map of "start of region x of my device"
> to "offset y in the platform bus mmio space".
> 
>> Say you have 2
>> consecutive memory regions and the device tree requires separate "reg"
>> entries for them.  But because they are consecutive (or perhaps because
>> you have a PCI version of the same device that sticks them in a single
>> BAR) you use a single MMIO area at the sysbus level.
>>
>> In that case, you will use platform_bus_get_mmio_addr on the two inner
>> regions, not the outer one.
> 
> In that case, you will use platform_bus_get_mmio_addr on the outer
> region because that's what the device model exposes. The parameter to
> this function that tells us which region we want is the "mmio region
> number" that sysbus exposes.
> 
> If in device tree there are 2 reg properties, the device tree assembling
> code has to do the conversion from sysbus granularity to device tree
> granularity :).

Thanks for the clarification.  Series

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

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

end of thread, other threads:[~2014-09-29  8:30 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-24 15:22 [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Alexander Graf
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 1/7] sysbus: Add dynamic sysbus device search Alexander Graf
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 2/7] sysbus: Make devices spawnable via -device Alexander Graf
2014-09-24 15:37   ` Paolo Bonzini
2014-09-25 13:17     ` [Qemu-devel] [PATCH v4 " Alexander Graf
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 3/7] sysbus: Expose IRQ enumeration helpers Alexander Graf
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 4/7] sysbus: Expose MMIO enumeration helper Alexander Graf
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 5/7] sysbus: Add new platform bus helper device Alexander Graf
2014-09-26 12:05   ` Paolo Bonzini
2014-09-26 12:26     ` Alexander Graf
2014-09-26 12:44       ` Paolo Bonzini
2014-09-29  8:24         ` Alexander Graf
2014-09-29  8:30           ` Paolo Bonzini
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 6/7] PPC: e500: Support dynamically spawned sysbus devices Alexander Graf
2014-09-24 15:22 ` [Qemu-devel] [PATCH v3 7/7] e500: Add support for eTSEC in device tree Alexander Graf
2014-09-24 15:40 ` [Qemu-devel] [PATCH v3 0/7] Dynamic sysbus device allocation support Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.