Hi,
arm and arm64 topology.c share a lot of code related to parsing of capacity
information. This is v3 of a solution [1] (based on Will's, Catalin's and
Mark's off-line suggestions) to move such common code in a single place:
drivers/base/arch_topology.c (by creating such file and conditionally compiling
it for arm and arm64 only).
First 4 patches are actually fixes for the current code.
Patch 5 is the actual refactoring.
Patch 6 is a minor change suggested by Greg and can be squashed as needed.
Patch 7 removes one of the extern symbols by changing a bit the now common
code.
Patch 8 removes the remaining externs (as required by Russell during v1 review)
by creating a new header file include/linux/arch_topology.h and including that
from arm, arm64 and drivers.
Last patch addresses Dietmar's comments to v1 and adds a 'atd_' prefix to
interfaces exported by drivers code and used by arch (and potentially others in
the future).
Changes from v2:
- rebase on top of 4.11-rc4
- fix various problems pointed out by Greg, thanks for the review!
(see patch 5 for details)
The set is based on top of linux/master (4.11-rc4 c02ed2e75ef4) and it is also
available from:
git://linux-arm.org/linux-jl.git upstream/default_caps_factorize-v3
Best,
- Juri
[1] v1 - https://marc.info/?l=linux-kernel&m=148483680119355&w=2
v2 - https://marc.info/?l=linux-kernel&m=148663344018205&w=2
Juri Lelli (9):
Documentation: arm: fix wrong reference number in DT definition
Documentation/ABI: add information about cpu_capacity
arm: fix return value of parse_cpu_capacity
arm: remove wrong CONFIG_PROC_SYSCTL ifdef
arm, arm64: factorize common cpu capacity default code
drivers: remove useless comment from base/arch_topology.c
arm,arm64,drivers: reduce scope of cap_parsing_failed
arm,arm64,drivers: move externs in a new header file
arm,arm64,drivers: add a prefix to drivers arch_topology interfaces
Documentation/ABI/testing/sysfs-devices-system-cpu | 7 +
Documentation/devicetree/bindings/arm/cpus.txt | 4 +-
arch/arm/Kconfig | 1 +
arch/arm/kernel/topology.c | 221 +------------------
arch/arm64/Kconfig | 1 +
arch/arm64/kernel/topology.c | 226 +------------------
drivers/base/Kconfig | 8 +
drivers/base/Makefile | 1 +
drivers/base/arch_topology.c | 241 +++++++++++++++++++++
include/linux/arch_topology.h | 17 ++
10 files changed, 288 insertions(+), 439 deletions(-)
create mode 100644 drivers/base/arch_topology.c
create mode 100644 include/linux/arch_topology.h
--
2.10.0
parse_cpu_capacity() has to return 0 on failure, but it currently returns
1 instead if raw_capacity kcalloc failed.
Fix it by removing the negation of the return value.
Cc: Russell King <[email protected]>
Reported-by: Morten Rasmussen <[email protected]>
Fixes: 06073ee26775 ('ARM: 8621/3: parse cpu capacity-dmips-mhz from DT')
Signed-off-by: Juri Lelli <[email protected]>
---
arch/arm/kernel/topology.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index f8a3ab82e77f..4e4af809606a 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -166,7 +166,7 @@ static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
if (!raw_capacity) {
pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
cap_parsing_failed = true;
- return !ret;
+ return ret;
}
}
capacity_scale = max(cpu_capacity, capacity_scale);
--
2.10.0
/sys/devices/system/cpu/cpu#/cpu_capacity describe information about
CPUs heterogeneity (ref. to Documentation/devicetree/bindings/arm/
cpu-capacity.txt).
Add such description.
Signed-off-by: Juri Lelli <[email protected]>
---
Documentation/ABI/testing/sysfs-devices-system-cpu | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 2a4a423d08e0..f3d5817c4ef0 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -366,3 +366,10 @@ Contact: Linux ARM Kernel Mailing list <[email protected]>
Description: AArch64 CPU registers
'identification' directory exposes the CPU ID registers for
identifying model and revision of the CPU.
+
+What: /sys/devices/system/cpu/cpu#/cpu_capacity
+Date: December 2016
+Contact: Linux kernel mailing list <[email protected]>
+Description: information about CPUs heterogeneity.
+
+ cpu_capacity: capacity of cpu#.
--
2.10.0
Reference to cpu capacity binding has a wrong number. Fix it.
Reported-by: Lorenzo Pieralisi <[email protected]>
Signed-off-by: Juri Lelli <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/arm/cpus.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 698ad1f097fa..83ec3fa0a05e 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -248,7 +248,7 @@ nodes to be present and contain the properties described below.
Usage: Optional
Value type: <u32>
Definition:
- # u32 value representing CPU capacity [3] in
+ # u32 value representing CPU capacity [4] in
DMIPS/MHz, relative to highest capacity-dmips-mhz
in the system.
@@ -475,5 +475,5 @@ cpus {
[2] arm/msm/qcom,kpss-acc.txt
[3] ARM Linux kernel documentation - idle states bindings
Documentation/devicetree/bindings/arm/idle-states.txt
-[3] ARM Linux kernel documentation - cpu capacity bindings
+[4] ARM Linux kernel documentation - cpu capacity bindings
Documentation/devicetree/bindings/arm/cpu-capacity.txt
--
2.10.0
Reduce the scope of cap_parsing_failed (making it static in
drivers/base/arch_topology.c) by slightly changing {arm,arm64} DT
parsing code.
For arm checking for !cap_parsing_failed before calling normalize_
cpu_capacity() is superfluous, as returning an error from parse_
cpu_capacity() (above) means cap_from _dt is set to false.
For arm64 we can simply check if raw_capacity points to something,
which is not if capacity parsing has failed.
Suggested-by: Morten Rasmussen <[email protected]>
Signed-off-by: Juri Lelli <[email protected]>
---
arch/arm/kernel/topology.c | 3 +--
arch/arm64/kernel/topology.c | 5 +----
drivers/base/arch_topology.c | 4 ++--
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 49ef025ffaa0..1e35a3265ddf 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -76,7 +76,6 @@ static unsigned long *__cpu_capacity;
static unsigned long middle_capacity = 1;
static bool cap_from_dt = true;
-extern bool cap_parsing_failed;
extern void normalize_cpu_capacity(void);
extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
@@ -165,7 +164,7 @@ static void __init parse_dt_topology(void)
middle_capacity = ((max_capacity / 3)
>> (SCHED_CAPACITY_SHIFT-1)) + 1;
- if (cap_from_dt && !cap_parsing_failed)
+ if (cap_from_dt)
normalize_cpu_capacity();
}
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index c5bc31eb97e8..7e1f6f75185b 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -27,7 +27,6 @@
#include <asm/cputype.h>
#include <asm/topology.h>
-extern bool cap_parsing_failed;
extern void normalize_cpu_capacity(void);
extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
@@ -187,10 +186,8 @@ static int __init parse_dt_topology(void)
* cluster with restricted subnodes.
*/
map = of_get_child_by_name(cn, "cpu-map");
- if (!map) {
- cap_parsing_failed = true;
+ if (!map)
goto out;
- }
ret = parse_cluster(map, 0);
if (ret != 0)
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index b24d9a2af2c5..6543a032b332 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -93,7 +93,7 @@ subsys_initcall(register_cpu_capacity_sysctl);
static u32 capacity_scale;
static u32 *raw_capacity;
-bool cap_parsing_failed;
+static bool cap_parsing_failed;
void normalize_cpu_capacity(void)
{
@@ -208,7 +208,7 @@ static int __init register_cpufreq_notifier(void)
* until we have the necessary code to parse the cpu capacity, so
* skip registering cpufreq notifier.
*/
- if (!acpi_disabled || cap_parsing_failed)
+ if (!acpi_disabled || !raw_capacity)
return -EINVAL;
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
--
2.10.0
Printing out an error message when we failed to get the cpu device is
not helping anyone. Remove it.
Signed-off-by: Juri Lelli <[email protected]>
---
drivers/base/arch_topology.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index c33482121b7d..b24d9a2af2c5 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -81,11 +81,9 @@ static int register_cpu_capacity_sysctl(void)
for_each_possible_cpu(i) {
cpu = get_cpu_device(i);
- if (!cpu) {
- pr_err("%s: too early to get CPU%d device!\n",
- __func__, i);
+ if (!cpu)
continue;
- }
+
device_create_file(cpu, &dev_attr_cpu_capacity);
}
--
2.10.0
The sysfs cpu_capacity entry for each CPU has nothing to do with
PROC_FS, nor it's in /proc/sys path.
Remove such ifdef.
Cc: Russell King <[email protected]>
Reported-and-suggested-by: Sudeep Holla <[email protected]>
Fixes: 7e5930aaef5d ('ARM: 8622/3: add sysfs cpu_capacity attribute')
Signed-off-by: Juri Lelli <[email protected]>
---
arch/arm/kernel/topology.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 4e4af809606a..162c82aeed96 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -57,7 +57,6 @@ static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
per_cpu(cpu_scale, cpu) = capacity;
}
-#ifdef CONFIG_PROC_SYSCTL
static ssize_t cpu_capacity_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -114,7 +113,6 @@ static int register_cpu_capacity_sysctl(void)
return 0;
}
subsys_initcall(register_cpu_capacity_sysctl);
-#endif
#ifdef CONFIG_OF
struct cpu_efficiency {
--
2.10.0
Now that some functions that deal with arch topology information live
under drivers, there is a clash of naming that might create confusion.
Tidy things up by creating a drivers namespace for interfaces used by
arch code; achieve this by prepending a 'atd_' (arch topology driver)
prefix to driver interfaces.
Signed-off-by: Juri Lelli <[email protected]>
---
arch/arm/kernel/topology.c | 8 ++++----
arch/arm64/kernel/topology.c | 4 ++--
drivers/base/arch_topology.c | 20 ++++++++++----------
include/linux/arch_topology.h | 8 ++++----
4 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 557be4f1d2d7..e53391026c1b 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -111,7 +111,7 @@ static void __init parse_dt_topology(void)
continue;
}
- if (parse_cpu_capacity(cn, cpu)) {
+ if (atd_parse_cpu_capacity(cn, cpu)) {
of_node_put(cn);
continue;
}
@@ -160,7 +160,7 @@ static void __init parse_dt_topology(void)
>> (SCHED_CAPACITY_SHIFT-1)) + 1;
if (cap_from_dt)
- normalize_cpu_capacity();
+ atd_normalize_cpu_capacity();
}
/*
@@ -173,10 +173,10 @@ static void update_cpu_capacity(unsigned int cpu)
if (!cpu_capacity(cpu) || cap_from_dt)
return;
- set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
+ atd_set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
pr_info("CPU%u: update cpu_capacity %lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
+ cpu, atd_scale_cpu_capacity(NULL, cpu));
}
#else
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 255230c3e835..5f24faa09c05 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -39,7 +39,7 @@ static int __init get_cpu_for_node(struct device_node *node)
for_each_possible_cpu(cpu) {
if (of_get_cpu_node(cpu, NULL) == cpu_node) {
- parse_cpu_capacity(cpu_node, cpu);
+ atd_parse_cpu_capacity(cpu_node, cpu);
of_node_put(cpu_node);
return cpu;
}
@@ -191,7 +191,7 @@ static int __init parse_dt_topology(void)
if (ret != 0)
goto out_map;
- normalize_cpu_capacity();
+ atd_normalize_cpu_capacity();
/*
* Check that all cores are in the topology; the SMP code will
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 0fc77fa900a9..87dca3320536 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -25,12 +25,12 @@
static DEFINE_MUTEX(cpu_scale_mutex);
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
-unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
+unsigned long atd_scale_cpu_capacity(struct sched_domain *sd, int cpu)
{
return per_cpu(cpu_scale, cpu);
}
-void set_capacity_scale(unsigned int cpu, unsigned long capacity)
+void atd_set_capacity_scale(unsigned int cpu, unsigned long capacity)
{
per_cpu(cpu_scale, cpu) = capacity;
}
@@ -42,7 +42,7 @@ static ssize_t cpu_capacity_show(struct device *dev,
struct cpu *cpu = container_of(dev, struct cpu, dev);
return sprintf(buf, "%lu\n",
- arch_scale_cpu_capacity(NULL, cpu->dev.id));
+ atd_scale_cpu_capacity(NULL, cpu->dev.id));
}
static ssize_t cpu_capacity_store(struct device *dev,
@@ -67,7 +67,7 @@ static ssize_t cpu_capacity_store(struct device *dev,
mutex_lock(&cpu_scale_mutex);
for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
- set_capacity_scale(i, new_capacity);
+ atd_set_capacity_scale(i, new_capacity);
mutex_unlock(&cpu_scale_mutex);
return count;
@@ -96,7 +96,7 @@ static u32 capacity_scale;
static u32 *raw_capacity;
static bool cap_parsing_failed;
-void normalize_cpu_capacity(void)
+void atd_normalize_cpu_capacity(void)
{
u64 capacity;
int cpu;
@@ -111,14 +111,14 @@ void normalize_cpu_capacity(void)
cpu, raw_capacity[cpu]);
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
/ capacity_scale;
- set_capacity_scale(cpu, capacity);
+ atd_set_capacity_scale(cpu, capacity);
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
+ cpu, atd_scale_cpu_capacity(NULL, cpu));
}
mutex_unlock(&cpu_scale_mutex);
}
-int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
+int __init atd_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
{
int ret = 1;
u32 cpu_capacity;
@@ -183,12 +183,12 @@ init_cpu_capacity_callback(struct notifier_block *nb,
cpus_to_visit,
policy->related_cpus);
for_each_cpu(cpu, policy->related_cpus) {
- raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
+ raw_capacity[cpu] = atd_scale_cpu_capacity(NULL, cpu) *
policy->cpuinfo.max_freq / 1000UL;
capacity_scale = max(raw_capacity[cpu], capacity_scale);
}
if (cpumask_empty(cpus_to_visit)) {
- normalize_cpu_capacity();
+ atd_normalize_cpu_capacity();
kfree(raw_capacity);
pr_debug("cpu_capacity: parsing done\n");
cap_parsing_done = true;
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
index 4edae9fe8cdd..e25458d7ee9a 100644
--- a/include/linux/arch_topology.h
+++ b/include/linux/arch_topology.h
@@ -4,14 +4,14 @@
#ifndef _LINUX_ARCH_TOPOLOGY_H_
#define _LINUX_ARCH_TOPOLOGY_H_
-void normalize_cpu_capacity(void);
+void atd_normalize_cpu_capacity(void);
struct device_node;
-int parse_cpu_capacity(struct device_node *cpu_node, int cpu);
+int atd_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
struct sched_domain;
-unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
+unsigned long atd_scale_cpu_capacity(struct sched_domain *sd, int cpu);
-void set_capacity_scale(unsigned int cpu, unsigned long capacity);
+void atd_set_capacity_scale(unsigned int cpu, unsigned long capacity);
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
--
2.10.0
arm and arm64 share lot of code relative to parsing CPU capacity
information from DT, using that information for appropriate scaling and
exposing a sysfs interface for chaging such values at runtime.
Factorize such code in a common place (driver/base/arch_topology.c) in
preparation for further additions.
Suggested-by: Will Deacon <[email protected]>
Suggested-by: Mark Rutland <[email protected]>
Suggested-by: Catalin Marinas <[email protected]>
Cc: Russell King <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Juri Lelli <[email protected]>
---
Changes from v2:
- make capacity_scale and raw_capacity static
- added SPDX header
- improved indent
- misc. whitespaces/newlines fixes
Changes from v1:
- keep the original GPLv2 header
---
arch/arm/Kconfig | 1 +
arch/arm/kernel/topology.c | 213 ++-----------------------------------
arch/arm64/Kconfig | 1 +
arch/arm64/kernel/topology.c | 219 +--------------------------------------
drivers/base/Kconfig | 8 ++
drivers/base/Makefile | 1 +
drivers/base/arch_topology.c | 242 +++++++++++++++++++++++++++++++++++++++++++
7 files changed, 262 insertions(+), 423 deletions(-)
create mode 100644 drivers/base/arch_topology.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0d4e71b42c77..cd61154bb6d0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -25,6 +25,7 @@ config ARM
select EDAC_SUPPORT
select EDAC_ATOMIC_SCRUB
select GENERIC_ALLOCATOR
+ select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY
select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_EARLY_IOREMAP
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 162c82aeed96..49ef025ffaa0 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -44,75 +44,10 @@
* 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) = SCHED_CAPACITY_SCALE;
-static DEFINE_MUTEX(cpu_scale_mutex);
-unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, 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;
-}
-
-static ssize_t cpu_capacity_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
-
- return sprintf(buf, "%lu\n",
- arch_scale_cpu_capacity(NULL, cpu->dev.id));
-}
-
-static ssize_t cpu_capacity_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int this_cpu = cpu->dev.id, i;
- unsigned long new_capacity;
- ssize_t ret;
-
- if (count) {
- ret = kstrtoul(buf, 0, &new_capacity);
- if (ret)
- return ret;
- if (new_capacity > SCHED_CAPACITY_SCALE)
- return -EINVAL;
-
- mutex_lock(&cpu_scale_mutex);
- for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
- set_capacity_scale(i, new_capacity);
- mutex_unlock(&cpu_scale_mutex);
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(cpu_capacity);
-
-static int register_cpu_capacity_sysctl(void)
-{
- int i;
- struct device *cpu;
-
- for_each_possible_cpu(i) {
- cpu = get_cpu_device(i);
- if (!cpu) {
- pr_err("%s: too early to get CPU%d device!\n",
- __func__, i);
- continue;
- }
- device_create_file(cpu, &dev_attr_cpu_capacity);
- }
-
- return 0;
-}
-subsys_initcall(register_cpu_capacity_sysctl);
+extern unsigned long
+arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
+extern void set_capacity_scale(unsigned int cpu, unsigned long capacity);
#ifdef CONFIG_OF
struct cpu_efficiency {
@@ -141,145 +76,9 @@ static unsigned long *__cpu_capacity;
static unsigned long middle_capacity = 1;
static bool cap_from_dt = true;
-static u32 *raw_capacity;
-static bool cap_parsing_failed;
-static u32 capacity_scale;
-
-static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
-{
- int ret = 1;
- u32 cpu_capacity;
-
- if (cap_parsing_failed)
- return !ret;
-
- ret = of_property_read_u32(cpu_node,
- "capacity-dmips-mhz",
- &cpu_capacity);
- if (!ret) {
- if (!raw_capacity) {
- raw_capacity = kcalloc(num_possible_cpus(),
- sizeof(*raw_capacity),
- GFP_KERNEL);
- if (!raw_capacity) {
- pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
- cap_parsing_failed = true;
- return ret;
- }
- }
- capacity_scale = max(cpu_capacity, capacity_scale);
- raw_capacity[cpu] = cpu_capacity;
- pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
- cpu_node->full_name, raw_capacity[cpu]);
- } else {
- if (raw_capacity) {
- pr_err("cpu_capacity: missing %s raw capacity\n",
- cpu_node->full_name);
- pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
- }
- cap_parsing_failed = true;
- kfree(raw_capacity);
- }
-
- return !ret;
-}
-
-static void normalize_cpu_capacity(void)
-{
- u64 capacity;
- int cpu;
-
- if (!raw_capacity || cap_parsing_failed)
- return;
-
- pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
- mutex_lock(&cpu_scale_mutex);
- for_each_possible_cpu(cpu) {
- capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
- / capacity_scale;
- set_capacity_scale(cpu, capacity);
- pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
- }
- mutex_unlock(&cpu_scale_mutex);
-}
-
-#ifdef CONFIG_CPU_FREQ
-static cpumask_var_t cpus_to_visit;
-static bool cap_parsing_done;
-static void parsing_done_workfn(struct work_struct *work);
-static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
-
-static int
-init_cpu_capacity_callback(struct notifier_block *nb,
- unsigned long val,
- void *data)
-{
- struct cpufreq_policy *policy = data;
- int cpu;
-
- if (cap_parsing_failed || cap_parsing_done)
- return 0;
-
- switch (val) {
- case CPUFREQ_NOTIFY:
- pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
- cpumask_pr_args(policy->related_cpus),
- cpumask_pr_args(cpus_to_visit));
- cpumask_andnot(cpus_to_visit,
- cpus_to_visit,
- policy->related_cpus);
- for_each_cpu(cpu, policy->related_cpus) {
- raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
- policy->cpuinfo.max_freq / 1000UL;
- capacity_scale = max(raw_capacity[cpu], capacity_scale);
- }
- if (cpumask_empty(cpus_to_visit)) {
- normalize_cpu_capacity();
- kfree(raw_capacity);
- pr_debug("cpu_capacity: parsing done\n");
- cap_parsing_done = true;
- schedule_work(&parsing_done_work);
- }
- }
- return 0;
-}
-
-static struct notifier_block init_cpu_capacity_notifier = {
- .notifier_call = init_cpu_capacity_callback,
-};
-
-static int __init register_cpufreq_notifier(void)
-{
- if (cap_parsing_failed)
- return -EINVAL;
-
- if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
- pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
- return -ENOMEM;
- }
- cpumask_copy(cpus_to_visit, cpu_possible_mask);
-
- return cpufreq_register_notifier(&init_cpu_capacity_notifier,
- CPUFREQ_POLICY_NOTIFIER);
-}
-core_initcall(register_cpufreq_notifier);
-
-static void parsing_done_workfn(struct work_struct *work)
-{
- cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
- CPUFREQ_POLICY_NOTIFIER);
-}
-
-#else
-static int __init free_raw_capacity(void)
-{
- kfree(raw_capacity);
-
- return 0;
-}
-core_initcall(free_raw_capacity);
-#endif
+extern bool cap_parsing_failed;
+extern void normalize_cpu_capacity(void);
+extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
/*
* Iterate all CPUs' descriptor in DT and compute the efficiency
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3741859765cf..e36fb12afad6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -40,6 +40,7 @@ config ARM64
select EDAC_SUPPORT
select FRAME_POINTER
select GENERIC_ALLOCATOR
+ select GENERIC_ARCH_TOPOLOGY
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_CPU_AUTOPROBE
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 08243533e5ee..c5bc31eb97e8 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -11,7 +11,6 @@
* for more details.
*/
-#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -23,226 +22,14 @@
#include <linux/sched/topology.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/cpufreq.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/topology.h>
-static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
-static DEFINE_MUTEX(cpu_scale_mutex);
-
-unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, 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;
-}
-
-static ssize_t cpu_capacity_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
-
- return sprintf(buf, "%lu\n",
- arch_scale_cpu_capacity(NULL, cpu->dev.id));
-}
-
-static ssize_t cpu_capacity_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int this_cpu = cpu->dev.id, i;
- unsigned long new_capacity;
- ssize_t ret;
-
- if (count) {
- ret = kstrtoul(buf, 0, &new_capacity);
- if (ret)
- return ret;
- if (new_capacity > SCHED_CAPACITY_SCALE)
- return -EINVAL;
-
- mutex_lock(&cpu_scale_mutex);
- for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
- set_capacity_scale(i, new_capacity);
- mutex_unlock(&cpu_scale_mutex);
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(cpu_capacity);
-
-static int register_cpu_capacity_sysctl(void)
-{
- int i;
- struct device *cpu;
-
- for_each_possible_cpu(i) {
- cpu = get_cpu_device(i);
- if (!cpu) {
- pr_err("%s: too early to get CPU%d device!\n",
- __func__, i);
- continue;
- }
- device_create_file(cpu, &dev_attr_cpu_capacity);
- }
-
- return 0;
-}
-subsys_initcall(register_cpu_capacity_sysctl);
-
-static u32 capacity_scale;
-static u32 *raw_capacity;
-static bool cap_parsing_failed;
-
-static void __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
-{
- int ret;
- u32 cpu_capacity;
-
- if (cap_parsing_failed)
- return;
-
- ret = of_property_read_u32(cpu_node,
- "capacity-dmips-mhz",
- &cpu_capacity);
- if (!ret) {
- if (!raw_capacity) {
- raw_capacity = kcalloc(num_possible_cpus(),
- sizeof(*raw_capacity),
- GFP_KERNEL);
- if (!raw_capacity) {
- pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
- cap_parsing_failed = true;
- return;
- }
- }
- capacity_scale = max(cpu_capacity, capacity_scale);
- raw_capacity[cpu] = cpu_capacity;
- pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
- cpu_node->full_name, raw_capacity[cpu]);
- } else {
- if (raw_capacity) {
- pr_err("cpu_capacity: missing %s raw capacity\n",
- cpu_node->full_name);
- pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
- }
- cap_parsing_failed = true;
- kfree(raw_capacity);
- }
-}
-
-static void normalize_cpu_capacity(void)
-{
- u64 capacity;
- int cpu;
-
- if (!raw_capacity || cap_parsing_failed)
- return;
-
- pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
- mutex_lock(&cpu_scale_mutex);
- for_each_possible_cpu(cpu) {
- pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
- cpu, raw_capacity[cpu]);
- capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
- / capacity_scale;
- set_capacity_scale(cpu, capacity);
- pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
- }
- mutex_unlock(&cpu_scale_mutex);
-}
-
-#ifdef CONFIG_CPU_FREQ
-static cpumask_var_t cpus_to_visit;
-static bool cap_parsing_done;
-static void parsing_done_workfn(struct work_struct *work);
-static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
-
-static int
-init_cpu_capacity_callback(struct notifier_block *nb,
- unsigned long val,
- void *data)
-{
- struct cpufreq_policy *policy = data;
- int cpu;
-
- if (cap_parsing_failed || cap_parsing_done)
- return 0;
-
- switch (val) {
- case CPUFREQ_NOTIFY:
- pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
- cpumask_pr_args(policy->related_cpus),
- cpumask_pr_args(cpus_to_visit));
- cpumask_andnot(cpus_to_visit,
- cpus_to_visit,
- policy->related_cpus);
- for_each_cpu(cpu, policy->related_cpus) {
- raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
- policy->cpuinfo.max_freq / 1000UL;
- capacity_scale = max(raw_capacity[cpu], capacity_scale);
- }
- if (cpumask_empty(cpus_to_visit)) {
- normalize_cpu_capacity();
- kfree(raw_capacity);
- pr_debug("cpu_capacity: parsing done\n");
- cap_parsing_done = true;
- schedule_work(&parsing_done_work);
- }
- }
- return 0;
-}
-
-static struct notifier_block init_cpu_capacity_notifier = {
- .notifier_call = init_cpu_capacity_callback,
-};
-
-static int __init register_cpufreq_notifier(void)
-{
- /*
- * on ACPI-based systems we need to use the default cpu capacity
- * until we have the necessary code to parse the cpu capacity, so
- * skip registering cpufreq notifier.
- */
- if (!acpi_disabled || cap_parsing_failed)
- return -EINVAL;
-
- if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
- pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
- return -ENOMEM;
- }
- cpumask_copy(cpus_to_visit, cpu_possible_mask);
-
- return cpufreq_register_notifier(&init_cpu_capacity_notifier,
- CPUFREQ_POLICY_NOTIFIER);
-}
-core_initcall(register_cpufreq_notifier);
-
-static void parsing_done_workfn(struct work_struct *work)
-{
- cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
- CPUFREQ_POLICY_NOTIFIER);
-}
-
-#else
-static int __init free_raw_capacity(void)
-{
- kfree(raw_capacity);
-
- return 0;
-}
-core_initcall(free_raw_capacity);
-#endif
+extern bool cap_parsing_failed;
+extern void normalize_cpu_capacity(void);
+extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
static int __init get_cpu_for_node(struct device_node *node)
{
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d718ae4b907a..f046d21de57d 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -339,4 +339,12 @@ config CMA_ALIGNMENT
endif
+config GENERIC_ARCH_TOPOLOGY
+ bool
+ help
+ Enable support for architectures common topology code: e.g., parsing
+ CPU capacity information from DT, usage of such information for
+ appropriate scaling, sysfs interface for changing capacity values at
+ runtime.
+
endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index f2816f6ff76a..397e5c344e6a 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SOC_BUS) += soc.o
obj-$(CONFIG_PINCTRL) += pinctrl.o
obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o
obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o
+obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o
obj-y += test/
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
new file mode 100644
index 000000000000..c33482121b7d
--- /dev/null
+++ b/drivers/base/arch_topology.c
@@ -0,0 +1,242 @@
+/*
+ * Arch specific cpu topology information
+ *
+ * Copyright (C) 2016, ARM Ltd.
+ * Written by: Juri Lelli, ARM Ltd.
+ *
+ * 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.
+ *
+ * Released under the GPLv2 only.
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/acpi.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sched/topology.h>
+
+static DEFINE_MUTEX(cpu_scale_mutex);
+static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
+
+unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
+{
+ return per_cpu(cpu_scale, cpu);
+}
+
+void set_capacity_scale(unsigned int cpu, unsigned long capacity)
+{
+ per_cpu(cpu_scale, cpu) = capacity;
+}
+
+static ssize_t cpu_capacity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cpu *cpu = container_of(dev, struct cpu, dev);
+
+ return sprintf(buf, "%lu\n",
+ arch_scale_cpu_capacity(NULL, cpu->dev.id));
+}
+
+static ssize_t cpu_capacity_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int this_cpu = cpu->dev.id;
+ int i;
+ unsigned long new_capacity;
+ ssize_t ret;
+
+ if (!count)
+ return 0;
+
+ ret = kstrtoul(buf, 0, &new_capacity);
+ if (ret)
+ return ret;
+ if (new_capacity > SCHED_CAPACITY_SCALE)
+ return -EINVAL;
+
+ mutex_lock(&cpu_scale_mutex);
+ for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
+ set_capacity_scale(i, new_capacity);
+ mutex_unlock(&cpu_scale_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(cpu_capacity);
+
+static int register_cpu_capacity_sysctl(void)
+{
+ int i;
+ struct device *cpu;
+
+ for_each_possible_cpu(i) {
+ cpu = get_cpu_device(i);
+ if (!cpu) {
+ pr_err("%s: too early to get CPU%d device!\n",
+ __func__, i);
+ continue;
+ }
+ device_create_file(cpu, &dev_attr_cpu_capacity);
+ }
+
+ return 0;
+}
+subsys_initcall(register_cpu_capacity_sysctl);
+
+static u32 capacity_scale;
+static u32 *raw_capacity;
+bool cap_parsing_failed;
+
+void normalize_cpu_capacity(void)
+{
+ u64 capacity;
+ int cpu;
+
+ if (!raw_capacity || cap_parsing_failed)
+ return;
+
+ pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
+ mutex_lock(&cpu_scale_mutex);
+ for_each_possible_cpu(cpu) {
+ pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
+ cpu, raw_capacity[cpu]);
+ capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
+ / capacity_scale;
+ set_capacity_scale(cpu, capacity);
+ pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
+ cpu, arch_scale_cpu_capacity(NULL, cpu));
+ }
+ mutex_unlock(&cpu_scale_mutex);
+}
+
+int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
+{
+ int ret = 1;
+ u32 cpu_capacity;
+
+ if (cap_parsing_failed)
+ return !ret;
+
+ ret = of_property_read_u32(cpu_node,
+ "capacity-dmips-mhz",
+ &cpu_capacity);
+ if (!ret) {
+ if (!raw_capacity) {
+ raw_capacity = kcalloc(num_possible_cpus(),
+ sizeof(*raw_capacity),
+ GFP_KERNEL);
+ if (!raw_capacity) {
+ pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
+ cap_parsing_failed = true;
+ return ret;
+ }
+ }
+ capacity_scale = max(cpu_capacity, capacity_scale);
+ raw_capacity[cpu] = cpu_capacity;
+ pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",
+ cpu_node->full_name, raw_capacity[cpu]);
+ } else {
+ if (raw_capacity) {
+ pr_err("cpu_capacity: missing %s raw capacity\n",
+ cpu_node->full_name);
+ pr_err("cpu_capacity: partial information: fallback to 1024 for all CPUs\n");
+ }
+ cap_parsing_failed = true;
+ kfree(raw_capacity);
+ }
+
+ return !ret;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static cpumask_var_t cpus_to_visit;
+static bool cap_parsing_done;
+static void parsing_done_workfn(struct work_struct *work);
+static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
+
+static int
+init_cpu_capacity_callback(struct notifier_block *nb,
+ unsigned long val,
+ void *data)
+{
+ struct cpufreq_policy *policy = data;
+ int cpu;
+
+ if (cap_parsing_failed || cap_parsing_done)
+ return 0;
+
+ switch (val) {
+ case CPUFREQ_NOTIFY:
+ pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
+ cpumask_pr_args(policy->related_cpus),
+ cpumask_pr_args(cpus_to_visit));
+ cpumask_andnot(cpus_to_visit,
+ cpus_to_visit,
+ policy->related_cpus);
+ for_each_cpu(cpu, policy->related_cpus) {
+ raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
+ policy->cpuinfo.max_freq / 1000UL;
+ capacity_scale = max(raw_capacity[cpu], capacity_scale);
+ }
+ if (cpumask_empty(cpus_to_visit)) {
+ normalize_cpu_capacity();
+ kfree(raw_capacity);
+ pr_debug("cpu_capacity: parsing done\n");
+ cap_parsing_done = true;
+ schedule_work(&parsing_done_work);
+ }
+ }
+ return 0;
+}
+
+static struct notifier_block init_cpu_capacity_notifier = {
+ .notifier_call = init_cpu_capacity_callback,
+};
+
+static int __init register_cpufreq_notifier(void)
+{
+ /*
+ * on ACPI-based systems we need to use the default cpu capacity
+ * until we have the necessary code to parse the cpu capacity, so
+ * skip registering cpufreq notifier.
+ */
+ if (!acpi_disabled || cap_parsing_failed)
+ return -EINVAL;
+
+ if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
+ pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
+ return -ENOMEM;
+ }
+
+ cpumask_copy(cpus_to_visit, cpu_possible_mask);
+
+ return cpufreq_register_notifier(&init_cpu_capacity_notifier,
+ CPUFREQ_POLICY_NOTIFIER);
+}
+core_initcall(register_cpufreq_notifier);
+
+static void parsing_done_workfn(struct work_struct *work)
+{
+ cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
+ CPUFREQ_POLICY_NOTIFIER);
+}
+
+#else
+static int __init free_raw_capacity(void)
+{
+ kfree(raw_capacity);
+
+ return 0;
+}
+core_initcall(free_raw_capacity);
+#endif
--
2.10.0
Create a new header file (include/linux/arch_topology.h) and put there
declarations of interfaces used by arm, arm64 and drivers code.
Signed-off-by: Juri Lelli <[email protected]>
---
arch/arm/kernel/topology.c | 7 +------
arch/arm64/kernel/topology.c | 4 +---
drivers/base/arch_topology.c | 1 +
include/linux/arch_topology.h | 17 +++++++++++++++++
4 files changed, 20 insertions(+), 9 deletions(-)
create mode 100644 include/linux/arch_topology.h
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 1e35a3265ddf..557be4f1d2d7 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -11,6 +11,7 @@
* for more details.
*/
+#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
@@ -45,10 +46,6 @@
* updated during this sequence.
*/
-extern unsigned long
-arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
-extern void set_capacity_scale(unsigned int cpu, unsigned long capacity);
-
#ifdef CONFIG_OF
struct cpu_efficiency {
const char *compatible;
@@ -76,8 +73,6 @@ static unsigned long *__cpu_capacity;
static unsigned long middle_capacity = 1;
static bool cap_from_dt = true;
-extern void normalize_cpu_capacity(void);
-extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
/*
* Iterate all CPUs' descriptor in DT and compute the efficiency
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 7e1f6f75185b..255230c3e835 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -11,6 +11,7 @@
* for more details.
*/
+#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -27,9 +28,6 @@
#include <asm/cputype.h>
#include <asm/topology.h>
-extern void normalize_cpu_capacity(void);
-extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
-
static int __init get_cpu_for_node(struct device_node *node)
{
struct device_node *cpu_node;
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 6543a032b332..0fc77fa900a9 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -13,6 +13,7 @@
*/
#include <linux/acpi.h>
+#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
new file mode 100644
index 000000000000..4edae9fe8cdd
--- /dev/null
+++ b/include/linux/arch_topology.h
@@ -0,0 +1,17 @@
+/*
+ * include/linux/arch_topology.h - arch specific cpu topology information
+ */
+#ifndef _LINUX_ARCH_TOPOLOGY_H_
+#define _LINUX_ARCH_TOPOLOGY_H_
+
+void normalize_cpu_capacity(void);
+
+struct device_node;
+int parse_cpu_capacity(struct device_node *cpu_node, int cpu);
+
+struct sched_domain;
+unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
+
+void set_capacity_scale(unsigned int cpu, unsigned long capacity);
+
+#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
--
2.10.0
On 27 March 2017 at 15:18, Juri Lelli <[email protected]> wrote:
> parse_cpu_capacity() has to return 0 on failure, but it currently returns
> 1 instead if raw_capacity kcalloc failed.
>
> Fix it by removing the negation of the return value.
>
> Cc: Russell King <[email protected]>
> Reported-by: Morten Rasmussen <[email protected]>
> Fixes: 06073ee26775 ('ARM: 8621/3: parse cpu capacity-dmips-mhz from DT')
> Signed-off-by: Juri Lelli <[email protected]>
> ---
> arch/arm/kernel/topology.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> index f8a3ab82e77f..4e4af809606a 100644
> --- a/arch/arm/kernel/topology.c
> +++ b/arch/arm/kernel/topology.c
> @@ -166,7 +166,7 @@ static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
> if (!raw_capacity) {
> pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
> cap_parsing_failed = true;
> - return !ret;
> + return ret;
Why not directly returning 0 ? whatever the value of ret, the parse of
cpu capacity has failed in this case
> }
> }
> capacity_scale = max(cpu_capacity, capacity_scale);
> --
> 2.10.0
>
On 27 March 2017 at 15:18, Juri Lelli <[email protected]> wrote:
> The sysfs cpu_capacity entry for each CPU has nothing to do with
> PROC_FS, nor it's in /proc/sys path.
>
> Remove such ifdef.
>
> Cc: Russell King <[email protected]>
> Reported-and-suggested-by: Sudeep Holla <[email protected]>
> Fixes: 7e5930aaef5d ('ARM: 8622/3: add sysfs cpu_capacity attribute')
> Signed-off-by: Juri Lelli <[email protected]>
Acked-by: Vincent Guittot <[email protected]>
> ---
> arch/arm/kernel/topology.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> index 4e4af809606a..162c82aeed96 100644
> --- a/arch/arm/kernel/topology.c
> +++ b/arch/arm/kernel/topology.c
> @@ -57,7 +57,6 @@ static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
> per_cpu(cpu_scale, cpu) = capacity;
> }
>
> -#ifdef CONFIG_PROC_SYSCTL
> static ssize_t cpu_capacity_show(struct device *dev,
> struct device_attribute *attr,
> char *buf)
> @@ -114,7 +113,6 @@ static int register_cpu_capacity_sysctl(void)
> return 0;
> }
> subsys_initcall(register_cpu_capacity_sysctl);
> -#endif
>
> #ifdef CONFIG_OF
> struct cpu_efficiency {
> --
> 2.10.0
>
On 29/03/17 09:37, Vincent Guittot wrote:
> On 27 March 2017 at 15:18, Juri Lelli <[email protected]> wrote:
> > parse_cpu_capacity() has to return 0 on failure, but it currently returns
> > 1 instead if raw_capacity kcalloc failed.
> >
> > Fix it by removing the negation of the return value.
> >
> > Cc: Russell King <[email protected]>
> > Reported-by: Morten Rasmussen <[email protected]>
> > Fixes: 06073ee26775 ('ARM: 8621/3: parse cpu capacity-dmips-mhz from DT')
> > Signed-off-by: Juri Lelli <[email protected]>
> > ---
> > arch/arm/kernel/topology.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> > index f8a3ab82e77f..4e4af809606a 100644
> > --- a/arch/arm/kernel/topology.c
> > +++ b/arch/arm/kernel/topology.c
> > @@ -166,7 +166,7 @@ static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
> > if (!raw_capacity) {
> > pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
> > cap_parsing_failed = true;
> > - return !ret;
> > + return ret;
>
> Why not directly returning 0 ? whatever the value of ret, the parse of
> cpu capacity has failed in this case
>
Sure, can change that.
Thanks,
- Juri
Hi,
On 27/03/17 14:18, Juri Lelli wrote:
> Hi,
>
> arm and arm64 topology.c share a lot of code related to parsing of capacity
> information. This is v3 of a solution [1] (based on Will's, Catalin's and
> Mark's off-line suggestions) to move such common code in a single place:
> drivers/base/arch_topology.c (by creating such file and conditionally compiling
> it for arm and arm64 only).
>
> First 4 patches are actually fixes for the current code.
>
> Patch 5 is the actual refactoring.
>
> Patch 6 is a minor change suggested by Greg and can be squashed as needed.
>
> Patch 7 removes one of the extern symbols by changing a bit the now common
> code.
>
> Patch 8 removes the remaining externs (as required by Russell during v1 review)
> by creating a new header file include/linux/arch_topology.h and including that
> from arm, arm64 and drivers.
>
> Last patch addresses Dietmar's comments to v1 and adds a 'atd_' prefix to
> interfaces exported by drivers code and used by arch (and potentially others in
> the future).
>
> Changes from v2:
>
> - rebase on top of 4.11-rc4
> - fix various problems pointed out by Greg, thanks for the review!
> (see patch 5 for details)
>
Thanks Vincent for your comments.
Everybody else, ping?
Thanks,
- Juri
On Mon, Mar 27, 2017 at 02:18:21PM +0100, Juri Lelli wrote:
> arm and arm64 share lot of code relative to parsing CPU capacity
> information from DT, using that information for appropriate scaling and
> exposing a sysfs interface for chaging such values at runtime.
>
> Factorize such code in a common place (driver/base/arch_topology.c) in
> preparation for further additions.
>
> Suggested-by: Will Deacon <[email protected]>
> Suggested-by: Mark Rutland <[email protected]>
> Suggested-by: Catalin Marinas <[email protected]>
I need some acks here from the arm maintainers before I can take this
series...
thanks,
greg k-h
On Mon, Mar 27, 2017 at 02:18:21PM +0100, Juri Lelli wrote:
> arm and arm64 share lot of code relative to parsing CPU capacity
> information from DT, using that information for appropriate scaling and
> exposing a sysfs interface for chaging such values at runtime.
>
> Factorize such code in a common place (driver/base/arch_topology.c) in
> preparation for further additions.
>
> Suggested-by: Will Deacon <[email protected]>
> Suggested-by: Mark Rutland <[email protected]>
> Suggested-by: Catalin Marinas <[email protected]>
> Cc: Russell King <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Signed-off-by: Juri Lelli <[email protected]>
> ---
>
> Changes from v2:
> - make capacity_scale and raw_capacity static
> - added SPDX header
> - improved indent
> - misc. whitespaces/newlines fixes
>
> Changes from v1:
> - keep the original GPLv2 header
> ---
> arch/arm/Kconfig | 1 +
> arch/arm/kernel/topology.c | 213 ++-----------------------------------
> arch/arm64/Kconfig | 1 +
> arch/arm64/kernel/topology.c | 219 +--------------------------------------
> drivers/base/Kconfig | 8 ++
> drivers/base/Makefile | 1 +
> drivers/base/arch_topology.c | 242 +++++++++++++++++++++++++++++++++++++++++++
For arm64:
Acked-by: Catalin Marinas <[email protected]>
On Mon, Mar 27, 2017 at 02:18:23PM +0100, Juri Lelli wrote:
> Reduce the scope of cap_parsing_failed (making it static in
> drivers/base/arch_topology.c) by slightly changing {arm,arm64} DT
> parsing code.
>
> For arm checking for !cap_parsing_failed before calling normalize_
> cpu_capacity() is superfluous, as returning an error from parse_
> cpu_capacity() (above) means cap_from _dt is set to false.
>
> For arm64 we can simply check if raw_capacity points to something,
> which is not if capacity parsing has failed.
>
> Suggested-by: Morten Rasmussen <[email protected]>
> Signed-off-by: Juri Lelli <[email protected]>
> ---
> arch/arm/kernel/topology.c | 3 +--
> arch/arm64/kernel/topology.c | 5 +----
> drivers/base/arch_topology.c | 4 ++--
> 3 files changed, 4 insertions(+), 8 deletions(-)
Acked-by: Catalin Marinas <[email protected]>
On Mon, Mar 27, 2017 at 02:18:24PM +0100, Juri Lelli wrote:
> Create a new header file (include/linux/arch_topology.h) and put there
> declarations of interfaces used by arm, arm64 and drivers code.
>
> Signed-off-by: Juri Lelli <[email protected]>
> ---
> arch/arm/kernel/topology.c | 7 +------
> arch/arm64/kernel/topology.c | 4 +---
> drivers/base/arch_topology.c | 1 +
> include/linux/arch_topology.h | 17 +++++++++++++++++
> 4 files changed, 20 insertions(+), 9 deletions(-)
> create mode 100644 include/linux/arch_topology.h
Acked-by: Catalin Marinas <[email protected]>
On Mon, Mar 27, 2017 at 02:18:25PM +0100, Juri Lelli wrote:
> Now that some functions that deal with arch topology information live
> under drivers, there is a clash of naming that might create confusion.
>
> Tidy things up by creating a drivers namespace for interfaces used by
> arch code; achieve this by prepending a 'atd_' (arch topology driver)
> prefix to driver interfaces.
>
> Signed-off-by: Juri Lelli <[email protected]>
> ---
> arch/arm/kernel/topology.c | 8 ++++----
> arch/arm64/kernel/topology.c | 4 ++--
> drivers/base/arch_topology.c | 20 ++++++++++----------
> include/linux/arch_topology.h | 8 ++++----
> 4 files changed, 20 insertions(+), 20 deletions(-)
Acked-by: Catalin Marinas <[email protected]>
On Mon, Mar 27, 2017 at 02:18:22PM +0100, Juri Lelli wrote:
> Printing out an error message when we failed to get the cpu device is
> not helping anyone. Remove it.
(1) the subject line talks about removing a "comment" but you're
actually removing an error printk
(2) I don't think it's "not helping anyone", although the description
above doesn't say _why_ - it's reporting the lack of a missing CPU
device that we expect to be present. If it's not present, then
we're not going to end up with the cpu capacity attribute, and the
error message answers the "why is that sysfs file missing" question.
I think a better commit message is needed for this change.
>
> Signed-off-by: Juri Lelli <[email protected]>
> ---
> drivers/base/arch_topology.c | 6 ++----
> 1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> index c33482121b7d..b24d9a2af2c5 100644
> --- a/drivers/base/arch_topology.c
> +++ b/drivers/base/arch_topology.c
> @@ -81,11 +81,9 @@ static int register_cpu_capacity_sysctl(void)
>
> for_each_possible_cpu(i) {
> cpu = get_cpu_device(i);
> - if (!cpu) {
> - pr_err("%s: too early to get CPU%d device!\n",
> - __func__, i);
> + if (!cpu)
> continue;
> - }
> +
> device_create_file(cpu, &dev_attr_cpu_capacity);
> }
>
> --
> 2.10.0
>
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
Hi,
On 10/04/17 14:51, Russell King - ARM Linux wrote:
> On Mon, Mar 27, 2017 at 02:18:22PM +0100, Juri Lelli wrote:
> > Printing out an error message when we failed to get the cpu device is
> > not helping anyone. Remove it.
>
> (1) the subject line talks about removing a "comment" but you're
> actually removing an error printk
> (2) I don't think it's "not helping anyone", although the description
> above doesn't say _why_ - it's reporting the lack of a missing CPU
> device that we expect to be present. If it's not present, then
> we're not going to end up with the cpu capacity attribute, and the
> error message answers the "why is that sysfs file missing" question.
That's the same I was thinking when I put the error message there in the
first place. But, then Greg didn't seem to like it.
>
> I think a better commit message is needed for this change.
>
We could just skip this patch entirely. Or, of course, I can easily
update the commit message.
Which way is to be preferred?
Thanks,
- Juri
> >
> > Signed-off-by: Juri Lelli <[email protected]>
> > ---
> > drivers/base/arch_topology.c | 6 ++----
> > 1 file changed, 2 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
> > index c33482121b7d..b24d9a2af2c5 100644
> > --- a/drivers/base/arch_topology.c
> > +++ b/drivers/base/arch_topology.c
> > @@ -81,11 +81,9 @@ static int register_cpu_capacity_sysctl(void)
> >
> > for_each_possible_cpu(i) {
> > cpu = get_cpu_device(i);
> > - if (!cpu) {
> > - pr_err("%s: too early to get CPU%d device!\n",
> > - __func__, i);
> > + if (!cpu)
> > continue;
> > - }
> > +
> > device_create_file(cpu, &dev_attr_cpu_capacity);
> > }
> >
> > --
> > 2.10.0
> >
>
> --
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
On Mon, Mar 27, 2017 at 02:18:16PM +0100, Juri Lelli wrote:
> arm and arm64 topology.c share a lot of code related to parsing of capacity
> information. This is v3 of a solution [1] (based on Will's, Catalin's and
> Mark's off-line suggestions) to move such common code in a single place:
> drivers/base/arch_topology.c (by creating such file and conditionally compiling
> it for arm and arm64 only).
I think overall this is okay, with the exception of one patch which seems
to be wrongly worded. Once that's resolved, then:
Acked-by: Russell King <[email protected]>
for the series.
Thanks.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
Hi,
On 10/04/17 16:05, Russell King - ARM Linux wrote:
> On Mon, Mar 27, 2017 at 02:18:16PM +0100, Juri Lelli wrote:
> > arm and arm64 topology.c share a lot of code related to parsing of capacity
> > information. This is v3 of a solution [1] (based on Will's, Catalin's and
> > Mark's off-line suggestions) to move such common code in a single place:
> > drivers/base/arch_topology.c (by creating such file and conditionally compiling
> > it for arm and arm64 only).
>
> I think overall this is okay, with the exception of one patch which seems
> to be wrongly worded.
As I said in reply to your comments, we could also consider dropping
that patch entirely. What's your opinion?
> Once that's resolved, then:
>
> Acked-by: Russell King <[email protected]>
>
> for the series.
>
Also, I'd like to update 3/9 as suggested by Vincent.
Thanks for the review.
Best,
- Juri
Hi,
On 10/04/17 09:18, Catalin Marinas wrote:
> On Mon, Mar 27, 2017 at 02:18:21PM +0100, Juri Lelli wrote:
> > arm and arm64 share lot of code relative to parsing CPU capacity
> > information from DT, using that information for appropriate scaling and
> > exposing a sysfs interface for chaging such values at runtime.
> >
> > Factorize such code in a common place (driver/base/arch_topology.c) in
> > preparation for further additions.
> >
> > Suggested-by: Will Deacon <[email protected]>
> > Suggested-by: Mark Rutland <[email protected]>
> > Suggested-by: Catalin Marinas <[email protected]>
> > Cc: Russell King <[email protected]>
> > Cc: Catalin Marinas <[email protected]>
> > Cc: Will Deacon <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Signed-off-by: Juri Lelli <[email protected]>
> > ---
> >
> > Changes from v2:
> > - make capacity_scale and raw_capacity static
> > - added SPDX header
> > - improved indent
> > - misc. whitespaces/newlines fixes
> >
> > Changes from v1:
> > - keep the original GPLv2 header
> > ---
> > arch/arm/Kconfig | 1 +
> > arch/arm/kernel/topology.c | 213 ++-----------------------------------
> > arch/arm64/Kconfig | 1 +
> > arch/arm64/kernel/topology.c | 219 +--------------------------------------
> > drivers/base/Kconfig | 8 ++
> > drivers/base/Makefile | 1 +
> > drivers/base/arch_topology.c | 242 +++++++++++++++++++++++++++++++++++++++++++
>
> For arm64:
>
> Acked-by: Catalin Marinas <[email protected]>
Thanks for reviewing the series.
Best,
- Juri
On Mon, Apr 10, 2017 at 03:02:14PM +0100, Juri Lelli wrote:
> Hi,
>
> On 10/04/17 14:51, Russell King - ARM Linux wrote:
> > On Mon, Mar 27, 2017 at 02:18:22PM +0100, Juri Lelli wrote:
> > > Printing out an error message when we failed to get the cpu device is
> > > not helping anyone. Remove it.
> >
> > (1) the subject line talks about removing a "comment" but you're
> > actually removing an error printk
> > (2) I don't think it's "not helping anyone", although the description
> > above doesn't say _why_ - it's reporting the lack of a missing CPU
> > device that we expect to be present. If it's not present, then
> > we're not going to end up with the cpu capacity attribute, and the
> > error message answers the "why is that sysfs file missing" question.
>
> That's the same I was thinking when I put the error message there in the
> first place. But, then Greg didn't seem to like it.
I don't think it was a case of "not liking it" - Greg asked what use it
was. Greg also pointed out the race with userspace.
I think dropping this patch is the quickest way to move forward.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
On 10/04/17 17:33, Russell King - ARM Linux wrote:
> On Mon, Apr 10, 2017 at 03:02:14PM +0100, Juri Lelli wrote:
> > Hi,
> >
> > On 10/04/17 14:51, Russell King - ARM Linux wrote:
> > > On Mon, Mar 27, 2017 at 02:18:22PM +0100, Juri Lelli wrote:
> > > > Printing out an error message when we failed to get the cpu device is
> > > > not helping anyone. Remove it.
> > >
> > > (1) the subject line talks about removing a "comment" but you're
> > > actually removing an error printk
> > > (2) I don't think it's "not helping anyone", although the description
> > > above doesn't say _why_ - it's reporting the lack of a missing CPU
> > > device that we expect to be present. If it's not present, then
> > > we're not going to end up with the cpu capacity attribute, and the
> > > error message answers the "why is that sysfs file missing" question.
> >
> > That's the same I was thinking when I put the error message there in the
> > first place. But, then Greg didn't seem to like it.
>
> I don't think it was a case of "not liking it" - Greg asked what use it
> was. Greg also pointed out the race with userspace.
>
Right. I asked him for more information, since I wasn't able to
understand where the problem is.
> I think dropping this patch is the quickest way to move forward.
>
OK, I'm also up for dropping it.
Best,
- Juri