:p
atchew
Login
Hello, This patch series introduces basic CPU topology support for ARM Xen. I'm a bit torn on the best way to implement the fallback macros like cpu_to_socket() in cpu-topology.h when CONFIG_CPU_TOPOLOGY is off. Specifically, I want non-x86 architectures to share these fallbacks while keeping x86 from seeing them. The first approach is simple, but it will break if x86 changes how it defines these helpers in the future. For example, if it switches from macros to inline functions: #ifndef cpu_to_socket #define cpu_to_socket(cpu) (0) #endif The second approach is to make them active only for Device Tree setups via CONFIG_DEVICE_TREE_PARSE. However, this might not be the "right" way either, just in case an architecture comes along that doesn't use DT but still populates the topology table via another method like ACPI. #ifdef CONFIG_DEVICE_TREE_PARSE #define cpu_to_socket(cpu) (0) #endif /* CONFIG_DEVICE_TREE_PARSE */ Then again, if ARM, RISC-V, and PPC all end up enabling CONFIG_CPU_TOPOLOGY by default anyway, we won't even need this =n fallback code. So I'm maybe just overthinking this. Future Work: - Support for the "credit2_runqueue=cluster" option. - CPU topology support for RISC-V and PPC (once SMP support is available). - Topology information generation from the ACPI PPTT. Changes in v3: - Use (nr_cpu_ids - 1) as the maximum CPU ID here. The fix for the sparse map mismatch issue on ARM Xen has been split out into a separate patch. - Switch topology sibling masks to cpumask_var_t for dynamic allocation. - Allow the system to keep running with a degraded fallback even if the topology table allocation fails. - Remove the temporary definitions of cpu_to_core() and cpu_to_socket() from RISC-V and PPC processor.h. - Minimize the use of #ifdef blocks, leveraging compiler Dead Code Elimination (DCE) where possible. - Clean up the code to follow the Xen coding style. Please let me know if I missed any style nits! - Verify successful builds across x86, RISC-V, and PPC environments. Changes in v2: - Generate topology information even when ACPI is enabled. Note that this is a temporary implementation and doesn't yet parse the PPTT (Processor Properties Topology Table). - Added support for cpu-map node in Device Tree that doesn't contain explicit cluster node definitions. Changes in v1 from the previous series "Introduce Device Tree based NUMA support for ARM Xen": 1. Optimized Memory Allocation: The series now allocates only the minimum required memory area to manage the essential data for the CPUs. 2. Flexible Device Tree Parsing: The parsing logic no longer depends on the definition order of the 'cpu' nodes and 'cpu-map' nodes in the Device Tree. They can now be read correctly even if their orders do not match. 3. CPU Hotplug Readiness: To support future CPU hotplug, the system assumes that inactive CPUs are also described in the Device Tree. Xen will pre-load and generate the topology information for these inactive CPUs during the boot phase so it stays available in memory. Thank you, Hirokazu Takahashi Hirokazu Takahashi (3): xen/device-tree: Parse 'cpu-map' node for CPU topology exploration xen/sched: Link CPU topology to scheduler xen/sched: Make cpu_nr_siblings() architecture-specific xen/arch/arm/Kconfig | 10 + xen/arch/arm/include/asm/processor.h | 4 - xen/arch/arm/smpboot.c | 29 +- xen/arch/ppc/include/asm/processor.h | 4 - xen/arch/riscv/include/asm/processor.h | 4 - xen/arch/x86/include/asm/processor.h | 1 + xen/common/Kconfig | 8 + xen/common/Makefile | 1 + xen/common/cpu-topology.c | 59 ++++ xen/common/device-tree/Makefile | 1 + xen/common/device-tree/cpu-topology.c | 403 +++++++++++++++++++++++++ xen/common/sched/credit2.c | 21 +- xen/common/sysctl.c | 1 + xen/drivers/acpi/Kconfig | 3 + xen/drivers/acpi/Makefile | 2 + xen/drivers/acpi/topology.c | 41 +++ xen/include/xen/acpi.h | 2 + xen/include/xen/cpu-topology.h | 55 ++++ xen/include/xen/dt-cpu-topology.h | 29 ++ 19 files changed, 642 insertions(+), 36 deletions(-) create mode 100644 xen/common/cpu-topology.c create mode 100644 xen/common/device-tree/cpu-topology.c create mode 100644 xen/drivers/acpi/topology.c create mode 100644 xen/include/xen/cpu-topology.h create mode 100644 xen/include/xen/dt-cpu-topology.h -- 2.43.0
Parse the 'cpu-map' node in the Device Tree to extract CPU topology information. If the 'cpu-map' node is absent, fall back to generating the topology data from the NUMA information. This generation assumes exactly one socket per NUMA node and that SMT is unsupported. Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp> --- xen/arch/arm/Kconfig | 10 + xen/arch/arm/smpboot.c | 6 + xen/common/Kconfig | 8 + xen/common/Makefile | 1 + xen/common/cpu-topology.c | 59 +++++ xen/common/device-tree/Makefile | 1 + xen/common/device-tree/cpu-topology.c | 352 ++++++++++++++++++++++++++ xen/drivers/acpi/Kconfig | 3 + xen/drivers/acpi/Makefile | 2 + xen/drivers/acpi/topology.c | 38 +++ xen/include/xen/acpi.h | 2 + xen/include/xen/cpu-topology.h | 35 +++ xen/include/xen/dt-cpu-topology.h | 29 +++ 13 files changed, 546 insertions(+) create mode 100644 xen/common/cpu-topology.c create mode 100644 xen/common/device-tree/cpu-topology.c create mode 100644 xen/drivers/acpi/topology.c create mode 100644 xen/include/xen/cpu-topology.h create mode 100644 xen/include/xen/dt-cpu-topology.h diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -XXX,XX +XXX,XX @@ 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. + config ACPI bool "ACPI (Advanced Configuration and Power Interface) Support (UNSUPPORTED)" if UNSUPPORTED depends on ARM_64 && ARM_EFI diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -XXX,XX +XXX,XX @@ #include <xen/acpi.h> #include <xen/cpu.h> +#include <xen/cpu-topology.h> #include <xen/cpumask.h> #include <xen/delay.h> #include <xen/device_tree.h> @@ -XXX,XX +XXX,XX @@ static void __init dt_smp_init_cpus(void) } else tmp_map[i] = hwid; + + /* Pass the info to dt_init_cpu_topology() */ + map_cpuid_to_node(i, cpu); } if ( !bootcpu_valid ) @@ -XXX,XX +XXX,XX @@ void __init smp_init_cpus(void) else acpi_smp_init_cpus(); + init_cpu_topology(); + if ( opt_hmp_unsafe ) warning_add("WARNING: HMP COMPUTING HAS BEEN ENABLED.\n" "It has implications on the security and stability of the system,\n" diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ 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 + config NUMA bool diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ 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 obj-$(CONFIG_DEBUG_TRACE) += debugtrace.o obj-$(CONFIG_HAS_DEVICE_TREE_DISCOVERY) += device.o obj-$(filter-out $(CONFIG_X86),$(CONFIG_ACPI)) += device.o diff --git a/xen/common/cpu-topology.c b/xen/common/cpu-topology.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/cpu-topology.c @@ -XXX,XX +XXX,XX @@ +/* 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: + */ diff --git a/xen/common/device-tree/Makefile b/xen/common/device-tree/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/device-tree/Makefile +++ b/xen/common/device-tree/Makefile @@ -XXX,XX +XXX,XX @@ 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 obj-y += device-tree.o obj-$(CONFIG_DOMAIN_BUILD_HELPERS) += domain-build.init.o obj-$(filter $(CONFIG_DOM0LESS_BOOT),$(CONFIG_HAS_DEVICE_TREE_DISCOVERY)) += dom0less-build.init.o diff --git a/xen/common/device-tree/cpu-topology.c b/xen/common/device-tree/cpu-topology.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/device-tree/cpu-topology.c @@ -XXX,XX +XXX,XX @@ +/* 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; +static const unsigned int __initdata invalid_topo_id = (~0U); +static struct cpu_map __initdata cpu_map[NR_CPUS] = { + [0 ... NR_CPUS - 1] = {invalid_topo_id, invalid_topo_id, invalid_topo_id, 0} +}; +static struct dt_device_node *__initdata dt_cpu_table[NR_CPUS]; + +static void __init setup_siblings_masks(unsigned int cpuid) +{ + struct cpu_topology *cpuid_topo = &cpu_topology[cpuid]; + struct cpu_map *cpuid_map = &cpu_map[cpuid]; + unsigned int cpu; + + /* Update core and thread sibling masks */ + for_each_possible_cpu(cpu) + { + struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + struct cpu_map *map = &cpu_map[cpu]; + + if ( cpuid_map->package_id != map->package_id ) + continue; + + cpumask_set_cpu(cpuid, cpu_topo->core_sibling); + cpumask_set_cpu(cpu, cpuid_topo->core_sibling); + + if ( cpuid_map->cluster_id != map->cluster_id ) + continue; + + if ( cpuid_map->cluster_id != invalid_topo_id ) + { + cpumask_set_cpu(cpu, cpuid_topo->cluster_sibling); + cpumask_set_cpu(cpuid, cpu_topo->cluster_sibling); + } + + if ( cpuid_map->core_id != map->core_id ) + continue; + + cpumask_set_cpu(cpuid, cpu_topo->thread_sibling); + cpumask_set_cpu(cpu, cpuid_topo->thread_sibling); + } +} + +static struct dt_device_node *__init + dt_find_child_node_by_name(struct dt_device_node *from, const char *name) +{ + struct dt_device_node *np; + const struct dt_device_node *dt = from; + + dt_for_each_child_node(dt, np) + if ( np->name && (dt_node_cmp(np->name, name) == 0) ) + break; + + return np; +} + +void __init map_cpuid_to_node(unsigned int cpuid, + struct dt_device_node *cpu_node) +{ + if ( cpuid < NR_CPUS ) + dt_cpu_table[cpuid] = cpu_node; +} + +static unsigned int __init cpu_node_to_id(struct dt_device_node *cpu_node) +{ + unsigned int cpu; + bool found = false; + + for_each_possible_cpu(cpu) + { + found = (cpu_node == dt_cpu_table[cpu]); + if ( found ) + return cpu; + } + + return invalid_topo_id; +} + +/* + * This function returns the logic cpu number of the node. + */ +static unsigned int __init get_cpu_for_node(struct dt_device_node *node) +{ + struct dt_device_node *cpu_node = dt_parse_phandle(node, "cpu", 0); + + 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]; + 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); + return -EINVAL; + } + i++; + } while ( true ); + + cpu = get_cpu_for_node(core); + + if ( cpu != invalid_topo_id ) + { + if ( !leaf ) + { + printk(XENLOG_ERR "ERROR: %pOF: Core has both threads and CPU\n", + core); + return -EINVAL; + } + + 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 = 0; + } + else if ( leaf ) + { + printk(XENLOG_ERR "ERROR: %pOF: Can't get CPU for leaf core\n", core); + return -EINVAL; + } + + return 0; +} + +static int __init parse_cluster(struct dt_device_node *cluster, + unsigned int package_id, + unsigned int cluster_id, + unsigned int depth) +{ + char name[20]; + bool leaf = true; + bool has_cores = false; + unsigned int core_id = 0; + unsigned int i; + int ret; + + /* + * First check for child clusters; we currently ignore any + * information about the nesting of clusters and present the + * scheduler with a flat list of them. + */ + i = 0; + do { + struct dt_device_node *c; + + snprintf(name, sizeof(name), "cluster%u", i); + c = dt_find_child_node_by_name(cluster, name); + + if ( !c ) + break; + + leaf = false; + ret = parse_cluster(c, package_id, i, depth + 1); + if ( depth > 0 ) + printk(XENLOG_WARNING + "WARNING: Topology for clusters of clusters not yet supported\n"); + if ( ret != 0 ) + return ret; + i++; + } while ( true ); + + /* Now check for cores */ + i = 0; + do { + struct dt_device_node *c; + + snprintf(name, sizeof(name), "core%u", i); + c = dt_find_child_node_by_name(cluster, name); + + if ( !c ) + break; + + has_cores = true; + + if ( depth == 0 ) + { + printk(XENLOG_ERR + "ERROR: %pOF: cpu-map children should be clusters\n", c); + return -EINVAL; + } + + if ( leaf ) + { + ret = parse_core(c, package_id, cluster_id, core_id++); + if ( ret != 0 ) + return ret; + } + else + { + printk(XENLOG_ERR "ERROR: %pOF: Non-leaf cluster with core %s\n", + cluster, name); + return -EINVAL; + } + + i++; + } while ( true ); + + if ( leaf && !has_cores ) + printk(XENLOG_WARNING "WARNING: %pOF: empty cluster\n", cluster); + + return 0; +} + +static int __init parse_socket(struct dt_device_node *socket) +{ + char name[20]; + bool has_socket = false; + unsigned int package_id = 0; + int ret; + + do { + struct dt_device_node *c; + + snprintf(name, sizeof(name), "socket%u", package_id); + c = dt_find_child_node_by_name(socket, name); + + if ( !c ) + break; + + has_socket = true; + ret = parse_cluster(c, package_id, invalid_topo_id, 0); + if ( ret != 0 ) + return ret; + + package_id++; + } while ( true ); + + if ( !has_socket ) + ret = parse_cluster(socket, 0, invalid_topo_id, 0); + + return ret; +} + +/* + * Generate cpu topology information when cpu-map node doesn't exist. + * It assumes that the cpu doesn't have SMT and all CPUs on a NUMA + * node belong to the same socket. + */ +static void __init fixup_topology(void) +{ + unsigned int cpu; + unsigned int clid = 0; + unsigned int pkgid = 0; + + for_each_possible_cpu(cpu) + { + struct cpu_map *map = &cpu_map[cpu]; + + map->package_id = cpu_to_node(cpu); + if ( map->package_id != pkgid ) + { + pkgid = map->package_id; + clid = 0; + } + map->cluster_id = clid++; + map->core_id = 0; + map->thread_id = 0; + } +} + +int __init parse_dt_topology(void) +{ + struct dt_device_node *cpus; + struct dt_device_node *map; + + cpus = dt_find_node_by_path("/cpus"); + + if ( !cpus ) + { + printk(XENLOG_ERR "ERROR: No CPU information found in DT\n"); + return -EINVAL; + } + + map = dt_find_child_node_by_name(cpus, "cpu-map"); + if ( !map ) + return -ENOENT; + + return parse_socket(map); +} + +void __init dt_init_cpu_topology(void) +{ + unsigned int cpu; + + BUG_ON(!acpi_disabled); + BUG_ON(!cpu_topology); + + if ( parse_dt_topology() ) + fixup_topology(); + + for_each_possible_cpu(cpu) + setup_siblings_masks(cpu); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/acpi/Kconfig b/xen/drivers/acpi/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/acpi/Kconfig +++ b/xen/drivers/acpi/Kconfig @@ -XXX,XX +XXX,XX @@ config ACPI_LEGACY_TABLES_LOOKUP config ACPI_NUMA bool select NUMA + +config ACPI_CPU_TOPOLOGY + bool diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/acpi/Makefile +++ b/xen/drivers/acpi/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_PM_OP) += pm-op.o obj-$(CONFIG_X86) += hwregs.o obj-$(CONFIG_X86) += reboot.o + +obj-$(CONFIG_ACPI_CPU_TOPOLOGY) += topology.o diff --git a/xen/drivers/acpi/topology.c b/xen/drivers/acpi/topology.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/drivers/acpi/topology.c @@ -XXX,XX +XXX,XX @@ +/* 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> + +/* + * TODO: Populate the topology information by scanning the ACPI + * PPTT (Processor Properties Topology Table). + */ +void __init acpi_init_cpu_topology(void) +{ + unsigned int cpu; + + /* + * Generate temporary cpu topology information for now. + * It assumes that the cpu doesn't have SMT and all CPUs + * belong to the same socket. + */ + for_each_possible_cpu(cpu) + { + struct cpu_topology *topo = &cpu_topology[cpu]; + + cpumask_set_cpu(cpu, topo->thread_sibling); + cpumask_copy(topo->core_sibling, &cpu_possible_map); + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/acpi.h +++ b/xen/include/xen/acpi.h @@ -XXX,XX +XXX,XX @@ void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); void acpi_table_print_srat_entry (struct acpi_subtable_header *srat); +void acpi_init_cpu_topology(void); + /* the following four functions are architecture-dependent */ void acpi_numa_slit_init (struct acpi_table_slit *slit); void acpi_numa_processor_affinity_init(const struct acpi_srat_cpu_affinity *); diff --git a/xen/include/xen/cpu-topology.h b/xen/include/xen/cpu-topology.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/cpu-topology.h @@ -XXX,XX +XXX,XX @@ +/* 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; +}; + +#ifdef CONFIG_CPU_TOPOLOGY + +extern struct cpu_topology *cpu_topology; +void init_cpu_topology(void); + +#else /* CONFIG_CPU_TOPOLOGY */ + +#define cpu_topology ((struct cpu_topology *)NULL) +static inline void init_cpu_topology(void) {} + +#endif /* CONFIG_CPU_TOPOLOGY */ + +#endif /* XEN_CPU_TOPOLOGY_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/dt-cpu-topology.h b/xen/include/xen/dt-cpu-topology.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/dt-cpu-topology.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XEN_DT_CPU_TOPOLOGY_H +#define XEN_DT_CPU_TOPOLOGY_H + +#include <xen/device_tree.h> + +#ifdef CONFIG_DT_CPU_TOPOLOGY + +void map_cpuid_to_node(unsigned int cpuid, struct dt_device_node *cpu_node); +void dt_init_cpu_topology(void); + +#else /* CONFIG_DT_CPU_TOPOLOGY */ + +static inline void map_cpuid_to_node(unsigned int cpuid, + struct dt_device_node *cpu_node) {} + +#endif /* CONFIG_DT_CPU_TOPOLOGY */ + +#endif /* XEN_DT_CPU_TOPOLOGY_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- 2.43.0
Make CPU topology information available to the Xen scheduler. Additionally, ensure that this topology information is displayed when executing the 'xl info -n' command. Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp> --- xen/arch/arm/include/asm/processor.h | 4 -- xen/arch/arm/smpboot.c | 23 ++++++++---- xen/arch/ppc/include/asm/processor.h | 4 -- xen/arch/riscv/include/asm/processor.h | 4 -- xen/common/device-tree/cpu-topology.c | 51 ++++++++++++++++++++++++++ xen/common/sched/credit2.c | 3 ++ xen/common/sysctl.c | 1 + xen/drivers/acpi/topology.c | 3 ++ xen/include/xen/cpu-topology.h | 15 ++++++++ 9 files changed, 89 insertions(+), 19 deletions(-) diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/processor.h +++ b/xen/arch/arm/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ void show_stack(const struct cpu_user_regs *regs); #define cpu_relax() barrier() /* Could yield? */ -/* All a bit UP for the moment */ -#define cpu_to_core(_cpu) (0) -#define cpu_to_socket(_cpu) (0) - struct vcpu; void vcpu_regs_hyp_to_user(const struct vcpu *vcpu, struct vcpu_guest_core_regs *regs); diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -XXX,XX +XXX,XX @@ static int setup_cpu_sibling_map(int cpu) !zalloc_cpumask_var(&per_cpu(cpu_core_mask, cpu)) ) return -ENOMEM; - /* - * Currently we assume there is no multithread and NUMA, so - * a CPU is a sibling with itself, and the all possible CPUs - * are supposed to belong to the same socket (NUMA node). - */ - cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); - cpumask_copy(per_cpu(cpu_core_mask, cpu), &cpu_possible_map); + if ( cpu_topology ) + { + cpumask_copy(per_cpu(cpu_sibling_mask, cpu), + cpu_topology[cpu].thread_sibling); + cpumask_copy(per_cpu(cpu_core_mask, cpu), + cpu_topology[cpu].core_sibling); + } + else + { + /* + * If CONFIG_CPU_TOPOLOGY is disabled, it is assumed that + * all CPUs reside in the same socket and that SMT is not used. + */ + cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); + cpumask_copy(per_cpu(cpu_core_mask, cpu), &cpu_possible_map); + } return 0; } diff --git a/xen/arch/ppc/include/asm/processor.h b/xen/arch/ppc/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/ppc/include/asm/processor.h +++ b/xen/arch/ppc/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ /* Macro to adjust thread priority for hardware multithreading */ #define HMT_very_low() asm volatile ( "or %r31, %r31, %r31" ) -/* TODO: This isn't correct */ -#define cpu_to_core(cpu) (0) -#define cpu_to_socket(cpu) (0) - /* * User-accessible registers: most of these need to be saved/restored * for every nested Xen invocation. diff --git a/xen/arch/riscv/include/asm/processor.h b/xen/arch/riscv/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/include/asm/processor.h +++ b/xen/arch/riscv/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ struct cpu_user_regs unsigned long pregs; }; -/* TODO: need to implement */ -#define cpu_to_core(cpu) 0 -#define cpu_to_socket(cpu) 0 - static inline void cpu_relax(void) { #ifdef __riscv_zihintpause diff --git a/xen/common/device-tree/cpu-topology.c b/xen/common/device-tree/cpu-topology.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/device-tree/cpu-topology.c +++ b/xen/common/device-tree/cpu-topology.c @@ -XXX,XX +XXX,XX @@ int __init parse_dt_topology(void) return parse_socket(map); } +static void __init setup_cpu_topology_ids(void) +{ + unsigned int cpu; + unsigned int next_core_id = 0; + unsigned int next_cluster_id = 0; + unsigned int next_socket_id = 0; + + for_each_possible_cpu(cpu) + { + unsigned int first_cpu; + struct cpu_topology *topo = &cpu_topology[cpu]; + + first_cpu = cpumask_first(topo->thread_sibling); + if ( first_cpu == cpu ) + { + topo->phys_core_id = next_core_id; + next_core_id++; + } + else + topo->phys_core_id = cpu_topology[first_cpu].phys_core_id; + + /* Reuse the calculated core id if clustering is not supported */ + if ( cpumask_empty(topo->cluster_sibling) ) + topo->phys_cluster_id = topo->phys_core_id; + else + { + first_cpu = cpumask_first(topo->cluster_sibling); + if ( first_cpu == cpu ) + { + topo->phys_cluster_id = next_cluster_id; + next_cluster_id++; + } + else + topo->phys_cluster_id = cpu_topology[first_cpu].phys_cluster_id; + } + + first_cpu = cpumask_first(topo->core_sibling); + if ( first_cpu == cpu ) + { + topo->phys_socket_id = next_socket_id; + next_socket_id++; + } + else + topo->phys_socket_id = cpu_topology[first_cpu].phys_socket_id; + + topo->num_siblings = cpumask_weight(topo->thread_sibling); + } +} + void __init dt_init_cpu_topology(void) { unsigned int cpu; @@ -XXX,XX +XXX,XX @@ void __init dt_init_cpu_topology(void) for_each_possible_cpu(cpu) setup_siblings_masks(cpu); + + setup_cpu_topology_ids(); } /* diff --git a/xen/common/sched/credit2.c b/xen/common/sched/credit2.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/sched/credit2.c +++ b/xen/common/sched/credit2.c @@ -XXX,XX +XXX,XX @@ * Based on an earlier verson by Emmanuel Ackaouy. */ +#include <xen/cpu-topology.h> #include <xen/errno.h> #include <xen/init.h> #include <xen/lib.h> @@ -XXX,XX +XXX,XX @@ static unsigned int cpu_nr_siblings(unsigned int cpu) { #ifdef CONFIG_X86 return cpu_data[cpu].x86_num_siblings; +#elif defined(CONFIG_CPU_TOPOLOGY) + return cpu_topology ? cpu_topology[cpu].num_siblings : 1; #else return 1; #endif diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -XXX,XX +XXX,XX @@ #include <xen/pmstat.h> #include <xen/livepatch.h> #include <xen/coverage.h> +#include <xen/cpu-topology.h> long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl) { diff --git a/xen/drivers/acpi/topology.c b/xen/drivers/acpi/topology.c index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/acpi/topology.c +++ b/xen/drivers/acpi/topology.c @@ -XXX,XX +XXX,XX @@ void __init acpi_init_cpu_topology(void) { struct cpu_topology *topo = &cpu_topology[cpu]; + topo->phys_core_id = cpu; + topo->num_siblings = 1; + cpumask_set_cpu(cpu, topo->thread_sibling); cpumask_copy(topo->core_sibling, &cpu_possible_map); } diff --git a/xen/include/xen/cpu-topology.h b/xen/include/xen/cpu-topology.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/cpu-topology.h +++ b/xen/include/xen/cpu-topology.h @@ -XXX,XX +XXX,XX @@ struct cpu_topology { cpumask_var_t thread_sibling; cpumask_var_t core_sibling; cpumask_var_t cluster_sibling; + unsigned int phys_core_id; + unsigned int phys_cluster_id; + unsigned int phys_socket_id; + unsigned int num_siblings; }; #ifdef CONFIG_CPU_TOPOLOGY @@ -XXX,XX +XXX,XX @@ struct cpu_topology { extern struct cpu_topology *cpu_topology; void init_cpu_topology(void); +#define cpu_to_core(cpu) (cpu_topology ? cpu_topology[cpu].phys_core_id : 0) +#define cpu_to_socket(cpu) (cpu_topology ? cpu_topology[cpu].phys_socket_id : 0) + #else /* CONFIG_CPU_TOPOLOGY */ #define cpu_topology ((struct cpu_topology *)NULL) static inline void init_cpu_topology(void) {} +#ifndef cpu_to_core +#define cpu_to_core(cpu) (0) +#endif + +#ifndef cpu_to_socket +#define cpu_to_socket(cpu) (0) +#endif + #endif /* CONFIG_CPU_TOPOLOGY */ #endif /* XEN_CPU_TOPOLOGY_H */ -- 2.43.0
Make cpu_nr_siblings() an architecture-specific function. This patch provides the implementation for x86 and a common version for Device Tree-based architectures. Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp> --- xen/arch/x86/include/asm/processor.h | 1 + xen/common/sched/credit2.c | 22 +++------------------- xen/include/xen/cpu-topology.h | 5 +++++ 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/processor.h +++ b/xen/arch/x86/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ extern void intel_init_arat(void); #define cpu_to_core(_cpu) (cpu_data[_cpu].cpu_core_id) #define cpu_to_socket(_cpu) (cpu_data[_cpu].phys_proc_id) +#define cpu_nr_siblings(_cpu) (cpu_data[_cpu].x86_num_siblings) unsigned int apicid_to_socket(unsigned int apicid); diff --git a/xen/common/sched/credit2.c b/xen/common/sched/credit2.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/sched/credit2.c +++ b/xen/common/sched/credit2.c @@ -XXX,XX +XXX,XX @@ /* #define d2printk printk */ #define d2printk(x...) -/* - * TODO: Abstract this properly, and figure out what Credit2 wants to do with - * the fact that x86_num_siblings doesn't even have the same meaning - * between x86 vendors. - */ -static unsigned int cpu_nr_siblings(unsigned int cpu) -{ -#ifdef CONFIG_X86 - return cpu_data[cpu].x86_num_siblings; -#elif defined(CONFIG_CPU_TOPOLOGY) - return cpu_topology ? cpu_topology[cpu].num_siblings : 1; -#else - return 1; -#endif -} - /* * Credit2 tracing events ("only" 512 available!). Check * include/public/trace.h for more details. @@ -XXX,XX +XXX,XX @@ cpu_runqueue_match(const struct csched2_runqueue_data *rqd, unsigned int cpu) /* * Additional checks, to avoid separating siblings in different runqueues. - * This deals with both Intel's HTs and AMD's CUs. An arch that does not have - * any similar concept will just have cpu_nr_siblings() always return 1, and - * setup the cpu_sibling_mask-s acordingly (as currently does ARM), and things + * This deals with Intel's HTs, AMD's CUs and ARM's SMT. An arch that + * does not have similar concept will just have cpu_nr_siblings() always + * return 1, and setup the cpu_sibling_mask-s accordingly, and things * will just work as well. */ static bool diff --git a/xen/include/xen/cpu-topology.h b/xen/include/xen/cpu-topology.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/cpu-topology.h +++ b/xen/include/xen/cpu-topology.h @@ -XXX,XX +XXX,XX @@ void init_cpu_topology(void); #define cpu_to_core(cpu) (cpu_topology ? cpu_topology[cpu].phys_core_id : 0) #define cpu_to_socket(cpu) (cpu_topology ? cpu_topology[cpu].phys_socket_id : 0) +#define cpu_nr_siblings(cpu) (cpu_topology ? cpu_topology[cpu].num_siblings : 1) #else /* CONFIG_CPU_TOPOLOGY */ @@ -XXX,XX +XXX,XX @@ static inline void init_cpu_topology(void) {} #define cpu_to_socket(cpu) (0) #endif +#ifndef cpu_nr_siblings +#define cpu_nr_siblings(cpu) (1) +#endif + #endif /* CONFIG_CPU_TOPOLOGY */ #endif /* XEN_CPU_TOPOLOGY_H */ -- 2.43.0
Hello, This patch series introduces Device-Tree based CPU topology support for ARM Xen. This version incorporates the feedback received from Jan on the v3 submission. The main focus of this update includes transitioning towards a generic Kconfig structure, untangling header dependencies and various code cleanups. Future Work: - Support for the "credit2_runqueue=cluster" option. - CPU topology support for RISC-V and PPC (once SMP support is available). - Topology information generation from the ACPI PPTT. Changes in v4: - Only display the CPU topology configuration prompt in common/Kconfig if the architecture defines HAS_GENERIC_CPU_TOPOLOGY. - Move the definition of the global 'cpu_topology' pointer to common/cpu-topology.c. - Update the Makefile to explicitly build objects as .init.o when all functions and data within a file are annotated with __init/__initdata, ensuring their memory is reclaimed after system initialization. - Add an error log in the CPU-to-node mapping function for out-of-bounds cases. - Use ARRAY_SIZE() instead of raw macros when guarding array accesses. - Rename variables and functions to avoid ambiguous or misleading terms: - Avoid 'cpuid' to prevent confusion with x86 CPUID features/instructions. - Avoid 'node' where it could be confused with a NUMA node, explicitly renaming them to clarify they refer to a Device Tree node. - Move local variable declarations into the narrowest possible scope. - Replace the unsupported "%pOF" printk format specifier with "%s" and explicit node name retrieval. - Remove #include <dt-cpu-topology.h> from cpu-topology.h, and ensure the header directly includes only what its definitions require. - Remove #include <xen/device_tree.h> from dt-cpu-topology.h, replacing it with a forward declaration of 'struct dt_device_node'. - Use 'const' qualifiers for pointer declarations where the pointed-to structure is not modified. - Explicitly #include <asm/processor.h> in cpu-topology.h to guarantee that arch-specific definitions of cpu_to_core() and cpu_to_socket() take precedence over the generic fallbacks. - Introduce inline initialization functions for cpu_sibling_mask and cpu_core_mask in cpu-topology.h, providing separate variants for both when CONFIG_GENERIC_CPU_TOPOLOGY is enabled and disabled. Changes in v3: - Use (nr_cpu_ids - 1) as the maximum CPU ID here. The fix for the sparse map mismatch issue on ARM Xen has been split out into a separate patch. - Switch topology sibling masks to cpumask_var_t for dynamic allocation. - Allow the system to keep running with a degraded fallback even if the topology table allocation fails. - Remove the temporary definitions of cpu_to_core() and cpu_to_socket() from RISC-V and PPC processor.h. - Minimize the use of #ifdef blocks, leveraging compiler Dead Code Elimination (DCE) where possible. - Clean up the code to follow the Xen coding style. Please let me know if I missed any style nits! - Verify successful builds across x86, RISC-V, and PPC environments. Changes in v2: - Generate topology information even when ACPI is enabled. Note that this is a temporary implementation and doesn't yet parse the PPTT (Processor Properties Topology Table). - Added support for cpu-map node in Device Tree that doesn't contain explicit cluster node definitions. Changes in v1 from the previous series "Introduce Device Tree based NUMA support for ARM Xen": 1. Optimized Memory Allocation: The series now allocates only the minimum required memory area to manage the essential data for the CPUs. 2. Flexible Device Tree Parsing: The parsing logic no longer depends on the definition order of the 'cpu' nodes and 'cpu-map' nodes in the Device Tree. They can now be read correctly even if their orders do not match. 3. CPU Hotplug Readiness: To support future CPU hotplug, the system assumes that inactive CPUs are also described in the Device Tree. Xen will pre-load and generate the topology information for these inactive CPUs during the boot phase so it stays available in memory. Thank you, Hirokazu Takahashi Hirokazu Takahashi (3): xen/device-tree: Parse 'cpu-map' node for CPU topology exploration xen/sched: Link CPU topology to scheduler xen/sched: Make cpu_nr_siblings() architecture-specific xen/arch/arm/Kconfig | 1 + xen/arch/arm/include/asm/processor.h | 4 - xen/arch/arm/smpboot.c | 15 +- xen/arch/ppc/include/asm/processor.h | 4 - xen/arch/riscv/include/asm/processor.h | 4 - xen/arch/x86/include/asm/processor.h | 1 + xen/common/Kconfig | 18 ++ xen/common/Makefile | 1 + xen/common/cpu-topology.c | 62 ++++ xen/common/device-tree/Makefile | 1 + xen/common/device-tree/cpu-topology.c | 406 +++++++++++++++++++++++++ xen/common/sched/credit2.c | 21 +- xen/common/sysctl.c | 1 + xen/drivers/acpi/Kconfig | 3 + xen/drivers/acpi/Makefile | 1 + xen/drivers/acpi/topology.c | 41 +++ xen/include/xen/acpi.h | 2 + xen/include/xen/cpu-topology.h | 83 +++++ xen/include/xen/dt-cpu-topology.h | 29 ++ 19 files changed, 662 insertions(+), 36 deletions(-) create mode 100644 xen/common/cpu-topology.c create mode 100644 xen/common/device-tree/cpu-topology.c create mode 100644 xen/drivers/acpi/topology.c create mode 100644 xen/include/xen/cpu-topology.h create mode 100644 xen/include/xen/dt-cpu-topology.h -- 2.43.0
Parse the 'cpu-map' node in the Device Tree to extract CPU topology information. If the 'cpu-map' node is absent, fall back to generating the topology data from the NUMA information. This generation assumes exactly one socket per NUMA node and that SMT is unsupported. Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp> --- Changes in v4: - Only display the CPU topology configuration prompt in common/Kconfig if the architecture defines HAS_GENERIC_CPU_TOPOLOGY. - Move the definition of the global 'cpu_topology' pointer to common/cpu-topology.c. - Update the Makefile to explicitly build objects as .init.o when all functions and data within a file are annotated with __init/__initdata, ensuring their memory is reclaimed after system initialization. - Add an error log in the CPU-to-node mapping function for out-of-bounds cases. - Use ARRAY_SIZE() instead of raw macros when guarding array accesses. - Rename variables and functions to avoid ambiguous or misleading terms: - Avoid 'cpuid' to prevent confusion with x86 CPUID features/instructions. - Avoid 'node' where it could be confused with a NUMA node, explicitly renaming them to clarify they refer to a Device Tree node. - Move local variable declarations into the narrowest possible scope. - Replace the unsupported "%pOF" printk format specifier with "%s" and explicit node name retrieval. - Remove #include <dt-cpu-topology.h> from cpu-topology.h, and ensure the header directly includes only what its definitions require. - Remove #include <xen/device_tree.h> from dt-cpu-topology.h, replacing it with a forward declaration of 'struct dt_device_node'. - Use 'const' qualifiers for pointer declarations where the pointed-to structure is not modified. Changes in v3: - Use (nr_cpu_ids - 1) as the maximum CPU ID here. The fix for the sparse map mismatch issue on ARM Xen has been split out into a separate patch. - Switch topology sibling masks to cpumask_var_t for dynamic allocation. - Allow the system to keep running with a degraded fallback even if the topology table allocation fails. - Clean up the code to follow the Xen coding style. Please let me know if I missed any style nits! - Verify successful builds across x86, RISC-V, and PPC environments. Changes in v2: - Generate topology information even when ACPI is enabled. Note that this is a temporary implementation and doesn't yet parse the PPTT (Processor Properties Topology Table). - Added support for cpu-map node in Device Tree that doesn't contain explicit cluster node definitions. xen/arch/arm/Kconfig | 1 + xen/arch/arm/smpboot.c | 7 + xen/common/Kconfig | 18 ++ xen/common/Makefile | 1 + xen/common/cpu-topology.c | 62 +++++ xen/common/device-tree/Makefile | 1 + xen/common/device-tree/cpu-topology.c | 355 ++++++++++++++++++++++++++ xen/drivers/acpi/Kconfig | 3 + xen/drivers/acpi/Makefile | 1 + xen/drivers/acpi/topology.c | 38 +++ xen/include/xen/acpi.h | 2 + xen/include/xen/cpu-topology.h | 35 +++ xen/include/xen/dt-cpu-topology.h | 29 +++ 13 files changed, 553 insertions(+) create mode 100644 xen/common/cpu-topology.c create mode 100644 xen/common/device-tree/cpu-topology.c create mode 100644 xen/drivers/acpi/topology.c create mode 100644 xen/include/xen/cpu-topology.h create mode 100644 xen/include/xen/dt-cpu-topology.h diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config ARM select HAS_GRANT_CACHE_FLUSH if GRANT_TABLE select HAS_STACK_PROTECTOR select HAS_UBSAN + select HAS_GENERIC_CPU_TOPOLOGY config ARCH_DEFCONFIG string diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -XXX,XX +XXX,XX @@ #include <xen/acpi.h> #include <xen/cpu.h> +#include <xen/cpu-topology.h> #include <xen/cpumask.h> #include <xen/delay.h> #include <xen/device_tree.h> #include <xen/domain_page.h> +#include <xen/dt-cpu-topology.h> #include <xen/errno.h> #include <xen/init.h> #include <xen/mm.h> @@ -XXX,XX +XXX,XX @@ static void __init dt_smp_init_cpus(void) } else tmp_map[i] = hwid; + + /* Pass the info to dt_init_cpu_topology() */ + map_cpu_to_dt_node(i, cpu); } if ( !bootcpu_valid ) @@ -XXX,XX +XXX,XX @@ void __init smp_init_cpus(void) else acpi_smp_init_cpus(); + init_cpu_topology(); + if ( opt_hmp_unsafe ) warning_add("WARNING: HMP COMPUTING HAS BEEN ENABLED.\n" "It has implications on the security and stability of the system,\n" diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config VM_EVENT config NEEDS_LIBELF bool +config HAS_GENERIC_CPU_TOPOLOGY + bool + +config DT_CPU_TOPOLOGY + bool + +config GENERIC_CPU_TOPOLOGY + bool "CPU topology support (UNSUPPORTED)" if UNSUPPORTED + depends on HAS_GENERIC_CPU_TOPOLOGY + select DT_CPU_TOPOLOGY if DEVICE_TREE_PARSE + select ACPI_CPU_TOPOLOGY if ACPI + 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. + config NUMA bool diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ 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_GENERIC_CPU_TOPOLOGY) += cpu-topology.o obj-$(CONFIG_DEBUG_TRACE) += debugtrace.o obj-$(CONFIG_HAS_DEVICE_TREE_DISCOVERY) += device.o obj-$(filter-out $(CONFIG_X86),$(CONFIG_ACPI)) += device.o diff --git a/xen/common/cpu-topology.c b/xen/common/cpu-topology.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/cpu-topology.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <xen/acpi.h> +#include <xen/cpu-topology.h> +#include <xen/cpumask.h> +#include <xen/dt-cpu-topology.h> +#include <xen/init.h> + +struct cpu_topology *__ro_after_init cpu_topology; + +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: + */ diff --git a/xen/common/device-tree/Makefile b/xen/common/device-tree/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/device-tree/Makefile +++ b/xen/common/device-tree/Makefile @@ -XXX,XX +XXX,XX @@ 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.init.o obj-y += device-tree.o obj-$(CONFIG_DOMAIN_BUILD_HELPERS) += domain-build.init.o obj-$(filter $(CONFIG_DOM0LESS_BOOT),$(CONFIG_HAS_DEVICE_TREE_DISCOVERY)) += dom0less-build.init.o diff --git a/xen/common/device-tree/cpu-topology.c b/xen/common/device-tree/cpu-topology.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/device-tree/cpu-topology.c @@ -XXX,XX +XXX,XX @@ +/* 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> + +struct cpu_map { + unsigned int thread_id; + unsigned int core_id; + unsigned int cluster_id; + unsigned int package_id; +}; + +static const unsigned int __initdata invalid_topo_id = ~0U; +static struct cpu_map __initdata cpu_map[NR_CPUS] = { + [0 ... NR_CPUS - 1] = {invalid_topo_id, invalid_topo_id, invalid_topo_id, 0} +}; +static struct dt_device_node *__initdata dt_cpu_table[NR_CPUS]; + +static void __init setup_siblings_masks(unsigned int target_cpu) +{ + const struct cpu_topology *target_topo = &cpu_topology[target_cpu]; + const struct cpu_map *target_map = &cpu_map[target_cpu]; + unsigned int cpu; + + /* Update core and thread sibling masks */ + for_each_possible_cpu(cpu) + { + const struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + const struct cpu_map *map = &cpu_map[cpu]; + + if ( target_map->package_id != map->package_id ) + continue; + + cpumask_set_cpu(target_cpu, cpu_topo->core_sibling); + cpumask_set_cpu(cpu, target_topo->core_sibling); + + if ( target_map->cluster_id != map->cluster_id ) + continue; + + if ( target_map->cluster_id != invalid_topo_id ) + { + cpumask_set_cpu(target_cpu, cpu_topo->cluster_sibling); + cpumask_set_cpu(cpu, target_topo->cluster_sibling); + } + + if ( target_map->core_id != map->core_id ) + continue; + + cpumask_set_cpu(target_cpu, cpu_topo->thread_sibling); + cpumask_set_cpu(cpu, target_topo->thread_sibling); + } +} + +static struct dt_device_node *__init + dt_find_child_node_by_name(const struct dt_device_node *dt, + const char *name) +{ + struct dt_device_node *np; + + dt_for_each_child_node(dt, np) + if ( np->name && (dt_node_cmp(np->name, name) == 0) ) + break; + + return np; +} + +void __init map_cpu_to_dt_node(unsigned int cpu, + struct dt_device_node *cpu_node) +{ + if ( cpu < ARRAY_SIZE(dt_cpu_table) ) + dt_cpu_table[cpu] = cpu_node; + else + printk(XENLOG_WARNING + "cpu id %u exceeds the max cores %lu\n", + cpu, ARRAY_SIZE(dt_cpu_table)); +} + +static unsigned int __init cpu_node_to_id(const struct dt_device_node *cpu_node) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) + if ( cpu_node == dt_cpu_table[cpu] ) + return cpu; + + return invalid_topo_id; +} + +/* + * This function returns the logical cpu number of the DT node. + */ +static unsigned int __init + get_cpu_for_node(const struct dt_device_node *dt_node) +{ + const struct dt_device_node *cpu_node = dt_parse_phandle(dt_node, "cpu", 0); + + if ( !cpu_node ) + return invalid_topo_id; + + return cpu_node_to_id(cpu_node); +} + +static int __init parse_core(const struct dt_device_node *core, + unsigned int package_id, + unsigned int cluster_id, + unsigned int core_id) +{ + bool leaf = true; + unsigned int i = 0; + unsigned int cpu; + + do { + const struct dt_device_node *t; + char name[20]; + + 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: %s: Can't get CPU for thread\n", dt_node_name(t)); + return -EINVAL; + } + i++; + } while ( true ); + + cpu = get_cpu_for_node(core); + + if ( cpu != invalid_topo_id ) + { + if ( !leaf ) + { + printk(XENLOG_ERR "ERROR: %s: Core has both threads and CPU\n", + dt_node_name(core)); + return -EINVAL; + } + + 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 = 0; + } + else if ( leaf ) + { + printk(XENLOG_ERR + "ERROR: %s: Can't get CPU for leaf core\n", dt_node_name(core)); + return -EINVAL; + } + + return 0; +} + +static int __init parse_cluster(const struct dt_device_node *cluster, + unsigned int package_id, + unsigned int cluster_id, + unsigned int depth) +{ + bool leaf = true; + bool has_cores = false; + unsigned int core_id = 0; + unsigned int i = 0; + + /* + * First check for child clusters; we currently ignore any + * information about the nesting of clusters and present the + * scheduler with a flat list of them. + */ + do { + const struct dt_device_node *c; + char name[20]; + int ret; + + snprintf(name, sizeof(name), "cluster%u", i); + c = dt_find_child_node_by_name(cluster, name); + + if ( !c ) + break; + + leaf = false; + ret = parse_cluster(c, package_id, i, depth + 1); + if ( depth > 0 ) + printk(XENLOG_WARNING + "WARNING: Topology for clusters of clusters not yet supported\n"); + if ( ret != 0 ) + return ret; + i++; + } while ( true ); + + /* Now check for cores */ + i = 0; + do { + const struct dt_device_node *c; + char name[20]; + int ret; + + snprintf(name, sizeof(name), "core%u", i); + c = dt_find_child_node_by_name(cluster, name); + + if ( !c ) + break; + + has_cores = true; + + if ( depth == 0 ) + { + printk(XENLOG_ERR + "ERROR: %s: cpu-map children should be clusters\n", + dt_node_name(c)); + return -EINVAL; + } + + if ( leaf ) + { + ret = parse_core(c, package_id, cluster_id, core_id++); + if ( ret != 0 ) + return ret; + } + else + { + printk(XENLOG_ERR "ERROR: %s: Non-leaf cluster with core %s\n", + dt_node_name(cluster), name); + return -EINVAL; + } + + i++; + } while ( true ); + + if ( leaf && !has_cores ) + printk(XENLOG_WARNING "WARNING: %s: empty cluster\n", + dt_node_name(cluster)); + + return 0; +} + +static int __init parse_socket(const struct dt_device_node *socket) +{ + bool has_socket = false; + unsigned int package_id = 0; + int ret; + + do { + const struct dt_device_node *c; + char name[20]; + + snprintf(name, sizeof(name), "socket%u", package_id); + c = dt_find_child_node_by_name(socket, name); + + if ( !c ) + break; + + has_socket = true; + ret = parse_cluster(c, package_id, invalid_topo_id, 0); + if ( ret != 0 ) + return ret; + + package_id++; + } while ( true ); + + if ( !has_socket ) + ret = parse_cluster(socket, 0, invalid_topo_id, 0); + + return ret; +} + +/* + * Generate cpu topology information when cpu-map node doesn't exist. + * It assumes that the cpu doesn't have SMT and all CPUs on a NUMA + * node belong to the same socket. + */ +static void __init fixup_topology(void) +{ + unsigned int cpu; + unsigned int clid = 0; + unsigned int pkgid = 0; + + for_each_possible_cpu(cpu) + { + struct cpu_map *map = &cpu_map[cpu]; + + map->package_id = cpu_to_node(cpu); + if ( map->package_id != pkgid ) + { + pkgid = map->package_id; + clid = 0; + } + map->cluster_id = clid++; + map->core_id = 0; + map->thread_id = 0; + } +} + +int __init parse_dt_topology(void) +{ + const struct dt_device_node *cpus; + const struct dt_device_node *map; + + cpus = dt_find_node_by_path("/cpus"); + if ( !cpus ) + { + printk(XENLOG_ERR "ERROR: No CPU information found in DT\n"); + return -EINVAL; + } + + map = dt_find_child_node_by_name(cpus, "cpu-map"); + if ( !map ) + return -ENOENT; + + return parse_socket(map); +} + +void __init dt_init_cpu_topology(void) +{ + unsigned int cpu; + + BUG_ON(!acpi_disabled); + BUG_ON(!cpu_topology); + + if ( parse_dt_topology() ) + fixup_topology(); + + for_each_possible_cpu(cpu) + setup_siblings_masks(cpu); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/acpi/Kconfig b/xen/drivers/acpi/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/acpi/Kconfig +++ b/xen/drivers/acpi/Kconfig @@ -XXX,XX +XXX,XX @@ config ACPI_LEGACY_TABLES_LOOKUP config ACPI_NUMA bool select NUMA + +config ACPI_CPU_TOPOLOGY + bool diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/acpi/Makefile +++ b/xen/drivers/acpi/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_PM_OP) += pm-op.o obj-$(CONFIG_X86) += hwregs.o obj-$(CONFIG_X86) += reboot.o +obj-$(CONFIG_ACPI_CPU_TOPOLOGY) += topology.init.o diff --git a/xen/drivers/acpi/topology.c b/xen/drivers/acpi/topology.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/drivers/acpi/topology.c @@ -XXX,XX +XXX,XX @@ +/* 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> + +/* + * TODO: Populate the topology information by scanning the ACPI + * PPTT (Processor Properties Topology Table). + */ +void __init acpi_init_cpu_topology(void) +{ + unsigned int cpu; + + /* + * Generate temporary cpu topology information for now. + * It assumes that the cpu doesn't have SMT and all CPUs + * belong to the same socket. + */ + for_each_possible_cpu(cpu) + { + struct cpu_topology *topo = &cpu_topology[cpu]; + + cpumask_set_cpu(cpu, topo->thread_sibling); + cpumask_copy(topo->core_sibling, &cpu_possible_map); + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/acpi.h +++ b/xen/include/xen/acpi.h @@ -XXX,XX +XXX,XX @@ void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); void acpi_table_print_srat_entry (struct acpi_subtable_header *srat); +void acpi_init_cpu_topology(void); + /* the following four functions are architecture-dependent */ void acpi_numa_slit_init (struct acpi_table_slit *slit); void acpi_numa_processor_affinity_init(const struct acpi_srat_cpu_affinity *); diff --git a/xen/include/xen/cpu-topology.h b/xen/include/xen/cpu-topology.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/cpu-topology.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XEN_CPU_TOPOLOGY_H +#define XEN_CPU_TOPOLOGY_H + +#include <xen/cpumask.h> + +#ifdef CONFIG_GENERIC_CPU_TOPOLOGY + +struct cpu_topology { + cpumask_var_t thread_sibling; + cpumask_var_t core_sibling; + cpumask_var_t cluster_sibling; +}; + +extern struct cpu_topology *cpu_topology; +void init_cpu_topology(void); + +#else /* CONFIG_GENERIC_CPU_TOPOLOGY */ + +#define cpu_topology ((struct cpu_topology *)NULL) +static inline void init_cpu_topology(void) {} + +#endif /* CONFIG_GENERIC_CPU_TOPOLOGY */ + +#endif /* XEN_CPU_TOPOLOGY_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/dt-cpu-topology.h b/xen/include/xen/dt-cpu-topology.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/dt-cpu-topology.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XEN_DT_CPU_TOPOLOGY_H +#define XEN_DT_CPU_TOPOLOGY_H + +struct dt_device_node; + +#ifdef CONFIG_DT_CPU_TOPOLOGY + +void map_cpu_to_dt_node(unsigned int cpu, struct dt_device_node *cpu_node); +void dt_init_cpu_topology(void); + +#else /* CONFIG_DT_CPU_TOPOLOGY */ + +static inline void map_cpu_to_dt_node(unsigned int cpu, + struct dt_device_node *cpu_node) {} + +#endif /* CONFIG_DT_CPU_TOPOLOGY */ + +#endif /* XEN_DT_CPU_TOPOLOGY_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- 2.43.0
Make CPU topology information available to the Xen scheduler. Additionally, ensure that this topology information is displayed when executing the 'xl info -n' command. Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp> --- Changes in v4 - Explicitly #include <asm/processor.h> in cpu-topology.h to guarantee that arch-specific definitions of cpu_to_core() and cpu_to_socket() take precedence over the generic fallbacks. - Introduce inline initialization functions for cpu_sibling_mask and cpu_core_mask in cpu-topology.h, providing separate variants for both when CONFIG_GENERIC_CPU_TOPOLOGY is enabled and disabled. Changes in v3 - Remove the temporary definitions of cpu_to_core() and cpu_to_socket() from RISC-V and PPC processor.h. - Minimize the use of #ifdef blocks, leveraging compiler Dead Code Elimination (DCE) where possible. xen/arch/arm/include/asm/processor.h | 4 -- xen/arch/arm/smpboot.c | 8 +--- xen/arch/ppc/include/asm/processor.h | 4 -- xen/arch/riscv/include/asm/processor.h | 4 -- xen/common/device-tree/cpu-topology.c | 51 ++++++++++++++++++++++++++ xen/common/sched/credit2.c | 3 ++ xen/common/sysctl.c | 1 + xen/drivers/acpi/topology.c | 3 ++ xen/include/xen/cpu-topology.h | 45 ++++++++++++++++++++++- 9 files changed, 103 insertions(+), 20 deletions(-) diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/processor.h +++ b/xen/arch/arm/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ void show_stack(const struct cpu_user_regs *regs); #define cpu_relax() barrier() /* Could yield? */ -/* All a bit UP for the moment */ -#define cpu_to_core(_cpu) (0) -#define cpu_to_socket(_cpu) (0) - struct vcpu; void vcpu_regs_hyp_to_user(const struct vcpu *vcpu, struct vcpu_guest_core_regs *regs); diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/smpboot.c +++ b/xen/arch/arm/smpboot.c @@ -XXX,XX +XXX,XX @@ static int setup_cpu_sibling_map(int cpu) !zalloc_cpumask_var(&per_cpu(cpu_core_mask, cpu)) ) return -ENOMEM; - /* - * Currently we assume there is no multithread and NUMA, so - * a CPU is a sibling with itself, and the all possible CPUs - * are supposed to belong to the same socket (NUMA node). - */ - cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); - cpumask_copy(per_cpu(cpu_core_mask, cpu), &cpu_possible_map); + init_cpu_sibling_map(cpu); return 0; } diff --git a/xen/arch/ppc/include/asm/processor.h b/xen/arch/ppc/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/ppc/include/asm/processor.h +++ b/xen/arch/ppc/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ /* Macro to adjust thread priority for hardware multithreading */ #define HMT_very_low() asm volatile ( "or %r31, %r31, %r31" ) -/* TODO: This isn't correct */ -#define cpu_to_core(cpu) (0) -#define cpu_to_socket(cpu) (0) - /* * User-accessible registers: most of these need to be saved/restored * for every nested Xen invocation. diff --git a/xen/arch/riscv/include/asm/processor.h b/xen/arch/riscv/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/include/asm/processor.h +++ b/xen/arch/riscv/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ struct cpu_user_regs unsigned long pregs; }; -/* TODO: need to implement */ -#define cpu_to_core(cpu) 0 -#define cpu_to_socket(cpu) 0 - static inline void cpu_relax(void) { #ifdef __riscv_zihintpause diff --git a/xen/common/device-tree/cpu-topology.c b/xen/common/device-tree/cpu-topology.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/device-tree/cpu-topology.c +++ b/xen/common/device-tree/cpu-topology.c @@ -XXX,XX +XXX,XX @@ int __init parse_dt_topology(void) return parse_socket(map); } +static void __init setup_cpu_topology_ids(void) +{ + unsigned int cpu; + unsigned int next_core_id = 0; + unsigned int next_cluster_id = 0; + unsigned int next_socket_id = 0; + + for_each_possible_cpu(cpu) + { + unsigned int first_cpu; + struct cpu_topology *topo = &cpu_topology[cpu]; + + first_cpu = cpumask_first(topo->thread_sibling); + if ( first_cpu == cpu ) + { + topo->phys_core_id = next_core_id; + next_core_id++; + } + else + topo->phys_core_id = cpu_topology[first_cpu].phys_core_id; + + /* Reuse the calculated core id if clustering is not supported */ + if ( cpumask_empty(topo->cluster_sibling) ) + topo->phys_cluster_id = topo->phys_core_id; + else + { + first_cpu = cpumask_first(topo->cluster_sibling); + if ( first_cpu == cpu ) + { + topo->phys_cluster_id = next_cluster_id; + next_cluster_id++; + } + else + topo->phys_cluster_id = cpu_topology[first_cpu].phys_cluster_id; + } + + first_cpu = cpumask_first(topo->core_sibling); + if ( first_cpu == cpu ) + { + topo->phys_socket_id = next_socket_id; + next_socket_id++; + } + else + topo->phys_socket_id = cpu_topology[first_cpu].phys_socket_id; + + topo->num_siblings = cpumask_weight(topo->thread_sibling); + } +} + void __init dt_init_cpu_topology(void) { unsigned int cpu; @@ -XXX,XX +XXX,XX @@ void __init dt_init_cpu_topology(void) for_each_possible_cpu(cpu) setup_siblings_masks(cpu); + + setup_cpu_topology_ids(); } /* diff --git a/xen/common/sched/credit2.c b/xen/common/sched/credit2.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/sched/credit2.c +++ b/xen/common/sched/credit2.c @@ -XXX,XX +XXX,XX @@ * Based on an earlier verson by Emmanuel Ackaouy. */ +#include <xen/cpu-topology.h> #include <xen/errno.h> #include <xen/init.h> #include <xen/lib.h> @@ -XXX,XX +XXX,XX @@ static unsigned int cpu_nr_siblings(unsigned int cpu) { #ifdef CONFIG_X86 return cpu_data[cpu].x86_num_siblings; +#elif defined(CONFIG_CPU_TOPOLOGY) + return cpu_topology ? cpu_topology[cpu].num_siblings : 1; #else return 1; #endif diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -XXX,XX +XXX,XX @@ #include <xen/pmstat.h> #include <xen/livepatch.h> #include <xen/coverage.h> +#include <xen/cpu-topology.h> long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl) { diff --git a/xen/drivers/acpi/topology.c b/xen/drivers/acpi/topology.c index XXXXXXX..XXXXXXX 100644 --- a/xen/drivers/acpi/topology.c +++ b/xen/drivers/acpi/topology.c @@ -XXX,XX +XXX,XX @@ void __init acpi_init_cpu_topology(void) { struct cpu_topology *topo = &cpu_topology[cpu]; + topo->phys_core_id = cpu; + topo->num_siblings = 1; + cpumask_set_cpu(cpu, topo->thread_sibling); cpumask_copy(topo->core_sibling, &cpu_possible_map); } diff --git a/xen/include/xen/cpu-topology.h b/xen/include/xen/cpu-topology.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/cpu-topology.h +++ b/xen/include/xen/cpu-topology.h @@ -XXX,XX +XXX,XX @@ #define XEN_CPU_TOPOLOGY_H #include <xen/cpumask.h> +#include <xen/percpu.h> +#include <asm/processor.h> +#include <asm/smp.h> #ifdef CONFIG_GENERIC_CPU_TOPOLOGY @@ -XXX,XX +XXX,XX @@ struct cpu_topology { cpumask_var_t thread_sibling; cpumask_var_t core_sibling; cpumask_var_t cluster_sibling; + unsigned int phys_core_id; + unsigned int phys_cluster_id; + unsigned int phys_socket_id; + unsigned int num_siblings; }; extern struct cpu_topology *cpu_topology; void init_cpu_topology(void); +static inline void init_cpu_sibling_map(unsigned int cpu) +{ + if ( cpu_topology ) + { + cpumask_copy(per_cpu(cpu_sibling_mask, cpu), + cpu_topology[cpu].thread_sibling); + cpumask_copy(per_cpu(cpu_core_mask, cpu), + cpu_topology[cpu].core_sibling); + } + else + { + cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); + cpumask_copy(per_cpu(cpu_core_mask, cpu), &cpu_possible_map); + } +} + +#define cpu_to_core(cpu) (cpu_topology ? cpu_topology[cpu].phys_core_id : 0) +#define cpu_to_socket(cpu) (cpu_topology ? cpu_topology[cpu].phys_socket_id : 0) + #else /* CONFIG_GENERIC_CPU_TOPOLOGY */ -#define cpu_topology ((struct cpu_topology *)NULL) static inline void init_cpu_topology(void) {} +static inline void init_cpu_sibling_map(unsigned int cpu) +{ + /* + * If CONFIG_GENERIC_CPU_TOPOLOGY is disabled, it is assumed that + * all CPUs reside in the same socket and that SMT is not used. + */ + cpumask_set_cpu(cpu, per_cpu(cpu_sibling_mask, cpu)); + cpumask_copy(per_cpu(cpu_core_mask, cpu), &cpu_possible_map); +} + +#ifndef cpu_to_core +#define cpu_to_core(cpu) (0) +#endif + +#ifndef cpu_to_socket +#define cpu_to_socket(cpu) (0) +#endif + #endif /* CONFIG_GENERIC_CPU_TOPOLOGY */ #endif /* XEN_CPU_TOPOLOGY_H */ -- 2.43.0
Make cpu_nr_siblings() an architecture-specific function. This patch provides the implementation for x86 and a common version for Device Tree-based architectures. Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp> Acked-by: Jan Beulich <jbeulich@suse.com> --- xen/arch/x86/include/asm/processor.h | 1 + xen/common/sched/credit2.c | 22 +++------------------- xen/include/xen/cpu-topology.h | 5 +++++ 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/processor.h +++ b/xen/arch/x86/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ extern void intel_init_arat(void); #define cpu_to_core(_cpu) (cpu_data[_cpu].cpu_core_id) #define cpu_to_socket(_cpu) (cpu_data[_cpu].phys_proc_id) +#define cpu_nr_siblings(_cpu) (cpu_data[_cpu].x86_num_siblings) unsigned int apicid_to_socket(unsigned int apicid); diff --git a/xen/common/sched/credit2.c b/xen/common/sched/credit2.c index XXXXXXX..XXXXXXX 100644 --- a/xen/common/sched/credit2.c +++ b/xen/common/sched/credit2.c @@ -XXX,XX +XXX,XX @@ /* #define d2printk printk */ #define d2printk(x...) -/* - * TODO: Abstract this properly, and figure out what Credit2 wants to do with - * the fact that x86_num_siblings doesn't even have the same meaning - * between x86 vendors. - */ -static unsigned int cpu_nr_siblings(unsigned int cpu) -{ -#ifdef CONFIG_X86 - return cpu_data[cpu].x86_num_siblings; -#elif defined(CONFIG_CPU_TOPOLOGY) - return cpu_topology ? cpu_topology[cpu].num_siblings : 1; -#else - return 1; -#endif -} - /* * Credit2 tracing events ("only" 512 available!). Check * include/public/trace.h for more details. @@ -XXX,XX +XXX,XX @@ cpu_runqueue_match(const struct csched2_runqueue_data *rqd, unsigned int cpu) /* * Additional checks, to avoid separating siblings in different runqueues. - * This deals with both Intel's HTs and AMD's CUs. An arch that does not have - * any similar concept will just have cpu_nr_siblings() always return 1, and - * setup the cpu_sibling_mask-s acordingly (as currently does ARM), and things + * This deals with Intel's HTs, AMD's CUs and ARM's SMT. An arch that + * does not have similar concept will just have cpu_nr_siblings() always + * return 1, and setup the cpu_sibling_mask-s accordingly, and things * will just work as well. */ static bool diff --git a/xen/include/xen/cpu-topology.h b/xen/include/xen/cpu-topology.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/cpu-topology.h +++ b/xen/include/xen/cpu-topology.h @@ -XXX,XX +XXX,XX @@ static inline void init_cpu_sibling_map(unsigned int cpu) #define cpu_to_core(cpu) (cpu_topology ? cpu_topology[cpu].phys_core_id : 0) #define cpu_to_socket(cpu) (cpu_topology ? cpu_topology[cpu].phys_socket_id : 0) +#define cpu_nr_siblings(cpu) (cpu_topology ? cpu_topology[cpu].num_siblings : 1) #else /* CONFIG_GENERIC_CPU_TOPOLOGY */ @@ -XXX,XX +XXX,XX @@ static inline void init_cpu_sibling_map(unsigned int cpu) #define cpu_to_socket(cpu) (0) #endif +#ifndef cpu_nr_siblings +#define cpu_nr_siblings(cpu) (1) +#endif + #endif /* CONFIG_GENERIC_CPU_TOPOLOGY */ #endif /* XEN_CPU_TOPOLOGY_H */ -- 2.43.0