linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 0/8] CPUs capacity information for heterogeneous systems
@ 2016-09-05 14:22 Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie

Hi all,

version 7 of "CPUs capacity information for heterogeneous systems" patchset [1]
(please refer to previous postings to get some context).

A few changes from v6:

 - rebase on top of mainline (4.8-rc5)
 - some ACKs collected
 - changelogs fixes
 - use cpuinfo.max_freq
 - add delayed work to unregister notifier

Patches high level description:

 o 01/08 introduces documentation for the new optional DT binding
 o [02-06]/08 add cpu-capacity attribute to TC2, Juno and Juno r2 DTs and
   provide parsing of such information at boot time
 o [07-08]/08 introduce sysfs attribute

In case you would like to test this out, I pushed a branch here:

 git://linux-arm.org/linux-jl.git upstream/default_caps_v7

This branch contains additional patches, useful to better understand how CPU
capacity information is actually used by the scheduler.

These patches also form the basis for Morten/Dietmar's "Clean-ups and
asymmetric cpu capacity support" series [2] (and the EAS stack in general).

Best,

- Juri

[1] v1 - https://lkml.org/lkml/2015/11/23/391
    v2 - https://lkml.org/lkml/2016/1/8/417
    v3 - https://lkml.org/lkml/2016/2/3/405
    v4 - https://lkml.org/lkml/2016/3/18/350
    v5 - https://lkml.org/lkml/2016/6/15/291
    v6 - https://lkml.org/lkml/2016/7/19/419
[2] https://lkml.org/lkml/2016/8/31/292 


Juri Lelli (8):
  Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  arm: parse cpu capacity-dmips-mhz from DT
  arm, dts: add TC2 cpu capacity-dmips-mhz information
  arm64: parse cpu capacity-dmips-mhz from DT
  arm64, dts: add Juno cpu capacity-dmips-mhz information
  arm64, dts: add Juno r2 cpu capacity-dmips-mhz information
  arm: add sysfs cpu_capacity attribute
  arm64: add sysfs cpu_capacity attribute

 .../devicetree/bindings/arm/cpu-capacity.txt       | 236 +++++++++++++++++++++
 Documentation/devicetree/bindings/arm/cpus.txt     |  10 +
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts         |   5 +
 arch/arm/kernel/topology.c                         | 228 +++++++++++++++++++-
 arch/arm64/boot/dts/arm/juno-r2.dts                |   6 +
 arch/arm64/boot/dts/arm/juno.dts                   |   6 +
 arch/arm64/kernel/topology.c                       | 232 +++++++++++++++++++-
 7 files changed, 721 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt

