[PATCH 3/7] hw/arm: xlnx-zynqmp: Don't call qdev_get_machine in soc init

alistair23@gmail.com posted 7 patches 3 weeks, 5 days ago
Maintainers: "Michael S. Tsirkin" <mst@redhat.com>, Igor Mammedov <imammedo@redhat.com>, Ani Sinha <anisinha@redhat.com>, Peter Maydell <peter.maydell@linaro.org>, Jean-Christophe Dubois <jcd@tribudubois.net>, Andrey Smirnov <andrew.smirnov@gmail.com>, Bernhard Beschow <shentey@gmail.com>, Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Palmer Dabbelt <palmer@dabbelt.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
[PATCH 3/7] hw/arm: xlnx-zynqmp: Don't call qdev_get_machine in soc init
Posted by alistair23@gmail.com 3 weeks, 5 days ago
From: Alistair Francis <alistair.francis@wdc.com>

Calling qdev_get_machine() in the soc_init function would result in
the following assert

    ../hw/core/qdev.c:858: qdev_get_machine: Assertion `dev' failed.

when trying to run

    ./qemu-system-aarch64 -S -display none -M virt -device xlnx-zynqmp,help

as the machine wasn't created yet. We call qdev_get_machine() to obtain
the number of CPUs in the machine. So instead of initialising the CPUs in
the SoC init let's instead do it in the realise where the machine
will exist.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/arm/xlnx-zynqmp.c | 42 ++++++++++++++++++------------------------
 1 file changed, 18 insertions(+), 24 deletions(-)

diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 5f0e34ccec..979e55e305 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -380,30 +380,15 @@ static void xlnx_zynqmp_create_unimp_mmio(XlnxZynqMPState *s)
 
 static void xlnx_zynqmp_init(Object *obj)
 {
-    MachineState *ms = MACHINE(qdev_get_machine());
     XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
     int i;
-    int num_apus = MIN(ms->smp.cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
-    int num_rpus = xlnx_zynqmp_get_rpu_number(ms);
 
     object_initialize_child(obj, "apu-cluster", &s->apu_cluster,
                             TYPE_CPU_CLUSTER);
     qdev_prop_set_uint32(DEVICE(&s->apu_cluster), "cluster-id", 0);
 
-    for (i = 0; i < num_apus; i++) {
-        object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
-                                &s->apu_cpu[i],
-                                ARM_CPU_TYPE_NAME("cortex-a53"));
-    }
-
     object_initialize_child(obj, "gic", &s->gic, gic_class_name());
 
-    if (num_rpus) {
-        /* Do not create the rpu_gic if we don't have rpus */
-        object_initialize_child(obj, "rpu_gic", &s->rpu_gic,
-                                gic_class_name());
-    }
-
     for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
         object_initialize_child(obj, "gem[*]", &s->gem[i], TYPE_CADENCE_GEM);
         object_initialize_child(obj, "gem-irq-orgate[*]",
@@ -453,15 +438,6 @@ static void xlnx_zynqmp_init(Object *obj)
     object_initialize_child(obj, "qspi-irq-orgate",
                             &s->qspi_irq_orgate, TYPE_OR_IRQ);
 
-    if (num_rpus) {
-        for (i = 0; i < ARRAY_SIZE(s->splitter); i++) {
-            g_autofree char *name = g_strdup_printf("irq-splitter%d", i);
-            object_initialize_child(obj, name, &s->splitter[i], TYPE_SPLIT_IRQ);
-        }
-    }
-
-
-
     for (i = 0; i < XLNX_ZYNQMP_NUM_USB; i++) {
         object_initialize_child(obj, "usb[*]", &s->usb[i], TYPE_USB_DWC3);
     }
@@ -483,6 +459,24 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 
     ram_size = memory_region_size(s->ddr_ram);
 
+    for (i = 0; i < num_apus; i++) {
+        object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
+                                &s->apu_cpu[i],
+                                ARM_CPU_TYPE_NAME("cortex-a53"));
+    }
+
+    if (num_rpus) {
+        /* Do not create the rpu_gic if we don't have rpus */
+        object_initialize_child(OBJECT(dev), "rpu_gic", &s->rpu_gic,
+                                gic_class_name());
+
+        for (i = 0; i < ARRAY_SIZE(s->splitter); i++) {
+            g_autofree char *name = g_strdup_printf("irq-splitter%d", i);
+            object_initialize_child(OBJECT(dev), name, &s->splitter[i], TYPE_SPLIT_IRQ);
+        }
+    }
+
+
     /*
      * Create the DDR Memory Regions. User friendly checks should happen at
      * the board level
-- 
2.53.0
Re: [PATCH 3/7] hw/arm: xlnx-zynqmp: Don't call qdev_get_machine in soc init
Posted by Peter Maydell 3 weeks, 5 days ago
On Thu, 12 Mar 2026 at 04:32, <alistair23@gmail.com> wrote:
>
> From: Alistair Francis <alistair.francis@wdc.com>
>
> Calling qdev_get_machine() in the soc_init function would result in
> the following assert
>
>     ../hw/core/qdev.c:858: qdev_get_machine: Assertion `dev' failed.
>
> when trying to run
>
>     ./qemu-system-aarch64 -S -display none -M virt -device xlnx-zynqmp,help
>
> as the machine wasn't created yet. We call qdev_get_machine() to obtain
> the number of CPUs in the machine. So instead of initialising the CPUs in
> the SoC init let's instead do it in the realise where the machine
> will exist.

