cpu-topology: Move cpu topology code to common code.
authorAtish Patra <atish.patra@wdc.com>
Thu, 27 Jun 2019 19:52:58 +0000 (12:52 -0700)
committerPaul Walmsley <paul.walmsley@sifive.com>
Mon, 22 Jul 2019 16:36:06 +0000 (09:36 -0700)
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>
arch/arm64/include/asm/topology.h
arch/arm64/kernel/topology.c
drivers/base/arch_topology.c
include/linux/arch_topology.h
include/linux/topology.h

index 0524f243864931087c1227fc3b8cf970d471ce5b..a4d945db95a299f5f2c733d7cc4aa931ace67ed0 100644 (file)
@@ -4,29 +4,6 @@
 
 #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
 
 struct pci_bus;
index 0825c4a856e33da0d794f403fd2a6464543467c3..6b95c91e7d6798c00034cc08eaf8b201b9dfdb04 100644 (file)
 #include <linux/acpi.h>
 #include <linux/arch_topology.h>
 #include <linux/cacheinfo.h>
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
 #include <linux/init.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/cputype.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)
 {
        struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
@@ -296,59 +59,19 @@ topology_populated:
        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
 /*
  * Propagate the topology information of the processor_topology_node tree to the
  * cpu_topology array.
  */
-static int __init parse_acpi_topology(void)
+int __init parse_acpi_topology(void)
 {
        bool is_threaded;
        int cpu, topology_id;
 
+       if (acpi_disabled)
+               return 0;
+
        is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
 
        for_each_possible_cpu(cpu) {
@@ -384,24 +107,6 @@ static int __init parse_acpi_topology(void)
 
        return 0;
 }
-
-#else
-static inline int __init parse_acpi_topology(void)
-{
-       return -EINVAL;
-}
 #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();
-}
index 63c1e76739f12648c9face8e841d756d693dec01..5dc0e1ddd080d19703e8782d1640ef73ff8fa731 100644 (file)
 #include <linux/string.h>
 #include <linux/sched/topology.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;
 
@@ -241,3 +246,294 @@ static void parsing_done_workfn(struct work_struct *work)
 #else
 core_initcall(free_raw_capacity);
 #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
index 1cfe05ea1d896124990f0133e2b8037edebc7a2e..ede0ce4623b42428f711a8884bfc26caababacee 100644 (file)
@@ -33,4 +33,32 @@ unsigned long topology_get_freq_scale(int 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_ */
index 47a3e3c08036b386cd052023b86e632526bb4dc5..2a19d196af2886899a552dda7c68edaf1015dc66 100644 (file)
@@ -27,6 +27,7 @@
 #ifndef _LINUX_TOPOLOGY_H
 #define _LINUX_TOPOLOGY_H
 
+#include <linux/arch_topology.h>
 #include <linux/cpumask.h>
 #include <linux/bitops.h>
 #include <linux/mmzone.h>