-- 
2.7.0

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-12-12 12:40   ` Lorenzo Pieralisi
  2016-09-05 14:22 ` [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie, Pawel Moll, Ian Campbell, Kumar Gala,
	Maxime Ripard, Olof Johansson, Gregory CLEMENT, Paul Walmsley,
	Linus Walleij, Chen-Yu Tsai, Thomas Petazzoni

ARM systems may be configured to have cpus with different power/performance
characteristics within the same chip. In this case, additional information
has to be made available to the kernel (the scheduler in particular) for it
to be aware of such differences and take decisions accordingly.

Therefore, this patch aims at standardizing cpu capacities device tree
bindings for ARM platforms. Bindings define cpu capacity-dmips-mhz
parameter, to allow operating systems to retrieve such information from
the device tree and initialize related kernel structures, paving the way
for common code in the kernel to deal with heterogeneity.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Olof Johansson <olof@lixom.net>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: devicetree@vger.kernel.org
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
 - removed section regarding capacity-scale
 - added information regarding normalization

Changes from v4:
 - binding changed to capacity-dmips-mhz
 - sections and changelod updated accordingly

Changes from v5:
 - addressed Mark and Vincent comments
---
 .../devicetree/bindings/arm/cpu-capacity.txt       | 236 +++++++++++++++++++++
 Documentation/devicetree/bindings/arm/cpus.txt     |  10 +
 2 files changed, 246 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt

diff --git a/Documentation/devicetree/bindings/arm/cpu-capacity.txt b/Documentation/devicetree/bindings/arm/cpu-capacity.txt
new file mode 100644
index 000000000000..7809fbe0cdb7
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cpu-capacity.txt
@@ -0,0 +1,236 @@
+==========================================
+ARM CPUs capacity bindings
+==========================================
+
+==========================================
+1 - Introduction
+==========================================
+
+ARM systems may be configured to have cpus with different power/performance
+characteristics within the same chip. In this case, additional information has
+to be made available to the kernel for it to be aware of such differences and
+take decisions accordingly.
+
+==========================================
+2 - CPU capacity definition
+==========================================
+
+CPU capacity is a number that provides the scheduler information about CPUs
+heterogeneity. Such heterogeneity can come from micro-architectural differences
+(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run
+(e.g., SMP systems with multiple frequency domains). Heterogeneity in this
+context is about differing performance characteristics; this binding tries to
+capture a first-order approximation of the relative performance of CPUs.
+
+CPU capacities are obtained by running a suitable benchmark. This binding makes
+no guarantees on the validity or suitability of any particular benchmark, the
+final capacity should, however, be:
+
+* A "single-threaded" or CPU affine benchmark
+* Divided by the running frequency of the CPU executing the benchmark
+* Not subject to dynamic frequency scaling of the CPU
+
+For the time being we however advise usage of the Dhrystone benchmark. What
+above thus becomes:
+
+CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
+max frequency (with caches enabled). The obtained DMIPS score is then divided
+by the frequency (in MHz) at which the benchmark has been run, so that
+DMIPS/MHz are obtained.  Such values are then normalized w.r.t. the highest
+score obtained in the system.
+
+==========================================
+3 - capacity-dmips-mhz
+==========================================
+
+capacity-dmips-mhz is an optional cpu node [1] property: u32 value
+representing CPU capacity expressed in normalized DMIPS/MHz. At boot time, the
+maximum frequency available to the cpu is then used to calculate the capacity
+value internally used by the kernel.
+
+capacity-dmips-mhz property is all-or-nothing: if it is specified for a cpu
+node, it has to be specified for every other cpu nodes, or the system will
+fall back to the default capacity value for every CPU. If cpufreq is not
+available, final capacities are calculated by directly using capacity-dmips-
+mhz values (normalized w.r.t. the highest value found while parsing the DT).
+
+===========================================
+4 - Examples
+===========================================
+
+Example 1 (ARM 64-bit, 6-cpu system, two clusters):
+capacities-dmips-mhz are scaled w.r.t. 1024 (cpu@0 and cpu@1)
+supposing cluster0@max-freq=1100 and custer1@max-freq=850,
+final capacities are 1024 for cluster0 and 446 for cluster1
+
+cpus {
+	#address-cells = <2>;
+	#size-cells = <0>;
+
+	cpu-map {
+		cluster0 {
+			core0 {
+				cpu = <&A57_0>;
+			};
+			core1 {
+				cpu = <&A57_1>;
+			};
+		};
+
+		cluster1 {
+			core0 {
+				cpu = <&A53_0>;
+			};
+			core1 {
+				cpu = <&A53_1>;
+			};
+			core2 {
+				cpu = <&A53_2>;
+			};
+			core3 {
+				cpu = <&A53_3>;
+			};
+		};
+	};
+
+	idle-states {
+		entry-method = "arm,psci";
+
+		CPU_SLEEP_0: cpu-sleep-0 {
+			compatible = "arm,idle-state";
+			arm,psci-suspend-param = <0x0010000>;
+			local-timer-stop;
+			entry-latency-us = <100>;
+			exit-latency-us = <250>;
+			min-residency-us = <150>;
+		};
+
+		CLUSTER_SLEEP_0: cluster-sleep-0 {
+			compatible = "arm,idle-state";
+			arm,psci-suspend-param = <0x1010000>;
+			local-timer-stop;
+			entry-latency-us = <800>;
+			exit-latency-us = <700>;
+			min-residency-us = <2500>;
+		};
+	};
+
+	A57_0: cpu@0 {
+		compatible = "arm,cortex-a57","arm,armv8";
+		reg = <0x0 0x0>;
+		device_type = "cpu";
+		enable-method = "psci";
+		next-level-cache = <&A57_L2>;
+		clocks = <&scpi_dvfs 0>;
+		cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+		capacity-dmips-mhz = <1024>;
+	};
+
+	A57_1: cpu@1 {
+		compatible = "arm,cortex-a57","arm,armv8";
+		reg = <0x0 0x1>;
+		device_type = "cpu";
+		enable-method = "psci";
+		next-level-cache = <&A57_L2>;
+		clocks = <&scpi_dvfs 0>;
+		cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+		capacity-dmips-mhz = <1024>;
+	};
+
+	A53_0: cpu@100 {
+		compatible = "arm,cortex-a53","arm,armv8";
+		reg = <0x0 0x100>;
+		device_type = "cpu";
+		enable-method = "psci";
+		next-level-cache = <&A53_L2>;
+		clocks = <&scpi_dvfs 1>;
+		cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+		capacity-dmips-mhz = <578>;
+	};
+
+	A53_1: cpu@101 {
+		compatible = "arm,cortex-a53","arm,armv8";
+		reg = <0x0 0x101>;
+		device_type = "cpu";
+		enable-method = "psci";
+		next-level-cache = <&A53_L2>;
+		clocks = <&scpi_dvfs 1>;
+		cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+		capacity-dmips-mhz = <578>;
+	};
+
+	A53_2: cpu@102 {
+		compatible = "arm,cortex-a53","arm,armv8";
+		reg = <0x0 0x102>;
+		device_type = "cpu";
+		enable-method = "psci";
+		next-level-cache = <&A53_L2>;
+		clocks = <&scpi_dvfs 1>;
+		cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+		capacity-dmips-mhz = <578>;
+	};
+
+	A53_3: cpu@103 {
+		compatible = "arm,cortex-a53","arm,armv8";
+		reg = <0x0 0x103>;
+		device_type = "cpu";
+		enable-method = "psci";
+		next-level-cache = <&A53_L2>;
+		clocks = <&scpi_dvfs 1>;
+		cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+		capacity-dmips-mhz = <578>;
+	};
+
+	A57_L2: l2-cache0 {
+		compatible = "cache";
+	};
+
+	A53_L2: l2-cache1 {
+		compatible = "cache";
+	};
+};
+
+Example 2 (ARM 32-bit, 4-cpu system, two clusters,
+	   cpus 0,1@1GHz, cpus 2,3@500MHz):
+capacities-dmips-mhz are scaled w.r.t. 2 (cpu@0 and cpu@1), this means that first
+cpu@0 and cpu@1 are twice fast than cpu@2 and cpu@3 (at the same frequency)
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu0: cpu@0 {
+		device_type = "cpu";
+		compatible = "arm,cortex-a15";
+		reg = <0>;
+		capacity-dmips-mhz = <2>;
+	};
+
+	cpu1: cpu@1 {
+		device_type = "cpu";
+		compatible = "arm,cortex-a15";
+		reg = <1>;
+		capacity-dmips-mhz = <2>;
+	};
+
+	cpu2: cpu@2 {
+		device_type = "cpu";
+		compatible = "arm,cortex-a15";
+		reg = <0x100>;
+		capacity-dmips-mhz = <1>;
+	};
+
+	cpu3: cpu@3 {
+		device_type = "cpu";
+		compatible = "arm,cortex-a15";
+		reg = <0x101>;
+		capacity-dmips-mhz = <1>;
+	};
+};
+
+===========================================
+5 - References
+===========================================
+
+[1] ARM Linux Kernel documentation - CPUs bindings
+    Documentation/devicetree/bindings/arm/cpus.txt
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index e6782d50cbcd..c1dcf4cade2e 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -241,6 +241,14 @@ nodes to be present and contain the properties described below.
 			# List of phandles to idle state nodes supported
 			  by this cpu [3].
 
+	- capacity-dmips-mhz
+		Usage: Optional
+		Value type: <u32>
+		Definition:
+			# u32 value representing CPU capacity [3] in
+			  DMIPS/MHz, relative to highest capacity-dmips-mhz
+			  in the system.
+
 	- rockchip,pmu
 		Usage: optional for systems that have an "enable-method"
 		       property value of "rockchip,rk3066-smp"
@@ -464,3 +472,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
+    Documentation/devicetree/bindings/arm/cpu-capacity.txt
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-12  8:36   ` Vincent Guittot
  2016-09-05 14:22 ` [PATCH v7 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information Juri Lelli
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie

With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
can now be calculated from values extracted from DT and information
coming from cpufreq. Add parsing of DT information at boot time, and
complement it with cpufreq information. We keep code that can produce
same information, based on different DT properties and hard-coded
values, as fall-back for backward compatibility.

Caveat: the information provided by this patch will start to be used in
the future. We need to #define arch_scale_cpu_capacity to something
provided in arch, so that scheduler's default implementation (which gets
used if arch_scale_cpu_capacity is not defined) is overwritten.

Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
  - normalize w.r.t. highest capacity found in DT
  - bailout conditions (all-or-nothing)

Changes from v4:
  - parsing modified to reflect change in binding (capacity-dmips-mhz)

Changes from v5:
  - allocate raw_capacity array with kcalloc()
  - pr_err() only for partial capacity information

Changes from v6:
  - use cpuinfo.max_freq instead of policy->max
  - add delayed work to unregister cpufreq notifier
---
 arch/arm/kernel/topology.c | 155 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index ec279d161b32..a26e787926dc 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -78,6 +78,144 @@ static unsigned long *__cpu_capacity;
 #define cpu_capacity(cpu)	__cpu_capacity[cpu]
 
 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);