Here I'm not sure I agree. We should init child objects in init, not in
realize, unless there's a strong reason we need to not do that.
Working around "we crash if the user does something pointless
on the command line" isn't a strong enough reason IMHO.

The problem here, though, is of the kind "what child objects we
need depends on the configuration of this device", which kind of
pushes "init children" into "realize". We do that in some places
already. But I don't like that -- it makes us inconsistent about
how we handle child init. If we're OK doing some child init in
the parent's realize method, why not do all child init in realize?

thanks
-- PMM
Re: [PATCH 3/7] hw/arm: xlnx-zynqmp: Don't call qdev_get_machine in soc init
Posted by BALATON Zoltan 3 weeks, 5 days ago
On Thu, 12 Mar 2026, Peter Maydell wrote:
> On Thu, 12 Mar 2026 at 04:32, <alistair23@gmail.com> wrote:
>>
>> From: Alistair Francis <alistair.francis@wdc.com>
>>
>> Calling qdev_get_machine() in the soc_init function would result in
>> the following assert
>>
>>     ../hw/core/qdev.c:858: qdev_get_machine: Assertion `dev' failed.
>>
>> when trying to run
>>
>>     ./qemu-system-aarch64 -S -display none -M virt -device xlnx-zynqmp,help
>>
>> as the machine wasn't created yet. We call qdev_get_machine() to obtain
>> the number of CPUs in the machine. So instead of initialising the CPUs in
>> the SoC init let's instead do it in the realise where the machine
>> will exist.
>
> Here I'm not sure I agree. We should init child objects in init, not in
> realize, unless there's a strong reason we need to not do that.
> Working around "we crash if the user does something pointless
> on the command line" isn't a strong enough reason IMHO.
>
> The problem here, though, is of the kind "what child objects we
> need depends on the configuration of this device", which kind of
> pushes "init children" into "realize". We do that in some places
> already. But I don't like that -- it makes us inconsistent about
> how we handle child init. If we're OK doing some child init in
> the parent's realize method, why not do all child init in realize?

How about saying that we do most things in realize (so simple devices 
don't even need an init method) and do in init those that need to be done 
before realize such as things exposing properties that can be set before 
realize. I think that's better than always splitting init and realize for 
all children that's most of the time would just add complexity without 
reason.

This is similar to what I asked about in
https://lists.nongnu.org/archive/html/qemu-devel/2026-02/msg03945.html

Regards,
BALATON Zoltan
Re: [PATCH 3/7] hw/arm: xlnx-zynqmp: Don't call qdev_get_machine in soc init
Posted by Alistair Francis 3 weeks, 4 days ago
On Thu, Mar 12, 2026 at 11:39 PM BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Thu, 12 Mar 2026, Peter Maydell wrote:
> > On Thu, 12 Mar 2026 at 04:32, <alistair23@gmail.com> wrote:
> >>
> >> From: Alistair Francis <alistair.francis@wdc.com>
> >>
> >> Calling qdev_get_machine() in the soc_init function would result in
> >> the following assert
> >>
> >>     ../hw/core/qdev.c:858: qdev_get_machine: Assertion `dev' failed.
> >>
> >> when trying to run
> >>
> >>     ./qemu-system-aarch64 -S -display none -M virt -device xlnx-zynqmp,help
> >>
> >> as the machine wasn't created yet. We call qdev_get_machine() to obtain
> >> the number of CPUs in the machine. So instead of initialising the CPUs in
> >> the SoC init let's instead do it in the realise where the machine
> >> will exist.
> >
> > Here I'm not sure I agree. We should init child objects in init, not in
> > realize, unless there's a strong reason we need to not do that.
> > Working around "we crash if the user does something pointless
> > on the command line" isn't a strong enough reason IMHO.

