| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720 |
- /*
- * arch/arm/kernel/topology.c
- *
- * Copyright (C) 2011 Linaro Limited.
- * Written by: Vincent Guittot
- *
- * based on arch/sh/kernel/topology.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
- #include <linux/cpu.h>
- #include <linux/cpumask.h>
- #include <linux/export.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/slab.h>
- #include <asm/cputype.h>
- #include <asm/topology.h>
- /*
- * cpu capacity scale management
- */
- /*
- * cpu capacity table
- * This per cpu data structure describes the relative capacity of each core.
- * On a heteregenous system, cores don't have the same computation capacity
- * and we reflect that difference in the cpu_capacity field so the scheduler
- * can take this difference into account during load balance. A per cpu
- * structure is preferred because each CPU updates its own cpu_capacity field
- * during the load balance except for idle cores. One idle core is selected
- * to run the rebalance_domains for all idle cores and the cpu_capacity can be
- * updated during this sequence.
- */
- static DEFINE_PER_CPU(unsigned long, cpu_scale);
- unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
- {
- return per_cpu(cpu_scale, cpu);
- }
- unsigned long arch_get_max_cpu_capacity(int cpu)
- {
- return per_cpu(cpu_scale, cpu);
- }
- static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
- {
- per_cpu(cpu_scale, cpu) = capacity;
- }
- #ifdef CONFIG_OF
- struct cpu_efficiency {
- const char *compatible;
- unsigned long efficiency;
- };
- 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;
- for_each_possible_cpu(cpu) {
- if (of_get_cpu_node(cpu, NULL) == cpu_node) {
- of_node_put(cpu_node);
- return cpu;
- }
- }
- pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);
- of_node_put(cpu_node);
- return -1;
- }
- static int __init parse_core(struct device_node *core, int cluster_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].socket_id = cluster_id;
- cpu_topology[cpu].core_id = core_id;
- cpu_topology[cpu].thread_id = i;
- } else {
- pr_err("%s: Can't get CPU for thread\n",
- t->full_name);
- 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("%s: Core has both threads and CPU\n",
- core->full_name);
- return -EINVAL;
- }
- cpu_topology[cpu].socket_id = cluster_id;
- cpu_topology[cpu].core_id = core_id;
- } else if (leaf) {
- pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
- 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;
- int core_id = 0;
- static int cluster_id __initdata;
- struct device_node *c;
- 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("%s: cpu-map children should be clusters\n",
- c->full_name);
- of_node_put(c);
- return -EINVAL;
- }
- if (leaf) {
- ret = parse_core(c, cluster_id, core_id++);
- } else {
- pr_err("%s: Non-leaf cluster with core %s\n",
- cluster->full_name, name);
- ret = -EINVAL;
- }
- of_node_put(c);
- if (ret != 0)
- return ret;
- }
- i++;
- } while (c);
- if (leaf && !has_cores)
- pr_warn("%s: empty cluster\n", cluster->full_name);
- if (leaf)
- cluster_id++;
- return 0;
- }
- /*
- * Table of relative efficiency of each processors
- * The efficiency value must fit in 20bit and the final
- * cpu_scale value must be in the range
- * 0 < cpu_scale < SCHED_CAPACITY_SCALE.
- * Processors that are not defined in the table,
- * use the default SCHED_CAPACITY_SCALE value for cpu_scale.
- */
- static const struct cpu_efficiency table_efficiency[] = {
- {"arm,cortex-a15", 3891},
- {"arm,cortex-a17", 3276},
- {"arm,cortex-a12", 3276},
- {"arm,cortex-a53", 2520},
- {"arm,cortex-a7", 2048},
- {NULL, },
- };
- static unsigned long *__cpu_capacity;
- #define cpu_capacity(cpu) __cpu_capacity[cpu]
- static unsigned long max_cpu_perf, min_cpu_perf;
- 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;
- /*
- * 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].socket_id == -1)
- ret = -EINVAL;
- out_map:
- of_node_put(map);
- out:
- of_node_put(cn);
- return ret;
- }
- /*
- * Iterate all CPUs' descriptor in DT and compute the efficiency
- * (as per table_efficiency). Calculate the max cpu performance too.
- */
- static void parse_dt_cpu_capacity(void)
- {
- const struct cpu_efficiency *cpu_eff;
- struct device_node *cn = NULL;
- int cpu = 0, i = 0;
- __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity),
- GFP_NOWAIT);
- min_cpu_perf = ULONG_MAX;
- max_cpu_perf = 0;
- for_each_possible_cpu(cpu) {
- const u32 *rate;
- int len;
- unsigned long cpu_perf;
- /* too early to use cpu->of_node */
- cn = of_get_cpu_node(cpu, NULL);
- if (!cn) {
- pr_err("missing device node for CPU %d\n", cpu);
- continue;
- }
- for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
- if (of_device_is_compatible(cn, cpu_eff->compatible))
- break;
- if (cpu_eff->compatible == NULL)
- continue;
- rate = of_get_property(cn, "clock-frequency", &len);
- if (!rate || len != 4) {
- pr_err("%s missing clock-frequency property\n",
- cn->full_name);
- continue;
- }
- cpu_perf = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
- cpu_capacity(cpu) = cpu_perf;
- max_cpu_perf = max(max_cpu_perf, cpu_perf);
- min_cpu_perf = min(min_cpu_perf, cpu_perf);
- i++;
- }
- if (i < num_possible_cpus()) {
- max_cpu_perf = 0;
- min_cpu_perf = 0;
- }
- }
- /*
- * Look for a customed capacity of a CPU in the cpu_capacity table during the
- * boot. The update of all CPUs is in O(n^2) for heteregeneous system but the
- * function returns directly for SMP systems or if there is no complete set
- * of cpu efficiency, clock frequency data for each cpu.
- */
- static void update_cpu_capacity(unsigned int cpu)
- {
- unsigned long capacity = cpu_capacity(cpu);
- if (!capacity || !max_cpu_perf) {
- cpu_capacity(cpu) = 0;
- return;
- }
- capacity *= SCHED_CAPACITY_SCALE;
- capacity /= max_cpu_perf;
- set_capacity_scale(cpu, capacity);
- printk(KERN_INFO "CPU%u: update cpu_capacity %lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
- }
- /*
- * Scheduler load-tracking scale-invariance
- *
- * Provides the scheduler with a scale-invariance correction factor that
- * compensates for frequency scaling.
- */
- static DEFINE_PER_CPU(atomic_long_t, cpu_freq_capacity);
- static DEFINE_PER_CPU(atomic_long_t, cpu_max_freq);
- /* cpufreq callback function setting current cpu frequency */
- void arch_scale_set_curr_freq(int cpu, unsigned long freq)
- {
- unsigned long max = atomic_long_read(&per_cpu(cpu_max_freq, cpu));
- unsigned long curr;
- if (!max)
- return;
- curr = (freq * SCHED_CAPACITY_SCALE) / max;
- atomic_long_set(&per_cpu(cpu_freq_capacity, cpu), curr);
- }
- /* cpufreq callback function setting max cpu frequency */
- void arch_scale_set_max_freq(int cpu, unsigned long freq)
- {
- atomic_long_set(&per_cpu(cpu_max_freq, cpu), freq);
- }
- unsigned long arch_scale_freq_capacity(struct sched_domain *sd, int cpu)
- {
- unsigned long curr = atomic_long_read(&per_cpu(cpu_freq_capacity, cpu));
- if (!curr)
- return SCHED_CAPACITY_SCALE;
- return curr;
- }
- #else
- static inline void parse_dt_topology(void) {}
- static inline void update_cpu_capacity(unsigned int cpuid) {}
- #endif
- /*
- * cpu topology table
- */
- struct cputopo_arm cpu_topology[NR_CPUS];
- EXPORT_SYMBOL_GPL(cpu_topology);
- const struct cpumask *cpu_coregroup_mask(int cpu)
- {
- return &cpu_topology[cpu].core_sibling;
- }
- /*
- * The current assumption is that we can power gate each core independently.
- * This will be superseded by DT binding once available.
- */
- const struct cpumask *cpu_corepower_mask(int cpu)
- {
- return &cpu_topology[cpu].thread_sibling;
- }
- static void update_siblings_masks(unsigned int cpuid)
- {
- struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
- int cpu;
- /* update core and thread sibling masks */
- for_each_possible_cpu(cpu) {
- cpu_topo = &cpu_topology[cpu];
- if (cpuid_topo->socket_id != cpu_topo->socket_id)
- continue;
- cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
- if (cpu != cpuid)
- 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);
- if (cpu != cpuid)
- cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
- }
- smp_wmb();
- }
- /*
- * store_cpu_topology is called at boot when only one cpu is running
- * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
- * which prevents simultaneous write access to cpu_topology array
- */
- void store_cpu_topology(unsigned int cpuid)
- {
- struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
- unsigned int mpidr;
- mpidr = read_cpuid_mpidr();
- /* If the cpu topology has been already set, just return */
- if (cpuid_topo->socket_id != -1)
- goto topology_populated;
- /* create cpu topology mapping */
- if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) {
- /*
- * This is a multiprocessor system
- * multiprocessor format & multiprocessor mode field are set
- */
- if (mpidr & MPIDR_MT_BITMASK) {
- /* core performance interdependency */
- cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
- cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
- } else {
- /* largely independent cores */
- cpuid_topo->thread_id = -1;
- cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
- }
- } else {
- /*
- * This is an uniprocessor system
- * we are in multiprocessor format but uniprocessor system
- * or in the old uniprocessor format
- */
- cpuid_topo->thread_id = -1;
- cpuid_topo->core_id = 0;
- cpuid_topo->socket_id = -1;
- }
- cpuid_topo->partno = read_cpuid_part();
- topology_populated:
- update_siblings_masks(cpuid);
- update_cpu_capacity(cpuid);
- printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
- cpuid, cpu_topology[cpuid].thread_id,
- cpu_topology[cpuid].core_id,
- cpu_topology[cpuid].socket_id, mpidr);
- }
- static inline int cpu_corepower_flags(void)
- {
- return SD_SHARE_PKG_RESOURCES | SD_SHARE_POWERDOMAIN;
- }
- static struct sched_domain_topology_level arm_topology[] = {
- #ifdef CONFIG_SCHED_MC
- { cpu_corepower_mask, cpu_corepower_flags, SD_INIT_NAME(GMC) },
- { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
- #endif
- { cpu_cpu_mask, SD_INIT_NAME(DIE) },
- { NULL, },
- };
- #ifdef CONFIG_SCHED_HMP
- void __init arch_get_fast_and_slow_cpus(struct cpumask *fast,
- struct cpumask *slow)
- {
- unsigned int cpu;
- cpumask_clear(fast);
- cpumask_clear(slow);
- /*
- * Use the config options if they are given. This helps testing
- * HMP scheduling on systems without a big.LITTLE architecture.
- */
- if (strlen(CONFIG_HMP_FAST_CPU_MASK) && strlen(CONFIG_HMP_SLOW_CPU_MASK)) {
- if (cpulist_parse(CONFIG_HMP_FAST_CPU_MASK, fast))
- WARN(1, "Failed to parse HMP fast cpu mask!\n");
- if (cpulist_parse(CONFIG_HMP_SLOW_CPU_MASK, slow))
- WARN(1, "Failed to parse HMP slow cpu mask!\n");
- return;
- }
- /* check by capacity */
- for_each_possible_cpu(cpu) {
- if (cpu_capacity(cpu) > min_cpu_perf)
- cpumask_set_cpu(cpu, fast);
- else
- cpumask_set_cpu(cpu, slow);
- }
- if (!cpumask_empty(fast) && !cpumask_empty(slow))
- return;
- /*
- * We didn't find both big and little cores so let's call all cores
- * fast as this will keep the system running, with all cores being
- * treated equal.
- */
- cpumask_setall(slow);
- cpumask_clear(fast);
- }
- struct cpumask hmp_fast_cpu_mask;
- struct cpumask hmp_slow_cpu_mask;
- void __init arch_get_hmp_domains(struct list_head *hmp_domains_list)
- {
- struct hmp_domain *domain;
- arch_get_fast_and_slow_cpus(&hmp_fast_cpu_mask, &hmp_slow_cpu_mask);
- /*
- * Initialize hmp_domains
- * Must be ordered with respect to compute capacity.
- * Fastest domain at head of list.
- */
- if (!cpumask_empty(&hmp_slow_cpu_mask)) {
- domain = (struct hmp_domain *)
- kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
- cpumask_copy(&domain->possible_cpus, &hmp_slow_cpu_mask);
- cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
- list_add(&domain->hmp_domains, hmp_domains_list);
- }
- domain = (struct hmp_domain *)
- kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
- cpumask_copy(&domain->possible_cpus, &hmp_fast_cpu_mask);
- cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
- list_add(&domain->hmp_domains, hmp_domains_list);
- }
- #endif /* CONFIG_SCHED_HMP */
- static void __init reset_cpu_topology(void)
- {
- unsigned int cpu;
- /* init core mask and capacity */
- for_each_possible_cpu(cpu) {
- struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
- cpu_topo->thread_id = -1;
- cpu_topo->core_id = -1;
- cpu_topo->socket_id = -1;
- 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);
- set_capacity_scale(cpu, SCHED_CAPACITY_SCALE);
- }
- smp_wmb();
- }
- static int cpu_topology_init;
- /*
- * init_cpu_topology is called at boot when only one cpu is running
- * which prevent simultaneous write access to cpu_topology array
- */
- /*
- * init_cpu_topology is called at boot when only one cpu is running
- * which prevent simultaneous write access to cpu_topology array
- */
- void __init init_cpu_topology(void)
- {
- if (cpu_topology_init)
- return;
- reset_cpu_topology();
- /*
- * Discard anything that was parsed if we hit an error so we
- * don't use partial information.
- */
- if (parse_dt_topology())
- reset_cpu_topology();
- parse_dt_cpu_capacity();
- /* Set scheduler topology descriptor */
- set_sched_topology(arm_topology);
- }
- #ifdef CONFIG_MTK_CPU_TOPOLOGY
- void __init arch_build_cpu_topology_domain(void)
- {
- init_cpu_topology();
- cpu_topology_init = 1;
- }
- #endif
- /*
- * Extras of CPU & Cluster functions
- */
- int arch_cpu_is_big(unsigned int cpu)
- {
- struct cputopo_arm *arm_cputopo = &cpu_topology[cpu];
- switch (arm_cputopo->partno) {
- case ARM_CPU_PART_CORTEX_A12:
- case ARM_CPU_PART_CORTEX_A17:
- case ARM_CPU_PART_CORTEX_A15:
- return 1;
- default:
- return 0;
- }
- }
- int arch_cpu_is_little(unsigned int cpu)
- {
- return !arch_cpu_is_big(cpu);
- }
- int arch_is_smp(void)
- {
- static int __arch_smp = -1;
- if (__arch_smp != -1)
- return __arch_smp;
- __arch_smp = (max_cpu_perf != min_cpu_perf) ? 0 : 1;
- return __arch_smp;
- }
- int arch_get_nr_clusters(void)
- {
- static int __arch_nr_clusters = -1;
- int max_id = 0;
- unsigned int cpu;
- if (__arch_nr_clusters != -1)
- return __arch_nr_clusters;
- /* assume socket id is monotonic increasing without gap. */
- for_each_possible_cpu(cpu) {
- struct cputopo_arm *arm_cputopo = &cpu_topology[cpu];
- if (arm_cputopo->socket_id > max_id)
- max_id = arm_cputopo->socket_id;
- }
- __arch_nr_clusters = max_id + 1;
- return __arch_nr_clusters;
- }
- int arch_is_multi_cluster(void)
- {
- return arch_get_nr_clusters() > 1 ? 1 : 0;
- }
- int arch_get_cluster_id(unsigned int cpu)
- {
- struct cputopo_arm *arm_cputopo = &cpu_topology[cpu];
- return arm_cputopo->socket_id < 0 ? 0 : arm_cputopo->socket_id;
- }
- void arch_get_cluster_cpus(struct cpumask *cpus, int cluster_id)
- {
- unsigned int cpu;
- cpumask_clear(cpus);
- for_each_possible_cpu(cpu) {
- struct cputopo_arm *arm_cputopo = &cpu_topology[cpu];
- if (arm_cputopo->socket_id == cluster_id)
- cpumask_set_cpu(cpu, cpus);
- }
- }
- int arch_better_capacity(unsigned int cpu)
- {
- BUG_ON(cpu >= num_possible_cpus());
- return cpu_capacity(cpu) > min_cpu_perf;
- }
|