+	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));
+	}
+}
+
+#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
 
 /*
  * Iterate all CPUs' descriptor in DT and compute the efficiency
@@ -99,6 +237,12 @@ static void __init parse_dt_topology(void)
 	__cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity),
 				 GFP_NOWAIT);
 
+	cn = of_find_node_by_path("/cpus");
+	if (!cn) {
+		pr_err("No CPU information found in DT\n");
+		return;
+	}
+
 	for_each_possible_cpu(cpu) {
 		const u32 *rate;
 		int len;
@@ -110,6 +254,13 @@ static void __init parse_dt_topology(void)
 			continue;
 		}
 
+		if (parse_cpu_capacity(cn, cpu)) {
+			of_node_put(cn);
+			continue;
+		}
+
+		cap_from_dt = false;
+
 		for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
 			if (of_device_is_compatible(cn, cpu_eff->compatible))
 				break;
@@ -151,6 +302,8 @@ static void __init parse_dt_topology(void)
 		middle_capacity = ((max_capacity / 3)
 				>> (SCHED_CAPACITY_SHIFT-1)) + 1;
 
+	if (cap_from_dt && !cap_parsing_failed)
+		normalize_cpu_capacity();
 }
 
 /*
@@ -160,7 +313,7 @@ static void __init parse_dt_topology(void)
  */
 static void update_cpu_capacity(unsigned int cpu)
 {
-	if (!cpu_capacity(cpu))
+	if (!cpu_capacity(cpu) || cap_from_dt)
 		return;
 
 	set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie, Liviu Dudau, Pawel Moll, Ian Campbell,
	Kumar Gala

Add TC2 cpu capacity information.

Cc: Liviu Dudau <liviu.dudau@arm.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: devicetree@vger.kernel.org
Acked-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
  - capacity-scale removed

Changes from v4:
  - binding changed to capacity-dmips-mhz

Changes from v6:
  - s/binding// in changelog
---
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index 0205c97efdef..45d08cc37b01 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -39,6 +39,7 @@
 			reg = <0>;
 			cci-control-port = <&cci_control1>;
 			cpu-idle-states = <&CLUSTER_SLEEP_BIG>;
+			capacity-dmips-mhz = <1024>;
 		};
 
 		cpu1: cpu@1 {
@@ -47,6 +48,7 @@
 			reg = <1>;
 			cci-control-port = <&cci_control1>;
 			cpu-idle-states = <&CLUSTER_SLEEP_BIG>;
+			capacity-dmips-mhz = <1024>;
 		};
 
 		cpu2: cpu@2 {
@@ -55,6 +57,7 @@
 			reg = <0x100>;
 			cci-control-port = <&cci_control2>;
 			cpu-idle-states = <&CLUSTER_SLEEP_LITTLE>;
+			capacity-dmips-mhz = <516>;
 		};
 
 		cpu3: cpu@3 {
@@ -63,6 +66,7 @@
 			reg = <0x101>;
 			cci-control-port = <&cci_control2>;
 			cpu-idle-states = <&CLUSTER_SLEEP_LITTLE>;
+			capacity-dmips-mhz = <516>;
 		};
 
 		cpu4: cpu@4 {
@@ -71,6 +75,7 @@
 			reg = <0x102>;
 			cci-control-port = <&cci_control2>;
 			cpu-idle-states = <&CLUSTER_SLEEP_LITTLE>;
+			capacity-dmips-mhz = <516>;
 		};
 
 		idle-states {
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (2 preceding siblings ...)
  2016-09-05 14:22 ` [PATCH v7 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-12  8:37   ` Vincent Guittot
  2016-09-05 14:22 ` [PATCH v7 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information Juri Lelli
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie

With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
can now be calculated from values extracted from DT and information
coming from cpufreq. Add parsing of DT information at boot time, and
complement it with cpufreq information. Also, store such information
using per CPU variables, as we do for arm.

Caveat: the information provided by this patch will start to be used in
the future. We need to #define arch_scale_cpu_capacity to something
provided in arch, so that scheduler's default implementation (which gets
used if arch_scale_cpu_capacity is not defined) is overwritten.

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
  - normalize w.r.t. highest capacity found in DT
  - bailout conditions (all-or-nothing)

Changes from v4:
  - parsing modified to reflect change in binding (capacity-dmips-mhz)

Changes from v5:
  - allocate raw_capacity array with kcalloc()
  - pr_err() only for partial capacity information

Changes from v6:
  - use cpuinfo.max_freq instead of policy->max
  - add delayed work to unregister cpufreq notifier
---
 arch/arm64/kernel/topology.c | 159 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 158 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 694f6deedbab..b75b0ba2e113 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -19,10 +19,162 @@
 #include <linux/nodemask.h>
 #include <linux/of.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
 
 #include <asm/cputype.h>
 #include <asm/topology.h>
 
+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);
+}
+
+static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
+{
+	per_cpu(cpu_scale, cpu) = capacity;
+}
+
+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);
+	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));
+	}
+}
+
+#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
+
 static int __init get_cpu_for_node(struct device_node *node)
 {
 	struct device_node *cpu_node;
@@ -34,6 +186,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);
 			of_node_put(cpu_node);
 			return cpu;
 		}
@@ -178,13 +331,17 @@ static int __init parse_dt_topology(void)
 	 * cluster with restricted subnodes.
 	 */
 	map = of_get_child_by_name(cn, "cpu-map");
-	if (!map)
+	if (!map) {
+		cap_parsing_failed = true;
 		goto out;
+	}
 
 	ret = parse_cluster(map, 0);
 	if (ret != 0)
 		goto out_map;
 
+	normalize_cpu_capacity();
+
 	/*
 	 * Check that all cores are in the topology; the SMP code will
 	 * only mark cores described in the DT as possible.
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (3 preceding siblings ...)
  2016-09-05 14:22 ` [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 6/8] arm64, dts: add Juno r2 " Juri Lelli
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie, Pawel Moll, Ian Campbell, Kumar Gala,
	Liviu Dudau, Arnd Bergmann, Jon Medhurst, Olof Johansson,
	Robin Murphy

Add Juno cpu capacity-dmips-mhz information.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Liviu Dudau <Liviu.Dudau@arm.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jon Medhurst <tixy@linaro.org>
Cc: Olof Johansson <olof@lixom.net>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: devicetree@vger.kernel.org
Acked-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
  - capacity-scale removed

Changes from v4:
  - binding changed to capacity-dmips-mhz

Changes from v6:
  - s/bindings// in changelog
---
 arch/arm64/boot/dts/arm/juno.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index a7270eff6939..6b4135e9cfe5 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -90,6 +90,7 @@
 			next-level-cache = <&A57_L2>;
 			clocks = <&scpi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <1024>;
 		};
 
 		A57_1: cpu@1 {
@@ -100,6 +101,7 @@
 			next-level-cache = <&A57_L2>;
 			clocks = <&scpi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <1024>;
 		};
 
 		A53_0: cpu@100 {
@@ -110,6 +112,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <578>;
 		};
 
 		A53_1: cpu@101 {
@@ -120,6 +123,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <578>;
 		};
 
 		A53_2: cpu@102 {
@@ -130,6 +134,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <578>;
 		};
 
 		A53_3: cpu@103 {
@@ -140,6 +145,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <578>;
 		};
 
 		A57_L2: l2-cache0 {
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 6/8] arm64, dts: add Juno r2 cpu capacity-dmips-mhz information
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (4 preceding siblings ...)
  2016-09-05 14:22 ` [PATCH v7 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 7/8] arm: add sysfs cpu_capacity attribute Juri Lelli
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie, Pawel Moll, Ian Campbell, Kumar Gala,
	Liviu Dudau, Arnd Bergmann, Jon Medhurst, Olof Johansson,
	Robin Murphy

Add Juno r2 cpu capacity-dmips-mhz information.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Liviu Dudau <Liviu.Dudau@arm.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jon Medhurst <tixy@linaro.org>
Cc: Olof Johansson <olof@lixom.net>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: devicetree@vger.kernel.org
Acked-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v4:
  - new patch since Juno r2 dt has been merged

Changes from v6:
  - s/bindings// in changelog
---
 arch/arm64/boot/dts/arm/juno-r2.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts
index 007be826efce..614fc9227943 100644
--- a/arch/arm64/boot/dts/arm/juno-r2.dts
+++ b/arch/arm64/boot/dts/arm/juno-r2.dts
@@ -90,6 +90,7 @@
 			next-level-cache = <&A72_L2>;
 			clocks = <&scpi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <1024>;
 		};
 
 		A72_1: cpu@1 {
@@ -100,6 +101,7 @@
 			next-level-cache = <&A72_L2>;
 			clocks = <&scpi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <1024>;
 		};
 
 		A53_0: cpu@100 {
@@ -110,6 +112,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <485>;
 		};
 
 		A53_1: cpu@101 {
@@ -120,6 +123,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <485>;
 		};
 
 		A53_2: cpu@102 {
@@ -130,6 +134,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <485>;
 		};
 
 		A53_3: cpu@103 {
@@ -140,6 +145,7 @@
 			next-level-cache = <&A53_L2>;
 			clocks = <&scpi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			capacity-dmips-mhz = <485>;
 		};
 
 		A72_L2: l2-cache0 {
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 7/8] arm: add sysfs cpu_capacity attribute
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (5 preceding siblings ...)
  2016-09-05 14:22 ` [PATCH v7 6/8] arm64, dts: add Juno r2 " Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-05 14:22 ` [PATCH v7 8/8] arm64: " Juri Lelli
  2016-09-12  7:24 ` [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
  8 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie

Add a sysfs cpu_capacity attribute with which it is possible to read and
write (thus over-writing default values) CPUs capacity. This might be
useful in situations where values needs changing after boot.

The new attribute shows up as:

 /sys/devices/system/cpu/cpu*/cpu_capacity

Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v5:
  - add mutex to protect cpu_scale (as pointed out by Morten off-line)
---
 arch/arm/kernel/topology.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index a26e787926dc..e79ac856eeef 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -41,6 +41,7 @@
  * 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)
 {
@@ -52,6 +53,76 @@ static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
 	per_cpu(cpu_scale, cpu) = capacity;
 }
 
+#ifdef CONFIG_PROC_SYSCTL
+#include <asm/cpu.h>
+#include <linux/string.h>
+static ssize_t show_cpu_capacity(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, dev);
+	ssize_t rc;
+	int cpunum = cpu->dev.id;
+	unsigned long capacity = arch_scale_cpu_capacity(NULL, cpunum);
+
+	rc = sprintf(buf, "%lu\n", capacity);
+
+	return rc;
+}
+
+static ssize_t store_cpu_capacity(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) {
+		char *p = (char *) buf;
+
+		ret = kstrtoul(p, 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(cpu_capacity,
+		   0644,
+		   show_cpu_capacity,
+		   store_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;
+}
+late_initcall(register_cpu_capacity_sysctl);
+#endif
+
 #ifdef CONFIG_OF
 struct cpu_efficiency {
 	const char *compatible;
@@ -131,6 +202,7 @@ static void normalize_cpu_capacity(void)
 		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;
@@ -138,6 +210,7 @@ static void normalize_cpu_capacity(void)
 		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
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v7 8/8] arm64: add sysfs cpu_capacity attribute
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (6 preceding siblings ...)
  2016-09-05 14:22 ` [PATCH v7 7/8] arm: add sysfs cpu_capacity attribute Juri Lelli
@ 2016-09-05 14:22 ` Juri Lelli
  2016-09-12  7:24 ` [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
  8 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-05 14:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	juri.lelli, broonie

Add a sysfs cpu_capacity attribute with which it is possible to read and
write (thus over-writing default values) CPUs capacity. This might be
useful in situations where values needs changing after boot.

The new attribute shows up as:

 /sys/devices/system/cpu/cpu*/cpu_capacity

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v5:
  - add mutex to protect cpu_scale (as pointed out by Morten off-line)
---
 arch/arm64/kernel/topology.c | 73 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index b75b0ba2e113..cff34cc858b7 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -26,6 +26,7 @@
 #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)
 {
@@ -37,6 +38,76 @@ static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
 	per_cpu(cpu_scale, cpu) = capacity;
 }
 
+#ifdef CONFIG_PROC_SYSCTL
+#include <asm/cpu.h>
+#include <linux/string.h>
+static ssize_t show_cpu_capacity(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, dev);
+	ssize_t rc;
+	int cpunum = cpu->dev.id;
+	unsigned long capacity = arch_scale_cpu_capacity(NULL, cpunum);
+
+	rc = sprintf(buf, "%lu\n", capacity);
+
+	return rc;
+}
+
+static ssize_t store_cpu_capacity(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) {
+		char *p = (char *) buf;
+
+		ret = kstrtoul(p, 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(cpu_capacity,
+		   0644,
+		   show_cpu_capacity,
+		   store_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;
+}
+late_initcall(register_cpu_capacity_sysctl);
+#endif
+
 static u32 capacity_scale;
 static u32 *raw_capacity;
 static bool cap_parsing_failed;
@@ -87,6 +158,7 @@ static void normalize_cpu_capacity(void)
 		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]);
@@ -96,6 +168,7 @@ static void normalize_cpu_capacity(void)
 		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
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 0/8] CPUs capacity information for heterogeneous systems
  2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (7 preceding siblings ...)
  2016-09-05 14:22 ` [PATCH v7 8/8] arm64: " Juri Lelli
@ 2016-09-12  7:24 ` Juri Lelli
  2016-09-19 11:10   ` Juri Lelli
  8 siblings, 1 reply; 17+ messages in thread
From: Juri Lelli @ 2016-09-12  7:24 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	broonie

Hi,

this is a ping for people interested in this series. Patches 2,4,7-8
still needs ACKs.

I know it's only been a week since I posted v7, but this series would
pair nicely with asym cpu capacity support bits already sitting in
tip/sched/core. I also know that it might be already late for 4.9 merge
window; nevertheless, still hoping we can make it.

Thanks!

Best,

- Juri

On 05/09/16 15:22, Juri Lelli wrote:
> Hi all,
> 
> version 7 of "CPUs capacity information for heterogeneous systems" patchset [1]
> (please refer to previous postings to get some context).
> 
> A few changes from v6:
> 
>  - rebase on top of mainline (4.8-rc5)
>  - some ACKs collected
>  - changelogs fixes
>  - use cpuinfo.max_freq
>  - add delayed work to unregister notifier
> 
> Patches high level description:
> 
>  o 01/08 introduces documentation for the new optional DT binding
>  o [02-06]/08 add cpu-capacity attribute to TC2, Juno and Juno r2 DTs and
>    provide parsing of such information at boot time
>  o [07-08]/08 introduce sysfs attribute
> 
> In case you would like to test this out, I pushed a branch here:
> 
>  git://linux-arm.org/linux-jl.git upstream/default_caps_v7
> 
> This branch contains additional patches, useful to better understand how CPU
> capacity information is actually used by the scheduler.
> 
> These patches also form the basis for Morten/Dietmar's "Clean-ups and
> asymmetric cpu capacity support" series [2] (and the EAS stack in general).
> 
> Best,
> 
> - Juri
> 
> [1] v1 - https://lkml.org/lkml/2015/11/23/391
>     v2 - https://lkml.org/lkml/2016/1/8/417
>     v3 - https://lkml.org/lkml/2016/2/3/405
>     v4 - https://lkml.org/lkml/2016/3/18/350
>     v5 - https://lkml.org/lkml/2016/6/15/291
>     v6 - https://lkml.org/lkml/2016/7/19/419
> [2] https://lkml.org/lkml/2016/8/31/292 
> 
> 
> Juri Lelli (8):
>   Documentation: arm: define DT cpu capacity-dmips-mhz bindings
>   arm: parse cpu capacity-dmips-mhz from DT
>   arm, dts: add TC2 cpu capacity-dmips-mhz information
>   arm64: parse cpu capacity-dmips-mhz from DT
>   arm64, dts: add Juno cpu capacity-dmips-mhz information
>   arm64, dts: add Juno r2 cpu capacity-dmips-mhz information
>   arm: add sysfs cpu_capacity attribute
>   arm64: add sysfs cpu_capacity attribute
> 
>  .../devicetree/bindings/arm/cpu-capacity.txt       | 236 +++++++++++++++++++++
>  Documentation/devicetree/bindings/arm/cpus.txt     |  10 +
>  arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts         |   5 +
>  arch/arm/kernel/topology.c                         | 228 +++++++++++++++++++-
>  arch/arm64/boot/dts/arm/juno-r2.dts                |   6 +
>  arch/arm64/boot/dts/arm/juno.dts                   |   6 +
>  arch/arm64/kernel/topology.c                       | 232 +++++++++++++++++++-
>  7 files changed, 721 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt
> 
> -- 
> 2.7.0
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT
  2016-09-05 14:22 ` [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
@ 2016-09-12  8:36   ` Vincent Guittot
  2016-09-12  8:55     ` Juri Lelli
  0 siblings, 1 reply; 17+ messages in thread
From: Vincent Guittot @ 2016-09-12  8:36 UTC (permalink / raw)
  To: Juri Lelli
  Cc: linux-kernel, linux-pm, LAK, devicetree, Peter Zijlstra,
	Rob Herring, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, Dietmar Eggemann, Mark Brown

Hi Juri,

On 5 September 2016 at 16:22, Juri Lelli <juri.lelli@arm.com> wrote:
> With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
> can now be calculated from values extracted from DT and information
> coming from cpufreq. Add parsing of DT information at boot time, and
> complement it with cpufreq information. We keep code that can produce
> same information, based on different DT properties and hard-coded
> values, as fall-back for backward compatibility.
>
> Caveat: the information provided by this patch will start to be used in
> the future. We need to #define arch_scale_cpu_capacity to something
> provided in arch, so that scheduler's default implementation (which gets
> used if arch_scale_cpu_capacity is not defined) is overwritten.
>
> Cc: Russell King <linux@arm.linux.org.uk>
> Signed-off-by: Juri Lelli <juri.lelli@arm.com>

