qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH 01/19] cpus: Add argument to qemu_get_cpu() to filter CPU


From: Philippe Mathieu-Daudé
Subject: Re: [RFC PATCH 01/19] cpus: Add argument to qemu_get_cpu() to filter CPUs by QOM type
Date: Fri, 20 Oct 2023 19:29:21 +0200
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.15.1

Hi Peter,

On 20/10/23 19:14, Peter Maydell wrote:
On Fri, 20 Oct 2023 at 17:36, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:

Heterogeneous machines have different type of CPU.
qemu_get_cpu() returning unfiltered CPUs doesn't make
sense anymore. Add a 'type' argument to filter CPU by
QOM type.

I'm not sure "filter by CPU type" is ever really the
correct answer to this problem, though.

Picking out a handful of arm-related parts to this patchset
as examples of different situations where we're currently
using qemu_get_cpu():

diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
index 474cfdc87c..1c1585f3e1 100644
--- a/hw/arm/fsl-imx7.c
+++ b/hw/arm/fsl-imx7.c
@@ -212,7 +212,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)

      for (i = 0; i < smp_cpus; i++) {
          SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore);
-        DeviceState  *d   = DEVICE(qemu_get_cpu(i));
+        DeviceState  *d   = DEVICE(qemu_get_cpu(i, NULL));

          irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
          sysbus_connect_irq(sbd, i, irq);

This is an Arm SoC object. What it wants is not "the i'th Arm
CPU in the whole system", but "the i'th CPU in this SoC object".
Conveniently, it has easy access to that: s->cpu[i].

diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
index e7c3d99224..0a698171ab 100644
--- a/hw/arm/pxa2xx_gpio.c
+++ b/hw/arm/pxa2xx_gpio.c
@@ -303,7 +303,7 @@ static void pxa2xx_gpio_realize(DeviceState *dev, Error 
**errp)
  {
      PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);

-    s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu));
+    s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu, NULL));

      qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
      qdev_init_gpio_out(dev, s->handler, s->lines);

This is grabbing a private pointer to the CPU object[*], which
we can do more cleanly by setting a link property, and getting
the board code to pass a pointer to the CPU.

[*] it then uses that pointer to mess with the internals of
the CPU to implement wake-up-on-GPIO in a completely horrible
way, but let's assume we don't want to try to clean that up now...

diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 3c7dfcd6dc..3571d5038f 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -275,7 +275,7 @@ static void create_fdt(SBSAMachineState *sms)

      for (cpu = sms->smp_cpus - 1; cpu >= 0; cpu--) {
          char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
-        ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
+        ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu, NULL));
          CPUState *cs = CPU(armcpu);
          uint64_t mpidr = sbsa_ref_cpu_mp_affinity(sms, cpu);

This is in a board model. By definition the board model for a
non-heterogenous board knows it isn't in a heterogenous system
model, and it doesn't need to say "specifically the first Arm CPU".
So I think we should be able to leave it alone...

diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index bfd8aa5644..8c9098d5d3 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -65,7 +65,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
          /* Make the GIC's TZ support match the CPUs. We assume that
           * either all the CPUs have TZ, or none do.
           */
-        cpuobj = OBJECT(qemu_get_cpu(0));
+        cpuobj = OBJECT(qemu_get_cpu(0, NULL));
          has_el3 = object_property_find(cpuobj, "has_el3") &&
              object_property_get_bool(cpuobj, "has_el3", &error_abort);
          qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
@@ -90,7 +90,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
       * appropriate GIC PPI inputs
       */
      for (i = 0; i < s->num_cpu; i++) {
-        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+        DeviceState *cpudev = DEVICE(qemu_get_cpu(i, NULL));
          int ppibase = s->num_irq - 32 + i * 32;
          int irq;
          /* Mapping from the output timer irq lines from the CPU to the

This is another case where what we want is "the Nth CPU
associated with this peripheral block", not the Nth CPU of
some particular architecture. (It's not as easy to figure
out where we would get that from as it is in the fsl-imx7
case, though -- perhaps we would need to tweak the API
these objects have somehow to pass in pointers to the CPUs?)

diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 2ebf880ead..cdf21dfc11 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -392,7 +392,7 @@ static void arm_gicv3_common_realize(DeviceState *dev, 
Error **errp)
      s->cpu = g_new0(GICv3CPUState, s->num_cpu);

      for (i = 0; i < s->num_cpu; i++) {
-        CPUState *cpu = qemu_get_cpu(i);
+        CPUState *cpu = qemu_get_cpu(i, NULL);
          uint64_t cpu_affid;

          s->cpu[i].cpu = cpu;

These gicv3 uses of qemu_get_cpu() are because instead of doing
the theoretical Right Thing and having the GIC object have to
be told which CPUs it is responsible for, we took a shortcut
and said "there's only one GIC, and it's connected to all the CPUs".
The fix is, again, not filtering by CPU type, but having the
board and SoC models do the work to explicitly represent
"this GIC object is attached to these CPU objects" (via link
properties or otherwise).


So overall there are some places where figuring out the right
replacement for qemu_get_cpu() is tricky, and some places where
it's probably fairly straightforward but just an annoying
amount of extra code to write, and some places where we don't
care because we know the board model is not heterogenous.
But I don't think "filter by CPU architecture type" is usually
going to be what we want.

Thank for these feedbacks. I agree the correct way to fix that
is a tedious case by case audit, most often using link properties.

"we know the board model is not heterogeneous" but we want to
link such board/model altogether in a single binary, using common
APIs.

qemu_get_cpu() isn't scalable, so as you said the board has to
propagate its CPUs as properties to the devices which require
access to them. Eventually removing qemu_get_cpu() use from hw/.

I started isolating PCI Host Bridges devices as an example of
device complex enough to use multiple address spaces, and I figured
it'll take some time... So wanted to give a try at some generic
mechanical changes to allow a small step in my prototype,
postponing the case by case changes. I agree this isn't the best
approach and I should start with few devices, ignoring the rest
of the tree (not converting all at once).

Interrupt Controller are another cases which need CPU as link
properties. See for example this M68K series:
https://lore.kernel.org/qemu-devel/20231020150627.56893-1-philmd@linaro.org/

Regards,

Phil.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]