cpu-topology: Move cpu topology code to common code.
Both RISC-V & ARM64 are using cpu-map device tree to describe their cpu topology. It's better to move the relevant code to a common place instead of duplicate code. To: Will Deacon <will.deacon@arm.com> To: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Atish Patra <atish.patra@wdc.com> [Tested on QDF2400] Tested-by: Jeffrey Hugo <jhugo@codeaurora.org> [Tested on Juno and other embedded platforms.] Tested-by: Sudeep Holla <sudeep.holla@arm.com> Reviewed-by: Sudeep Holla <sudeep.holla@arm.com> Acked-by: Will Deacon <will.deacon@arm.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
This commit is contained in:
Родитель
124e46a865
Коммит
60c1b220d8
|
@ -4,29 +4,6 @@
|
||||||
|
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
|
|
||||||
struct cpu_topology {
|
|
||||||
int thread_id;
|
|
||||||
int core_id;
|
|
||||||
int package_id;
|
|
||||||
int llc_id;
|
|
||||||
cpumask_t thread_sibling;
|
|
||||||
cpumask_t core_sibling;
|
|
||||||
cpumask_t llc_sibling;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct cpu_topology cpu_topology[NR_CPUS];
|
|
||||||
|
|
||||||
#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id)
|
|
||||||
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
|
|
||||||
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
|
|
||||||
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
|
|
||||||
#define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling)
|
|
||||||
|
|
||||||
void init_cpu_topology(void);
|
|
||||||
void store_cpu_topology(unsigned int cpuid);
|
|
||||||
void remove_cpu_topology(unsigned int cpuid);
|
|
||||||
const struct cpumask *cpu_coregroup_mask(int cpu);
|
|
||||||
|
|
||||||
#ifdef CONFIG_NUMA
|
#ifdef CONFIG_NUMA
|
||||||
|
|
||||||
struct pci_bus;
|
struct pci_bus;
|
||||||
|
|
|
@ -14,250 +14,13 @@
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/arch_topology.h>
|
#include <linux/arch_topology.h>
|
||||||
#include <linux/cacheinfo.h>
|
#include <linux/cacheinfo.h>
|
||||||
#include <linux/cpu.h>
|
|
||||||
#include <linux/cpumask.h>
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/percpu.h>
|
#include <linux/percpu.h>
|
||||||
#include <linux/node.h>
|
|
||||||
#include <linux/nodemask.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/sched/topology.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/smp.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
|
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/cputype.h>
|
#include <asm/cputype.h>
|
||||||
#include <asm/topology.h>
|
#include <asm/topology.h>
|
||||||
|
|
||||||
static int __init get_cpu_for_node(struct device_node *node)
|
|
||||||
{
|
|
||||||
struct device_node *cpu_node;
|
|
||||||
int cpu;
|
|
||||||
|
|
||||||
cpu_node = of_parse_phandle(node, "cpu", 0);
|
|
||||||
if (!cpu_node)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
cpu = of_cpu_node_to_id(cpu_node);
|
|
||||||
if (cpu >= 0)
|
|
||||||
topology_parse_cpu_capacity(cpu_node, cpu);
|
|
||||||
else
|
|
||||||
pr_crit("Unable to find CPU node for %pOF\n", cpu_node);
|
|
||||||
|
|
||||||
of_node_put(cpu_node);
|
|
||||||
return cpu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init parse_core(struct device_node *core, int package_id,
|
|
||||||
int core_id)
|
|
||||||
{
|
|
||||||
char name[10];
|
|
||||||
bool leaf = true;
|
|
||||||
int i = 0;
|
|
||||||
int cpu;
|
|
||||||
struct device_node *t;
|
|
||||||
|
|
||||||
do {
|
|
||||||
snprintf(name, sizeof(name), "thread%d", i);
|
|
||||||
t = of_get_child_by_name(core, name);
|
|
||||||
if (t) {
|
|
||||||
leaf = false;
|
|
||||||
cpu = get_cpu_for_node(t);
|
|
||||||
if (cpu >= 0) {
|
|
||||||
cpu_topology[cpu].package_id = package_id;
|
|
||||||
cpu_topology[cpu].core_id = core_id;
|
|
||||||
cpu_topology[cpu].thread_id = i;
|
|
||||||
} else {
|
|
||||||
pr_err("%pOF: Can't get CPU for thread\n",
|
|
||||||
t);
|
|
||||||
of_node_put(t);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
of_node_put(t);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} while (t);
|
|
||||||
|
|
||||||
cpu = get_cpu_for_node(core);
|
|
||||||
if (cpu >= 0) {
|
|
||||||
if (!leaf) {
|
|
||||||
pr_err("%pOF: Core has both threads and CPU\n",
|
|
||||||
core);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_topology[cpu].package_id = package_id;
|
|
||||||
cpu_topology[cpu].core_id = core_id;
|
|
||||||
} else if (leaf) {
|
|
||||||
pr_err("%pOF: Can't get CPU for leaf core\n", core);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init parse_cluster(struct device_node *cluster, int depth)
|
|
||||||
{
|
|
||||||
char name[10];
|
|
||||||
bool leaf = true;
|
|
||||||
bool has_cores = false;
|
|
||||||
struct device_node *c;
|
|
||||||
static int package_id __initdata;
|
|
||||||
int core_id = 0;
|
|
||||||
int i, 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 {
|
|
||||||
snprintf(name, sizeof(name), "cluster%d", i);
|
|
||||||
c = of_get_child_by_name(cluster, name);
|
|
||||||
if (c) {
|
|
||||||
leaf = false;
|
|
||||||
ret = parse_cluster(c, depth + 1);
|
|
||||||
of_node_put(c);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} while (c);
|
|
||||||
|
|
||||||
/* Now check for cores */
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
snprintf(name, sizeof(name), "core%d", i);
|
|
||||||
c = of_get_child_by_name(cluster, name);
|
|
||||||
if (c) {
|
|
||||||
has_cores = true;
|
|
||||||
|
|
||||||
if (depth == 0) {
|
|
||||||
pr_err("%pOF: cpu-map children should be clusters\n",
|
|
||||||
c);
|
|
||||||
of_node_put(c);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leaf) {
|
|
||||||
ret = parse_core(c, package_id, core_id++);
|
|
||||||
} else {
|
|
||||||
pr_err("%pOF: Non-leaf cluster with core %s\n",
|
|
||||||
cluster, name);
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
of_node_put(c);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
} while (c);
|
|
||||||
|
|
||||||
if (leaf && !has_cores)
|
|
||||||
pr_warn("%pOF: empty cluster\n", cluster);
|
|
||||||
|
|
||||||
if (leaf)
|
|
||||||
package_id++;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init parse_dt_topology(void)
|
|
||||||
{
|
|
||||||
struct device_node *cn, *map;
|
|
||||||
int ret = 0;
|
|
||||||
int cpu;
|
|
||||||
|
|
||||||
cn = of_find_node_by_path("/cpus");
|
|
||||||
if (!cn) {
|
|
||||||
pr_err("No CPU information found in DT\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When topology is provided cpu-map is essentially a root
|
|
||||||
* cluster with restricted subnodes.
|
|
||||||
*/
|
|
||||||
map = of_get_child_by_name(cn, "cpu-map");
|
|
||||||
if (!map)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = parse_cluster(map, 0);
|
|
||||||
if (ret != 0)
|
|
||||||
goto out_map;
|
|
||||||
|
|
||||||
topology_normalize_cpu_scale();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check that all cores are in the topology; the SMP code will
|
|
||||||
* only mark cores described in the DT as possible.
|
|
||||||
*/
|
|
||||||
for_each_possible_cpu(cpu)
|
|
||||||
if (cpu_topology[cpu].package_id == -1)
|
|
||||||
ret = -EINVAL;
|
|
||||||
|
|
||||||
out_map:
|
|
||||||
of_node_put(map);
|
|
||||||
out:
|
|
||||||
of_node_put(cn);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* cpu topology table
|
|
||||||
*/
|
|
||||||
struct cpu_topology cpu_topology[NR_CPUS];
|
|
||||||
EXPORT_SYMBOL_GPL(cpu_topology);
|
|
||||||
|
|
||||||
const struct cpumask *cpu_coregroup_mask(int cpu)
|
|
||||||
{
|
|
||||||
const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
|
|
||||||
|
|
||||||
/* Find the smaller of NUMA, core or LLC siblings */
|
|
||||||
if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
|
|
||||||
/* not numa in package, lets use the package siblings */
|
|
||||||
core_mask = &cpu_topology[cpu].core_sibling;
|
|
||||||
}
|
|
||||||
if (cpu_topology[cpu].llc_id != -1) {
|
|
||||||
if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask))
|
|
||||||
core_mask = &cpu_topology[cpu].llc_sibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
return core_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_siblings_masks(unsigned int cpuid)
|
|
||||||
{
|
|
||||||
struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
|
|
||||||
int cpu;
|
|
||||||
|
|
||||||
/* update core and thread sibling masks */
|
|
||||||
for_each_online_cpu(cpu) {
|
|
||||||
cpu_topo = &cpu_topology[cpu];
|
|
||||||
|
|
||||||
if (cpuid_topo->llc_id == cpu_topo->llc_id) {
|
|
||||||
cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling);
|
|
||||||
cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cpuid_topo->package_id != cpu_topo->package_id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
|
|
||||||
cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
|
|
||||||
|
|
||||||
if (cpuid_topo->core_id != cpu_topo->core_id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
|
|
||||||
cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void store_cpu_topology(unsigned int cpuid)
|
void store_cpu_topology(unsigned int cpuid)
|
||||||
{
|
{
|
||||||
struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
|
struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
|
||||||
|
@ -296,59 +59,19 @@ topology_populated:
|
||||||
update_siblings_masks(cpuid);
|
update_siblings_masks(cpuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_cpu_topology(int cpu)
|
|
||||||
{
|
|
||||||
struct cpu_topology *cpu_topo = &cpu_topology[cpu];
|
|
||||||
|
|
||||||
cpumask_clear(&cpu_topo->llc_sibling);
|
|
||||||
cpumask_set_cpu(cpu, &cpu_topo->llc_sibling);
|
|
||||||
|
|
||||||
cpumask_clear(&cpu_topo->core_sibling);
|
|
||||||
cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
|
|
||||||
cpumask_clear(&cpu_topo->thread_sibling);
|
|
||||||
cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init reset_cpu_topology(void)
|
|
||||||
{
|
|
||||||
unsigned int cpu;
|
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
|
||||||
struct cpu_topology *cpu_topo = &cpu_topology[cpu];
|
|
||||||
|
|
||||||
cpu_topo->thread_id = -1;
|
|
||||||
cpu_topo->core_id = 0;
|
|
||||||
cpu_topo->package_id = -1;
|
|
||||||
cpu_topo->llc_id = -1;
|
|
||||||
|
|
||||||
clear_cpu_topology(cpu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_cpu_topology(unsigned int cpu)
|
|
||||||
{
|
|
||||||
int sibling;
|
|
||||||
|
|
||||||
for_each_cpu(sibling, topology_core_cpumask(cpu))
|
|
||||||
cpumask_clear_cpu(cpu, topology_core_cpumask(sibling));
|
|
||||||
for_each_cpu(sibling, topology_sibling_cpumask(cpu))
|
|
||||||
cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
|
|
||||||
for_each_cpu(sibling, topology_llc_cpumask(cpu))
|
|
||||||
cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling));
|
|
||||||
|
|
||||||
clear_cpu_topology(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
/*
|
/*
|
||||||
* Propagate the topology information of the processor_topology_node tree to the
|
* Propagate the topology information of the processor_topology_node tree to the
|
||||||
* cpu_topology array.
|
* cpu_topology array.
|
||||||
*/
|
*/
|
||||||
static int __init parse_acpi_topology(void)
|
int __init parse_acpi_topology(void)
|
||||||
{
|
{
|
||||||
bool is_threaded;
|
bool is_threaded;
|
||||||
int cpu, topology_id;
|
int cpu, topology_id;
|
||||||
|
|
||||||
|
if (acpi_disabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
|
is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
|
@ -384,24 +107,6 @@ static int __init parse_acpi_topology(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
static inline int __init parse_acpi_topology(void)
|
|
||||||
{
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __init init_cpu_topology(void)
|
|
||||||
{
|
|
||||||
reset_cpu_topology();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Discard anything that was parsed if we hit an error so we
|
|
||||||
* don't use partial information.
|
|
||||||
*/
|
|
||||||
if (!acpi_disabled && parse_acpi_topology())
|
|
||||||
reset_cpu_topology();
|
|
||||||
else if (of_have_populated_dt() && parse_dt_topology())
|
|
||||||
reset_cpu_topology();
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/sched/topology.h>
|
#include <linux/sched/topology.h>
|
||||||
#include <linux/cpuset.h>
|
#include <linux/cpuset.h>
|
||||||
|
#include <linux/cpumask.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/smp.h>
|
||||||
|
|
||||||
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
|
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
|
||||||
|
|
||||||
|
@ -241,3 +246,294 @@ static void parsing_done_workfn(struct work_struct *work)
|
||||||
#else
|
#else
|
||||||
core_initcall(free_raw_capacity);
|
core_initcall(free_raw_capacity);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
|
||||||
|
static int __init get_cpu_for_node(struct device_node *node)
|
||||||
|
{
|
||||||
|
struct device_node *cpu_node;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
cpu_node = of_parse_phandle(node, "cpu", 0);
|
||||||
|
if (!cpu_node)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cpu = of_cpu_node_to_id(cpu_node);
|
||||||
|
if (cpu >= 0)
|
||||||
|
topology_parse_cpu_capacity(cpu_node, cpu);
|
||||||
|
else
|
||||||
|
pr_crit("Unable to find CPU node for %pOF\n", cpu_node);
|
||||||
|
|
||||||
|
of_node_put(cpu_node);
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init parse_core(struct device_node *core, int package_id,
|
||||||
|
int core_id)
|
||||||
|
{
|
||||||
|
char name[10];
|
||||||
|
bool leaf = true;
|
||||||
|
int i = 0;
|
||||||
|
int cpu;
|
||||||
|
struct device_node *t;
|
||||||
|
|
||||||
|
do {
|
||||||
|
snprintf(name, sizeof(name), "thread%d", i);
|
||||||
|
t = of_get_child_by_name(core, name);
|
||||||
|
if (t) {
|
||||||
|
leaf = false;
|
||||||
|
cpu = get_cpu_for_node(t);
|
||||||
|
if (cpu >= 0) {
|
||||||
|
cpu_topology[cpu].package_id = package_id;
|
||||||
|
cpu_topology[cpu].core_id = core_id;
|
||||||
|
cpu_topology[cpu].thread_id = i;
|
||||||
|
} else {
|
||||||
|
pr_err("%pOF: Can't get CPU for thread\n",
|
||||||
|
t);
|
||||||
|
of_node_put(t);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
of_node_put(t);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (t);
|
||||||
|
|
||||||
|
cpu = get_cpu_for_node(core);
|
||||||
|
if (cpu >= 0) {
|
||||||
|
if (!leaf) {
|
||||||
|
pr_err("%pOF: Core has both threads and CPU\n",
|
||||||
|
core);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_topology[cpu].package_id = package_id;
|
||||||
|
cpu_topology[cpu].core_id = core_id;
|
||||||
|
} else if (leaf) {
|
||||||
|
pr_err("%pOF: Can't get CPU for leaf core\n", core);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init parse_cluster(struct device_node *cluster, int depth)
|
||||||
|
{
|
||||||
|
char name[10];
|
||||||
|
bool leaf = true;
|
||||||
|
bool has_cores = false;
|
||||||
|
struct device_node *c;
|
||||||
|
static int package_id __initdata;
|
||||||
|
int core_id = 0;
|
||||||
|
int i, 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 {
|
||||||
|
snprintf(name, sizeof(name), "cluster%d", i);
|
||||||
|
c = of_get_child_by_name(cluster, name);
|
||||||
|
if (c) {
|
||||||
|
leaf = false;
|
||||||
|
ret = parse_cluster(c, depth + 1);
|
||||||
|
of_node_put(c);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (c);
|
||||||
|
|
||||||
|
/* Now check for cores */
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
snprintf(name, sizeof(name), "core%d", i);
|
||||||
|
c = of_get_child_by_name(cluster, name);
|
||||||
|
if (c) {
|
||||||
|
has_cores = true;
|
||||||
|
|
||||||
|
if (depth == 0) {
|
||||||
|
pr_err("%pOF: cpu-map children should be clusters\n",
|
||||||
|
c);
|
||||||
|
of_node_put(c);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaf) {
|
||||||
|
ret = parse_core(c, package_id, core_id++);
|
||||||
|
} else {
|
||||||
|
pr_err("%pOF: Non-leaf cluster with core %s\n",
|
||||||
|
cluster, name);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(c);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (c);
|
||||||
|
|
||||||
|
if (leaf && !has_cores)
|
||||||
|
pr_warn("%pOF: empty cluster\n", cluster);
|
||||||
|
|
||||||
|
if (leaf)
|
||||||
|
package_id++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init parse_dt_topology(void)
|
||||||
|
{
|
||||||
|
struct device_node *cn, *map;
|
||||||
|
int ret = 0;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
cn = of_find_node_by_path("/cpus");
|
||||||
|
if (!cn) {
|
||||||
|
pr_err("No CPU information found in DT\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When topology is provided cpu-map is essentially a root
|
||||||
|
* cluster with restricted subnodes.
|
||||||
|
*/
|
||||||
|
map = of_get_child_by_name(cn, "cpu-map");
|
||||||
|
if (!map)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = parse_cluster(map, 0);
|
||||||
|
if (ret != 0)
|
||||||
|
goto out_map;
|
||||||
|
|
||||||
|
topology_normalize_cpu_scale();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that all cores are in the topology; the SMP code will
|
||||||
|
* only mark cores described in the DT as possible.
|
||||||
|
*/
|
||||||
|
for_each_possible_cpu(cpu)
|
||||||
|
if (cpu_topology[cpu].package_id == -1)
|
||||||
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
out_map:
|
||||||
|
of_node_put(map);
|
||||||
|
out:
|
||||||
|
of_node_put(cn);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cpu topology table
|
||||||
|
*/
|
||||||
|
struct cpu_topology cpu_topology[NR_CPUS];
|
||||||
|
EXPORT_SYMBOL_GPL(cpu_topology);
|
||||||
|
|
||||||
|
const struct cpumask *cpu_coregroup_mask(int cpu)
|
||||||
|
{
|
||||||
|
const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
|
||||||
|
|
||||||
|
/* Find the smaller of NUMA, core or LLC siblings */
|
||||||
|
if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
|
||||||
|
/* not numa in package, lets use the package siblings */
|
||||||
|
core_mask = &cpu_topology[cpu].core_sibling;
|
||||||
|
}
|
||||||
|
if (cpu_topology[cpu].llc_id != -1) {
|
||||||
|
if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask))
|
||||||
|
core_mask = &cpu_topology[cpu].llc_sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
return core_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_siblings_masks(unsigned int cpuid)
|
||||||
|
{
|
||||||
|
struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
/* update core and thread sibling masks */
|
||||||
|
for_each_online_cpu(cpu) {
|
||||||
|
cpu_topo = &cpu_topology[cpu];
|
||||||
|
|
||||||
|
if (cpuid_topo->llc_id == cpu_topo->llc_id) {
|
||||||
|
cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling);
|
||||||
|
cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpuid_topo->package_id != cpu_topo->package_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
|
||||||
|
cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
|
||||||
|
|
||||||
|
if (cpuid_topo->core_id != cpu_topo->core_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
|
||||||
|
cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_cpu_topology(int cpu)
|
||||||
|
{
|
||||||
|
struct cpu_topology *cpu_topo = &cpu_topology[cpu];
|
||||||
|
|
||||||
|
cpumask_clear(&cpu_topo->llc_sibling);
|
||||||
|
cpumask_set_cpu(cpu, &cpu_topo->llc_sibling);
|
||||||
|
|
||||||
|
cpumask_clear(&cpu_topo->core_sibling);
|
||||||
|
cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
|
||||||
|
cpumask_clear(&cpu_topo->thread_sibling);
|
||||||
|
cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init reset_cpu_topology(void)
|
||||||
|
{
|
||||||
|
unsigned int cpu;
|
||||||
|
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
struct cpu_topology *cpu_topo = &cpu_topology[cpu];
|
||||||
|
|
||||||
|
cpu_topo->thread_id = -1;
|
||||||
|
cpu_topo->core_id = -1;
|
||||||
|
cpu_topo->package_id = -1;
|
||||||
|
cpu_topo->llc_id = -1;
|
||||||
|
|
||||||
|
clear_cpu_topology(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_cpu_topology(unsigned int cpu)
|
||||||
|
{
|
||||||
|
int sibling;
|
||||||
|
|
||||||
|
for_each_cpu(sibling, topology_core_cpumask(cpu))
|
||||||
|
cpumask_clear_cpu(cpu, topology_core_cpumask(sibling));
|
||||||
|
for_each_cpu(sibling, topology_sibling_cpumask(cpu))
|
||||||
|
cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
|
||||||
|
for_each_cpu(sibling, topology_llc_cpumask(cpu))
|
||||||
|
cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling));
|
||||||
|
|
||||||
|
clear_cpu_topology(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
__weak int __init parse_acpi_topology(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init init_cpu_topology(void)
|
||||||
|
{
|
||||||
|
reset_cpu_topology();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Discard anything that was parsed if we hit an error so we
|
||||||
|
* don't use partial information.
|
||||||
|
*/
|
||||||
|
if (parse_acpi_topology())
|
||||||
|
reset_cpu_topology();
|
||||||
|
else if (of_have_populated_dt() && parse_dt_topology())
|
||||||
|
reset_cpu_topology();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -33,4 +33,32 @@ unsigned long topology_get_freq_scale(int cpu)
|
||||||
return per_cpu(freq_scale, cpu);
|
return per_cpu(freq_scale, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cpu_topology {
|
||||||
|
int thread_id;
|
||||||
|
int core_id;
|
||||||
|
int package_id;
|
||||||
|
int llc_id;
|
||||||
|
cpumask_t thread_sibling;
|
||||||
|
cpumask_t core_sibling;
|
||||||
|
cpumask_t llc_sibling;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
|
||||||
|
extern struct cpu_topology cpu_topology[NR_CPUS];
|
||||||
|
|
||||||
|
#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id)
|
||||||
|
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
|
||||||
|
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
|
||||||
|
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
|
||||||
|
#define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling)
|
||||||
|
void init_cpu_topology(void);
|
||||||
|
void store_cpu_topology(unsigned int cpuid);
|
||||||
|
const struct cpumask *cpu_coregroup_mask(int cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
|
||||||
|
void update_siblings_masks(unsigned int cpu);
|
||||||
|
#endif
|
||||||
|
void remove_cpu_topology(unsigned int cpuid);
|
||||||
|
|
||||||
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
|
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#ifndef _LINUX_TOPOLOGY_H
|
#ifndef _LINUX_TOPOLOGY_H
|
||||||
#define _LINUX_TOPOLOGY_H
|
#define _LINUX_TOPOLOGY_H
|
||||||
|
|
||||||
|
#include <linux/arch_topology.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/mmzone.h>
|
#include <linux/mmzone.h>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче