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

Re: [PATCH v3 1/3] xen/device-tree: Parse 'cpu-map' node for CPU topology exploration


  • To: Hirokazu Takahashi <taka@xxxxxxxxxxxxx>
  • From: Jan Beulich <jbeulich@xxxxxxxx>
  • Date: Tue, 30 Jun 2026 08:53:37 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=suse.com header.i="@suse.com" header.h="Content-Transfer-Encoding:In-Reply-To:Autocrypt:From:Content-Language:References:Cc:To:Subject:User-Agent:MIME-Version:Date:Message-ID"
  • Autocrypt: addr=jbeulich@xxxxxxxx; keydata= xsDiBFk3nEQRBADAEaSw6zC/EJkiwGPXbWtPxl2xCdSoeepS07jW8UgcHNurfHvUzogEq5xk hu507c3BarVjyWCJOylMNR98Yd8VqD9UfmX0Hb8/BrA+Hl6/DB/eqGptrf4BSRwcZQM32aZK 7Pj2XbGWIUrZrd70x1eAP9QE3P79Y2oLrsCgbZJfEwCgvz9JjGmQqQkRiTVzlZVCJYcyGGsD /0tbFCzD2h20ahe8rC1gbb3K3qk+LpBtvjBu1RY9drYk0NymiGbJWZgab6t1jM7sk2vuf0Py O9Hf9XBmK0uE9IgMaiCpc32XV9oASz6UJebwkX+zF2jG5I1BfnO9g7KlotcA/v5ClMjgo6Gl MDY4HxoSRu3i1cqqSDtVlt+AOVBJBACrZcnHAUSuCXBPy0jOlBhxPqRWv6ND4c9PH1xjQ3NP nxJuMBS8rnNg22uyfAgmBKNLpLgAGVRMZGaGoJObGf72s6TeIqKJo/LtggAS9qAUiuKVnygo 3wjfkS9A3DRO+SpU7JqWdsveeIQyeyEJ/8PTowmSQLakF+3fote9ybzd880fSmFuIEJldWxp Y2ggPGpiZXVsaWNoQHN1c2UuY29tPsJgBBMRAgAgBQJZN5xEAhsDBgsJCAcDAgQVAggDBBYC AwECHgECF4AACgkQoDSui/t3IH4J+wCfQ5jHdEjCRHj23O/5ttg9r9OIruwAn3103WUITZee e7Sbg12UgcQ5lv7SzsFNBFk3nEQQCACCuTjCjFOUdi5Nm244F+78kLghRcin/awv+IrTcIWF hUpSs1Y91iQQ7KItirz5uwCPlwejSJDQJLIS+QtJHaXDXeV6NI0Uef1hP20+y8qydDiVkv6l IreXjTb7DvksRgJNvCkWtYnlS3mYvQ9NzS9PhyALWbXnH6sIJd2O9lKS1Mrfq+y0IXCP10eS FFGg+Av3IQeFatkJAyju0PPthyTqxSI4lZYuJVPknzgaeuJv/2NccrPvmeDg6Coe7ZIeQ8Yj t0ARxu2xytAkkLCel1Lz1WLmwLstV30g80nkgZf/wr+/BXJW/oIvRlonUkxv+IbBM3dX2OV8 AmRv1ySWPTP7AAMFB/9PQK/VtlNUJvg8GXj9ootzrteGfVZVVT4XBJkfwBcpC/XcPzldjv+3 HYudvpdNK3lLujXeA5fLOH+Z/G9WBc5pFVSMocI71I8bT8lIAzreg0WvkWg5V2WZsUMlnDL9 mpwIGFhlbM3gfDMs7MPMu8YQRFVdUvtSpaAs8OFfGQ0ia3LGZcjA6Ik2+xcqscEJzNH+qh8V m5jjp28yZgaqTaRbg3M/+MTbMpicpZuqF4rnB0AQD12/3BNWDR6bmh+EkYSMcEIpQmBM51qM EKYTQGybRCjpnKHGOxG0rfFY1085mBDZCH5Kx0cl0HVJuQKC+dV2ZY5AqjcKwAxpE75MLFkr wkkEGBECAAkFAlk3nEQCGwwACgkQoDSui/t3IH7nnwCfcJWUDUFKdCsBH/E5d+0ZnMQi+G0A nAuWpQkjM1ASeQwSHEeAWPgskBQL
  • Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • Delivery-date: Tue, 30 Jun 2026 06:53:56 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On 29.06.2026 23:58, Hirokazu Takahashi wrote:
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -101,6 +101,16 @@ endchoice
>  
>  source "arch/Kconfig"
>  
> +config ARM_CPU_TOPOLOGY
> +     bool "CPU topology support (UNSUPPORTED)" if UNSUPPORTED
> +     select CPU_TOPOLOGY
> +     help
> +       Retrieve CPU topology information from the device tree to optimize
> +       virtual CPU scheduling.
> +
> +       Note: Implementation for parsing CPU topology from the ACPI PPTT
> +       is currently missing.