Agreed, but there is an actual reason (maybe I should have been
clearer in the commit message). At SoC init the configuration for the
machine might not have been completed. So we don't have enough
information to init some child objects.

> >
> > The problem here, though, is of the kind "what child objects we
> > need depends on the configuration of this device", which kind of
> > pushes "init children" into "realize". We do that in some places

Exactly

> > already. But I don't like that -- it makes us inconsistent about
> > how we handle child init. If we're OK doing some child init in
> > the parent's realize method, why not do all child init in realize?

I agree it's not ideal. I think of it as we init children in the
parent init unless we can't because we depend on some configuration
data. At that point then we just have to do it in realise. We don't
really have much of an option. Maybe in the future things change and
we can revert this back, but for the time being I don't think there is
a better option

>
> How about saying that we do most things in realize (so simple devices
> don't even need an init method) and do in init those that need to be done
> before realize such as things exposing properties that can be set before
> realize. I think that's better than always splitting init and realize for
> all children that's most of the time would just add complexity without
> reason.

I do think we should strive to do all children init in the parent init
function, just sometimes we can't if we depend no certain config
information

Alistair

>
> This is similar to what I asked about in
> https://lists.nongnu.org/archive/html/qemu-devel/2026-02/msg03945.html
>
> Regards,
> BALATON Zoltan
Re: [PATCH 3/7] hw/arm: xlnx-zynqmp: Don't call qdev_get_machine in soc init
Posted by Thomas Huth 3 weeks, 1 day ago
On 13/03/2026 01.18, Alistair Francis wrote:
> On Thu, Mar 12, 2026 at 11:39 PM BALATON Zoltan <balaton@eik.bme.hu> wrote:
>>
>> On Thu, 12 Mar 2026, Peter Maydell wrote:
>>> On Thu, 12 Mar 2026 at 04:32, <alistair23@gmail.com> wrote:
>>>>
>>>> From: Alistair Francis <alistair.francis@wdc.com>
>>>>
>>>> Calling qdev_get_machine() in the soc_init function would result in
>>>> the following assert
>>>>
>>>>      ../hw/core/qdev.c:858: qdev_get_machine: Assertion `dev' failed.
>>>>
>>>> when trying to run
>>>>
>>>>      ./qemu-system-aarch64 -S -display none -M virt -device xlnx-zynqmp,help
>>>>
>>>> as the machine wasn't created yet. We call qdev_get_machine() to obtain
>>>> the number of CPUs in the machine. So instead of initialising the CPUs in
>>>> the SoC init let's instead do it in the realise where the machine
>>>> will exist.
>>>
>>> Here I'm not sure I agree. We should init child objects in init, not in
>>> realize, unless there's a strong reason we need to not do that.
>>> Working around "we crash if the user does something pointless
>>> on the command line" isn't a strong enough reason IMHO.
> 
> Agreed, but there is an actual reason (maybe I should have been
> clearer in the commit message). At SoC init the configuration for the
> machine might not have been completed. So we don't have enough
> information to init some child objects.
> 
>>>
>>> The problem here, though, is of the kind "what child objects we
>>> need depends on the configuration of this device", which kind of
>>> pushes "init children" into "realize". We do that in some places
> 
> Exactly
> 
>>> already. But I don't like that -- it makes us inconsistent about
>>> how we handle child init. If we're OK doing some child init in
>>> the parent's realize method, why not do all child init in realize?
> 
> I agree it's not ideal. I think of it as we init children in the
> parent init unless we can't because we depend on some configuration
> data. At that point then we just have to do it in realise. We don't
> really have much of an option. Maybe in the future things change and
> we can revert this back, but for the time being I don't think there is
> a better option

I think I agree with Alistair here. First, let's state that ideally, the SoC 
device should not query the amount of CPUs, but have a property that 
specifies this configuration, and it is then up to the machine init code to 
set that configuration when creating the devices of the machine. But we then 
still have the problem that the instance_init function of the device is 
called before the machine code can set the property. Or is there a way to 
set properties before the instance of a device has been created? (global 
properties maybe, but that's ugly, too?)

So I think for the time being, let's use Alistair's patches to fix the 
crashes. We can still rework the code later in case we find a better 
solution. Thus I'll add the series to my next pull request if there are no 
objections.

  Thomas