Commit 8ae9e2d8 authored by Catalin Marinas's avatar Catalin Marinas
Browse files

Merge branch 'for-next/smt-control' into for-next/core

* for-next/smt-control:
  : Support SMT control on arm64
  arm64: Kconfig: Enable HOTPLUG_SMT
  arm64: topology: Support SMT control on ACPI based system
  arch_topology: Support SMT control for OF based system
  cpu/SMT: Provide a default topology_is_primary_thread()
parents 8cc14fdc eed4583b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -250,6 +250,7 @@ config ARM64
	select HAVE_KRETPROBES
	select HAVE_GENERIC_VDSO
	select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
	select HOTPLUG_SMT if HOTPLUG_CPU
	select IRQ_DOMAIN
	select IRQ_FORCED_THREADING
	select KASAN_VMALLOC if KASAN
+54 −0
Original line number Diff line number Diff line
@@ -15,9 +15,11 @@
#include <linux/arch_topology.h>
#include <linux/cacheinfo.h>
#include <linux/cpufreq.h>
#include <linux/cpu_smt.h>
#include <linux/init.h>
#include <linux/percpu.h>
#include <linux/sched/isolation.h>
#include <linux/xarray.h>

#include <asm/cpu.h>
#include <asm/cputype.h>
@@ -38,17 +40,28 @@ static bool __init acpi_cpu_is_threaded(int cpu)
	return !!is_threaded;
}

struct cpu_smt_info {
	unsigned int thread_num;
	int core_id;
};

/*
 * Propagate the topology information of the processor_topology_node tree to the
 * cpu_topology array.
 */
int __init parse_acpi_topology(void)
{
	unsigned int max_smt_thread_num = 1;
	struct cpu_smt_info *entry;
	struct xarray hetero_cpu;
	unsigned long hetero_id;
	int cpu, topology_id;

	if (acpi_disabled)
		return 0;

	xa_init(&hetero_cpu);

	for_each_possible_cpu(cpu) {
		topology_id = find_acpi_cpu_topology(cpu, 0);
		if (topology_id < 0)
@@ -58,6 +71,34 @@ int __init parse_acpi_topology(void)
			cpu_topology[cpu].thread_id = topology_id;
			topology_id = find_acpi_cpu_topology(cpu, 1);
			cpu_topology[cpu].core_id   = topology_id;

			/*
			 * In the PPTT, CPUs below a node with the 'identical
			 * implementation' flag have the same number of threads.
			 * Count the number of threads for only one CPU (i.e.
			 * one core_id) among those with the same hetero_id.
			 * See the comment of find_acpi_cpu_topology_hetero_id()
			 * for more details.
			 *
			 * One entry is created for each node having:
			 * - the 'identical implementation' flag
			 * - its parent not having the flag
			 */
			hetero_id = find_acpi_cpu_topology_hetero_id(cpu);
			entry = xa_load(&hetero_cpu, hetero_id);
			if (!entry) {
				entry = kzalloc(sizeof(*entry), GFP_KERNEL);
				WARN_ON_ONCE(!entry);

				if (entry) {
					entry->core_id = topology_id;
					entry->thread_num = 1;
					xa_store(&hetero_cpu, hetero_id,
						 entry, GFP_KERNEL);
				}
			} else if (entry->core_id == topology_id) {
				entry->thread_num++;
			}
		} else {
			cpu_topology[cpu].thread_id  = -1;
			cpu_topology[cpu].core_id    = topology_id;
@@ -68,6 +109,19 @@ int __init parse_acpi_topology(void)
		cpu_topology[cpu].package_id = topology_id;
	}

	/*
	 * This is a short loop since the number of XArray elements is the
	 * number of heterogeneous CPU clusters. On a homogeneous system
	 * there's only one entry in the XArray.
	 */
	xa_for_each(&hetero_cpu, hetero_id, entry) {
		max_smt_thread_num = max(max_smt_thread_num, entry->thread_num);
		xa_erase(&hetero_cpu, hetero_id);
		kfree(entry);
	}

	cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num);
	xa_destroy(&hetero_cpu);
	return 0;
}
#endif
+1 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
{
	return cpu == cpu_first_thread_sibling(cpu);
}
#define topology_is_primary_thread topology_is_primary_thread

static inline bool topology_smt_thread_allowed(unsigned int cpu)
{
+1 −1
Original line number Diff line number Diff line
@@ -229,11 +229,11 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
{
	return cpumask_test_cpu(cpu, cpu_primary_thread_mask);
}
#define topology_is_primary_thread topology_is_primary_thread

#else /* CONFIG_SMP */
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
static inline int topology_max_smt_threads(void) { return 1; }
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
static inline unsigned int topology_amd_nodes_per_pkg(void) { return 1; }
#endif /* !CONFIG_SMP */

+18 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/cleanup.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/cpu_smt.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/slab.h>
@@ -508,6 +509,10 @@ core_initcall(free_raw_capacity);
#endif

#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)

/* Used to enable the SMT control */
static unsigned int max_smt_thread_num = 1;

/*
 * This function returns the logic cpu number of the node.
 * There are basically three kinds of return values:
@@ -567,6 +572,8 @@ static int __init parse_core(struct device_node *core, int package_id,
		i++;
	} while (1);

	max_smt_thread_num = max_t(unsigned int, max_smt_thread_num, i);

	cpu = get_cpu_for_node(core);
	if (cpu >= 0) {
		if (!leaf) {
@@ -679,6 +686,17 @@ static int __init parse_socket(struct device_node *socket)
	if (!has_socket)
		ret = parse_cluster(socket, 0, -1, 0);

	/*
	 * Reset the max_smt_thread_num to 1 on failure. Since on failure
	 * we need to notify the framework the SMT is not supported, but
	 * max_smt_thread_num can be initialized to the SMT thread number
	 * of the cores which are successfully parsed.
	 */
	if (ret)
		max_smt_thread_num = 1;

	cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num);

	return ret;
}

Loading