This option isn't itself used anywhere; it exists solely for its "select"
effect. Since topology is an arch-independent concept, I'd suggest
CPU_TOPOLOGY to have the prompt and help text, and there being a per-arch
HAS_CPU_TOPOLOGY (or maybe HAS_GENERIC_CPU_TOPOLOGY, to avoid the false
impression that x86 doesn't deal with topology) which CPU_TOPOLOGY then
depends on.

> --- a/xen/common/Kconfig
> +++ b/xen/common/Kconfig
> @@ -188,6 +188,14 @@ config VM_EVENT
>  config NEEDS_LIBELF
>       bool
>  
> +config DT_CPU_TOPOLOGY
> +     bool
> +
> +config CPU_TOPOLOGY
> +     bool
> +     select DT_CPU_TOPOLOGY if DEVICE_TREE_PARSE
> +     select ACPI_CPU_TOPOLOGY if ACPI

As per part of what I said above, this may also want to be GENERIC_CPU_TOPOLOGY
or some such. Other maintainers' input may be wanted here.

> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -5,6 +5,7 @@ obj-$(CONFIG_GENERIC_BUG_FRAME) += bug.o
>  obj-$(CONFIG_HYPFS_CONFIG) += config_data.o
>  obj-$(CONFIG_CORE_PARKING) += core_parking.o
>  obj-y += cpu.o
> +obj-$(CONFIG_CPU_TOPOLOGY) += cpu-topology.o

As least for now this may want to be

obj-bin-$(CONFIG_CPU_TOPOLOGY) += cpu-topology.init.o

seeing that ...

> --- /dev/null
> +++ b/xen/common/cpu-topology.c
> @@ -0,0 +1,59 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include <xen/acpi.h>
> +#include <xen/cpu-topology.h>
> +#include <xen/cpumask.h>
> +#include <xen/init.h>
> +
> +static void __init free_topology_table(void)
> +{
> +    unsigned int cpu;
> +
> +    for ( cpu = 0; cpu < nr_cpu_ids; cpu++ )
> +    {
> +        free_cpumask_var(cpu_topology[cpu].thread_sibling);
> +        free_cpumask_var(cpu_topology[cpu].core_sibling);
> +        free_cpumask_var(cpu_topology[cpu].cluster_sibling);
> +    }
> +
> +    XFREE(cpu_topology);
> +}
> +
> +void __init init_cpu_topology(void)
> +{
> +    unsigned int cpu;
> +
> +    cpu_topology = xzalloc_array(struct cpu_topology, nr_cpu_ids);
> +    if ( !cpu_topology )
> +    {
> +        printk(XENLOG_ERR "Failed to allocate memory for cpu_topology 
> table\n");
> +        return;
> +    }
> +
> +    for ( cpu = 0; cpu < nr_cpu_ids; cpu++ )
> +    {
> +        if ( !zalloc_cpumask_var(&cpu_topology[cpu].thread_sibling) ||
> +             !zalloc_cpumask_var(&cpu_topology[cpu].core_sibling) ||
> +             !zalloc_cpumask_var(&cpu_topology[cpu].cluster_sibling) )
> +        {
> +            free_topology_table();
> +            printk(XENLOG_ERR "Failed to allocate memory for cpu_topology 
> table\n");
> +            return;
> +        }
> +    }
> +
> +    if ( acpi_disabled )
> +        dt_init_cpu_topology();
> +    else
> +        acpi_init_cpu_topology();
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */

... there are only __init functions here.

> --- a/xen/common/device-tree/Makefile
> +++ b/xen/common/device-tree/Makefile
> @@ -1,6 +1,7 @@
>  obj-y += bootfdt.init.o
>  obj-$(CONFIG_HAS_DEVICE_TREE_DISCOVERY) += bootinfo-fdt.init.o
>  obj-$(CONFIG_HAS_DEVICE_TREE_DISCOVERY) += bootinfo.init.o
> +obj-$(CONFIG_DT_CPU_TOPOLOGY) += cpu-topology.o

Same here, albeit requiring ...

> --- /dev/null
> +++ b/xen/common/device-tree/cpu-topology.c
> @@ -0,0 +1,352 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Derived from Linux kernel 7.0's $drivers/base/arch_topology.c
> + * Parse cpu topology information.
> + */
> +
> +#include <xen/acpi.h>
> +#include <xen/cpu-topology.h>
> +#include <xen/cpumask.h>
> +#include <xen/device_tree.h>
> +#include <xen/errno.h>
> +#include <xen/init.h>
> +#include <xen/numa.h>
> +#include <xen/xvmalloc.h>
> +
> +struct cpu_map {
> +    unsigned int thread_id;
> +    unsigned int core_id;
> +    unsigned int cluster_id;
> +    unsigned int package_id;
> +};
> +
> +struct cpu_topology *cpu_topology;

... this (which ought to be __ro_after_init anyway) to be moved elsewhere.

> +static const unsigned int __initdata invalid_topo_id = (~0U);

Nit: What use are the parentheses here? This may want to be a #define (with
the identifier all uppercase), in which case the parentheses need keeping.

> +void __init map_cpuid_to_node(unsigned int cpuid,
> +                              struct dt_device_node *cpu_node)
> +{
> +    if ( cpuid < NR_CPUS )

Better use ARRAY_SIZE() when ...

> +        dt_cpu_table[cpuid] = cpu_node;

... an array access is guarded.

Just for my own understanding: It is deliberate for cpuid >= NR_CPUS to go
entirely silently here?

As to "cpuid" - please can this be "cpu", as you have it elsewhere. "cpuid"
is a misleading term here when x86 comes into play.

> +static unsigned int __init cpu_node_to_id(struct dt_device_node *cpu_node)
> +{
> +    unsigned int cpu;
> +    bool found = false;

Pointless initializer; in fact ...

> +    for_each_possible_cpu(cpu)
> +    {
> +        found = (cpu_node == dt_cpu_table[cpu]);

... the declaration could move here, or - better yet - could be omitted
altogether, as the variable is used ...

> +        if ( found )

... exacly once.

> +/*
> + * This function returns the logic cpu number of the node.

Nit: "logical"? Also "of the node" is misleading (towards NUMA), "of the DT
node" would be unambiguous.

> + */
> +static unsigned int __init get_cpu_for_node(struct dt_device_node *node)

Pointer-to-const?

> +{
> +    struct dt_device_node *cpu_node = dt_parse_phandle(node, "cpu", 0);

Again? Generally everywhere that it is possible and sensible.

> +    if ( !cpu_node )
> +        return invalid_topo_id;
> +
> +    return cpu_node_to_id(cpu_node);
> +}
> +
> +static int __init parse_core(struct dt_device_node *core,
> +                             unsigned int package_id,
> +                             unsigned int cluster_id,
> +                             unsigned int core_id)
> +{
> +    char name[20];

Move to the more narrow scope it's used in? (Again please take as a
general remark.)

> +    bool leaf = true;
> +    unsigned int i = 0;
> +    unsigned int cpu;
> +
> +    do {
> +        struct dt_device_node *t;
> +
> +        snprintf(name, sizeof(name), "thread%u", i);
> +        t = dt_find_child_node_by_name(core, name);
> +
> +        if ( !t )
> +            break;
> +
> +        leaf = false;
> +        cpu = get_cpu_for_node(t);
> +        if ( cpu != invalid_topo_id )
> +        {
> +            cpu_map[cpu].package_id = package_id;
> +            cpu_map[cpu].cluster_id = cluster_id;
> +            cpu_map[cpu].core_id = core_id;
> +            cpu_map[cpu].thread_id = i;
> +        }
> +        else
> +        {
> +            printk(XENLOG_ERR "ERROR: %pOF: Can't get CPU for thread\n", t);

I don't think we support %pOF (just yet).

> --- a/xen/drivers/acpi/Makefile
> +++ b/xen/drivers/acpi/Makefile
> @@ -10,3 +10,5 @@ obj-$(CONFIG_PM_OP) += pm-op.o
>  
>  obj-$(CONFIG_X86) += hwregs.o
>  obj-$(CONFIG_X86) += reboot.o
> +
> +obj-$(CONFIG_ACPI_CPU_TOPOLOGY) += topology.o

See earlier remarks as to object containing only __init code. Also this may
better be appended (without a blank line) to the earlier block of objects.

> --- /dev/null
> +++ b/xen/include/xen/cpu-topology.h
> @@ -0,0 +1,35 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef XEN_CPU_TOPOLOGY_H
> +#define XEN_CPU_TOPOLOGY_H
> +
> +#include <xen/dt-cpu-topology.h>
> +
> +struct cpu_topology {
> +    cpumask_var_t thread_sibling;
> +    cpumask_var_t core_sibling;
> +    cpumask_var_t cluster_sibling;

For these to compile independent of what #include-s occurred earlier in the
top-level .c file, don't you need to also "#include <xen/cpumask.h>"? Otoh
I can't quite spot why you #include xen/dt-cpu-topology.h here.

Further shouldn't this move ...

> +};
> +
> +#ifdef CONFIG_CPU_TOPOLOGY

... here?

> +extern struct cpu_topology *cpu_topology;
> +void init_cpu_topology(void);
> +
> +#else /* CONFIG_CPU_TOPOLOGY */
> +
> +#define cpu_topology ((struct cpu_topology *)NULL)

Why exactly is this needed? It very much looks as if its presence may hide
bugs.

> --- /dev/null
> +++ b/xen/include/xen/dt-cpu-topology.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef XEN_DT_CPU_TOPOLOGY_H
> +#define XEN_DT_CPU_TOPOLOGY_H
> +
> +#include <xen/device_tree.h>

Again I can't quite see why this would be needed. You need a forward-decl
of ...

> +#ifdef CONFIG_DT_CPU_TOPOLOGY
> +
> +void map_cpuid_to_node(unsigned int cpuid, struct dt_device_node *cpu_node);

... struct dt_device_node, yes, but that's all.

Jan



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.