Acked-by: Vincent Guittot <vincent.guittot@linaro.org>

Vincent

> ---
>
> Changes from v1:
>   - normalize w.r.t. highest capacity found in DT
>   - bailout conditions (all-or-nothing)
>
> Changes from v4:
>   - parsing modified to reflect change in binding (capacity-dmips-mhz)
>
> Changes from v5:
>   - allocate raw_capacity array with kcalloc()
>   - pr_err() only for partial capacity information
>
> Changes from v6:
>   - use cpuinfo.max_freq instead of policy->max
>   - add delayed work to unregister cpufreq notifier
> ---
>  arch/arm/kernel/topology.c | 155 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 154 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> index ec279d161b32..a26e787926dc 100644
> --- a/arch/arm/kernel/topology.c
> +++ b/arch/arm/kernel/topology.c
> @@ -78,6 +78,144 @@ static unsigned long *__cpu_capacity;
>  #define cpu_capacity(cpu)      __cpu_capacity[cpu]
>
>  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);
> +       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));
> +       }
> +}
> +
> +#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
>
>  /*
>   * Iterate all CPUs' descriptor in DT and compute the efficiency
> @@ -99,6 +237,12 @@ static void __init parse_dt_topology(void)
>         __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity),
>                                  GFP_NOWAIT);
>
> +       cn = of_find_node_by_path("/cpus");
> +       if (!cn) {
> +               pr_err("No CPU information found in DT\n");
> +               return;
> +       }
> +
>         for_each_possible_cpu(cpu) {
>                 const u32 *rate;
>                 int len;
> @@ -110,6 +254,13 @@ static void __init parse_dt_topology(void)
>                         continue;
>                 }
>
> +               if (parse_cpu_capacity(cn, cpu)) {
> +                       of_node_put(cn);
> +                       continue;
> +               }
> +
> +               cap_from_dt = false;
> +
>                 for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
>                         if (of_device_is_compatible(cn, cpu_eff->compatible))
>                                 break;
> @@ -151,6 +302,8 @@ static void __init parse_dt_topology(void)
>                 middle_capacity = ((max_capacity / 3)
>                                 >> (SCHED_CAPACITY_SHIFT-1)) + 1;
>
> +       if (cap_from_dt && !cap_parsing_failed)
> +               normalize_cpu_capacity();
>  }
>
>  /*
> @@ -160,7 +313,7 @@ static void __init parse_dt_topology(void)
>   */
>  static void update_cpu_capacity(unsigned int cpu)
>  {
> -       if (!cpu_capacity(cpu))
> +       if (!cpu_capacity(cpu) || cap_from_dt)
>                 return;
>
>         set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
> --
> 2.7.0
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT
  2016-09-05 14:22 ` [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
@ 2016-09-12  8:37   ` Vincent Guittot
  2016-09-12  8:56     ` Juri Lelli
  0 siblings, 1 reply; 17+ messages in thread
From: Vincent Guittot @ 2016-09-12  8:37 UTC (permalink / raw)
  To: Juri Lelli
  Cc: linux-kernel, linux-pm, LAK, devicetree, Peter Zijlstra,
	Rob Herring, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, Dietmar Eggemann, Mark Brown

Hi Juri,

On 5 September 2016 at 16:22, Juri Lelli <juri.lelli@arm.com> wrote:
> With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
> can now be calculated from values extracted from DT and information
> coming from cpufreq. Add parsing of DT information at boot time, and
> complement it with cpufreq information. Also, store such information
> using per CPU variables, as we do for arm.
>
> Caveat: the information provided by this patch will start to be used in
> the future. We need to #define arch_scale_cpu_capacity to something
> provided in arch, so that scheduler's default implementation (which gets
> used if arch_scale_cpu_capacity is not defined) is overwritten.
>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Mark Brown <broonie@kernel.org>
> Cc: Sudeep Holla <sudeep.holla@arm.com>
> Signed-off-by: Juri Lelli <juri.lelli@arm.com>

Acked-by: Vincent Guittot <vincent.guittot@linaro.org>

> ---
>
> Changes from v1:
>   - normalize w.r.t. highest capacity found in DT
>   - bailout conditions (all-or-nothing)
>
> Changes from v4:
>   - parsing modified to reflect change in binding (capacity-dmips-mhz)
>
> Changes from v5:
>   - allocate raw_capacity array with kcalloc()
>   - pr_err() only for partial capacity information
>
> Changes from v6:
>   - use cpuinfo.max_freq instead of policy->max
>   - add delayed work to unregister cpufreq notifier
> ---
>  arch/arm64/kernel/topology.c | 159 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 158 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> index 694f6deedbab..b75b0ba2e113 100644
> --- a/arch/arm64/kernel/topology.c
> +++ b/arch/arm64/kernel/topology.c
> @@ -19,10 +19,162 @@
>  #include <linux/nodemask.h>
>  #include <linux/of.h>
>  #include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/cpufreq.h>
>
>  #include <asm/cputype.h>
>  #include <asm/topology.h>
>
> +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);
> +}
> +
> +static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
> +{
> +       per_cpu(cpu_scale, cpu) = capacity;
> +}
> +
> +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);
> +       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));
> +       }
> +}
> +
> +#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
> +
>  static int __init get_cpu_for_node(struct device_node *node)
>  {
>         struct device_node *cpu_node;
> @@ -34,6 +186,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);
>                         of_node_put(cpu_node);
>                         return cpu;
>                 }
> @@ -178,13 +331,17 @@ static int __init parse_dt_topology(void)
>          * cluster with restricted subnodes.
>          */
>         map = of_get_child_by_name(cn, "cpu-map");
> -       if (!map)
> +       if (!map) {
> +               cap_parsing_failed = true;
>                 goto out;
> +       }
>
>         ret = parse_cluster(map, 0);
>         if (ret != 0)
>                 goto out_map;
>
> +       normalize_cpu_capacity();
> +
>         /*
>          * Check that all cores are in the topology; the SMP code will
>          * only mark cores described in the DT as possible.
> --
> 2.7.0
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT
  2016-09-12  8:36   ` Vincent Guittot
@ 2016-09-12  8:55     ` Juri Lelli
  0 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-12  8:55 UTC (permalink / raw)
  To: Vincent Guittot
  Cc: linux-kernel, linux-pm, LAK, devicetree, Peter Zijlstra,
	Rob Herring, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, Dietmar Eggemann, Mark Brown

Hi,

On 12/09/16 10:36, Vincent Guittot wrote:
> Hi Juri,
> 
> On 5 September 2016 at 16:22, Juri Lelli <juri.lelli@arm.com> wrote:
> > With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
> > can now be calculated from values extracted from DT and information
> > coming from cpufreq. Add parsing of DT information at boot time, and
> > complement it with cpufreq information. We keep code that can produce
> > same information, based on different DT properties and hard-coded
> > values, as fall-back for backward compatibility.
> >
> > Caveat: the information provided by this patch will start to be used in
> > the future. We need to #define arch_scale_cpu_capacity to something
> > provided in arch, so that scheduler's default implementation (which gets
> > used if arch_scale_cpu_capacity is not defined) is overwritten.
> >
> > Cc: Russell King <linux@arm.linux.org.uk>
> > Signed-off-by: Juri Lelli <juri.lelli@arm.com>
> 
> Acked-by: Vincent Guittot <vincent.guittot@linaro.org>
> 

Thanks!

Best,

- Juri

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT
  2016-09-12  8:37   ` Vincent Guittot
@ 2016-09-12  8:56     ` Juri Lelli
  0 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-12  8:56 UTC (permalink / raw)
  To: Vincent Guittot
  Cc: linux-kernel, linux-pm, LAK, devicetree, Peter Zijlstra,
	Rob Herring, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, Dietmar Eggemann, Mark Brown

Hi,

On 12/09/16 10:37, Vincent Guittot wrote:
> Hi Juri,
> 
> On 5 September 2016 at 16:22, Juri Lelli <juri.lelli@arm.com> wrote:
> > With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
> > can now be calculated from values extracted from DT and information
> > coming from cpufreq. Add parsing of DT information at boot time, and
> > complement it with cpufreq information. Also, store such information
> > using per CPU variables, as we do for arm.
> >
> > Caveat: the information provided by this patch will start to be used in
> > the future. We need to #define arch_scale_cpu_capacity to something
> > provided in arch, so that scheduler's default implementation (which gets
> > used if arch_scale_cpu_capacity is not defined) is overwritten.
> >
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Mark Brown <broonie@kernel.org>
> > Cc: Sudeep Holla <sudeep.holla@arm.com>
> > Signed-off-by: Juri Lelli <juri.lelli@arm.com>
> 
> Acked-by: Vincent Guittot <vincent.guittot@linaro.org>
> 

Thanks!

Best,

- Juri

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 0/8] CPUs capacity information for heterogeneous systems
  2016-09-12  7:24 ` [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
@ 2016-09-19 11:10   ` Juri Lelli
  0 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-09-19 11:10 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
	robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	broonie

Hi,

On 12/09/16 08:24, Juri Lelli wrote:
> Hi,
> 
> this is a ping for people interested in this series. Patches 2,4,7-8
> still needs ACKs.
> 

Weekly ping. :-)

Best,

- Juri

> I know it's only been a week since I posted v7, but this series would
> pair nicely with asym cpu capacity support bits already sitting in
> tip/sched/core. I also know that it might be already late for 4.9 merge
> window; nevertheless, still hoping we can make it.
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-09-05 14:22 ` [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
@ 2016-12-12 12:40   ` Lorenzo Pieralisi
  2016-12-12 13:33     ` Juri Lelli
  0 siblings, 1 reply; 17+ messages in thread
From: Lorenzo Pieralisi @ 2016-12-12 12:40 UTC (permalink / raw)
  To: Juri Lelli
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	vincent.guittot, robh+dt, mark.rutland, linux, sudeep.holla,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	broonie, Pawel Moll, Ian Campbell, Kumar Gala, Maxime Ripard,
	Olof Johansson, Gregory CLEMENT, Paul Walmsley, Linus Walleij,
	Chen-Yu Tsai, Thomas Petazzoni

On Mon, Sep 05, 2016 at 03:22:45PM +0100, Juri Lelli wrote:

[...]

> +===========================================
> +5 - References
> +===========================================
> +
> +[1] ARM Linux Kernel documentation - CPUs bindings
> +    Documentation/devicetree/bindings/arm/cpus.txt
> diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
> index e6782d50cbcd..c1dcf4cade2e 100644
> --- a/Documentation/devicetree/bindings/arm/cpus.txt
> +++ b/Documentation/devicetree/bindings/arm/cpus.txt
> @@ -241,6 +241,14 @@ nodes to be present and contain the properties described below.
>  			# List of phandles to idle state nodes supported
>  			  by this cpu [3].
>  
> +	- capacity-dmips-mhz
> +		Usage: Optional
> +		Value type: <u32>
> +		Definition:
> +			# u32 value representing CPU capacity [3] in
> +			  DMIPS/MHz, relative to highest capacity-dmips-mhz
> +			  in the system.
> +
>  	- rockchip,pmu
>  		Usage: optional for systems that have an "enable-method"
>  		       property value of "rockchip,rk3066-smp"
> @@ -464,3 +472,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
> +    Documentation/devicetree/bindings/arm/cpu-capacity.txt

Trivia: bumped into this while reviewing something else, too many
threes, you will have to fix the added reference up.

Thanks,
Lorenzo

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-12-12 12:40   ` Lorenzo Pieralisi
@ 2016-12-12 13:33     ` Juri Lelli
  0 siblings, 0 replies; 17+ messages in thread
From: Juri Lelli @ 2016-12-12 13:33 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	vincent.guittot, robh+dt, mark.rutland, linux, sudeep.holla,
	catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
	broonie, Pawel Moll, Ian Campbell, Kumar Gala, Maxime Ripard,
	Olof Johansson, Gregory CLEMENT, Paul Walmsley, Linus Walleij,
	Chen-Yu Tsai, Thomas Petazzoni

On 12/12/16 12:40, Lorenzo Pieralisi wrote:
> On Mon, Sep 05, 2016 at 03:22:45PM +0100, Juri Lelli wrote:
> 
> [...]
> 
> > +===========================================
> > +5 - References
> > +===========================================
> > +
> > +[1] ARM Linux Kernel documentation - CPUs bindings
> > +    Documentation/devicetree/bindings/arm/cpus.txt
> > diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
> > index e6782d50cbcd..c1dcf4cade2e 100644
> > --- a/Documentation/devicetree/bindings/arm/cpus.txt
> > +++ b/Documentation/devicetree/bindings/arm/cpus.txt
> > @@ -241,6 +241,14 @@ nodes to be present and contain the properties described below.
> >  			# List of phandles to idle state nodes supported
> >  			  by this cpu [3].
> >  
> > +	- capacity-dmips-mhz
> > +		Usage: Optional
> > +		Value type: <u32>
> > +		Definition:
> > +			# u32 value representing CPU capacity [3] in
> > +			  DMIPS/MHz, relative to highest capacity-dmips-mhz
> > +			  in the system.
> > +
> >  	- rockchip,pmu
> >  		Usage: optional for systems that have an "enable-method"
> >  		       property value of "rockchip,rk3066-smp"
> > @@ -464,3 +472,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
> > +    Documentation/devicetree/bindings/arm/cpu-capacity.txt
> 
> Trivia: bumped into this while reviewing something else, too many
> threes, you will have to fix the added reference up.

Argh! Fixed locally, thanks for catching it.

Best,

- Juri

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2016-12-12 13:33 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-05 14:22 [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
2016-09-05 14:22 ` [PATCH v7 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
2016-12-12 12:40   ` Lorenzo Pieralisi
2016-12-12 13:33     ` Juri Lelli
2016-09-05 14:22 ` [PATCH v7 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
2016-09-12  8:36   ` Vincent Guittot
2016-09-12  8:55     ` Juri Lelli
2016-09-05 14:22 ` [PATCH v7 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information Juri Lelli
2016-09-05 14:22 ` [PATCH v7 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
2016-09-12  8:37   ` Vincent Guittot
2016-09-12  8:56     ` Juri Lelli
2016-09-05 14:22 ` [PATCH v7 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information Juri Lelli
2016-09-05 14:22 ` [PATCH v7 6/8] arm64, dts: add Juno r2 " Juri Lelli
2016-09-05 14:22 ` [PATCH v7 7/8] arm: add sysfs cpu_capacity attribute Juri Lelli
2016-09-05 14:22 ` [PATCH v7 8/8] arm64: " Juri Lelli
2016-09-12  7:24 ` [PATCH v7 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
2016-09-19 11:10   ` Juri Lelli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).