linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/8] CPUs capacity information for heterogeneous systems
@ 2016-06-15 10:17 Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
                   ` (7 more replies)
  0 siblings, 8 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi

Hi all,

this is take 5 of "CPUs capacity information for heterogeneous systems"
patchset [1] (please refer to previous postings to get some context). Apologies
for taking so much time before posting a new version, I've been busy working on
other (related :-)) stuff.

Anyway, after v4 review we seem to still agree that a new DT binding is
reasonable (as it is only a first-order approximation that it is useful to get
acceptable good behaviours during boot and early execution and it can be then
overwritten using the sysfs interface if needed). However, Rob asked for more
precision in defining the binding and Mark, Sai and Vincent seem to agree that
we should extract the frequency component from the values we put in DT.

In this new version I made several changes:

 - first patch of v4 is now mainline (but we've got a new one, see below)
 - clearly state that Dhrystone is used to get this first order approx values
 - the binding is now called capacity-dmips-mhz (suggestions for better naming
   are welcome!)
 - capacity-dmips-mhz have to be calculated by:
   + running dhrystone at max freq on each cpu (in practice it can be run just
     on the first cpu of each cluster and at any frequency)
   + collect DMIPS/MHz by dividing the score by the frequency at which it has
     been run
   + normalize DMIPS/MHz and put such values in the DT (we've got a new patch
     in the series for JUNO R2)
 - at boot we use a cpufreq callback to be able to multiply back capacity-dmips
   -mhz for policy->max and then normalize w.r.t. 1024
 - if cpufreq is not in the mix, we use capacity-dmips-mhz values as they are
   (since we don't know at which frequency we are running at, we assume that
   CPUs run all at the same frequency)

I guess at least some more comments in the code and some more lines in
Documentation will help, but I'll defer that to v6: I'd like to see if we can
first reach an agreement.

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

The patchset is based on top of mainline as of today (4.7-rc3). 

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

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

This branch contains additional patches, useful to better understand how CPU
capacity information is actually used by the scheduler. However, discussion
regarding these additional patches is outside the scope of this posting.

Best,

- Juri

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                         | 213 ++++++++++++++++++-
 arch/arm64/boot/dts/arm/juno-r2.dts                |   6 +
 arch/arm64/boot/dts/arm/juno.dts                   |   6 +
 arch/arm64/kernel/topology.c                       | 213 +++++++++++++++++++
 7 files changed, 688 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt

-- 
2.7.0

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

* [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  2016-06-15 12:51   ` Vincent Guittot
                     ` (2 more replies)
  2016-06-15 10:17 ` [PATCH v5 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi, 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
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
---
 .../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 0000000..7582a13
--- /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 (the scheduler in particular) 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 aspersions 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. 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 3f0cbbb..d79442d 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -238,6 +238,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"
@@ -461,3 +469,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] 19+ messages in thread

* [PATCH v5 2/8] arm: parse cpu capacity-dmips-mhz from DT
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information Juri Lelli
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi

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)
---
 arch/arm/kernel/topology.c | 145 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 144 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index ec279d1..2bab290 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -78,6 +78,134 @@ 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 = kzalloc(sizeof(*raw_capacity) *
+					num_possible_cpus(), 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 {
+		pr_err("cpu_capacity: missing %s raw capacity "
+		       "(fallback to 1024 for all CPUs)\n",
+		       cpu_node->full_name);
+		cap_parsing_failed = true;
+		kfree(raw_capacity);
+	}
+
+	return !ret;
+}
+
+static void normalize_cpu_capacity(void)
+{
+	u64 capacity;
+	int cpu;
+
+	if (WARN_ON(!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 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->max / 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;
+		}
+	}
+	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);
+#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 +227,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 +244,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 +292,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 +303,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] 19+ messages in thread

* [PATCH v5 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi, Liviu Dudau, Pawel Moll,
	Ian Campbell, Kumar Gala

Add TC2 cpu capacity binding 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
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
  - capacity-scale removed

Changes from v4:
  - binding changed to capacity-dmips-mhz
---
 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 0205c97..45d08cc 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] 19+ messages in thread

* [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (2 preceding siblings ...)
  2016-06-15 10:17 ` [PATCH v5 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
       [not found]   ` <CADRr18P=EOwpZTc-aS=4cCa8B3ObpuqpbNNv+w5Q4shXD6s7HQ@mail.gmail.com>
  2016-06-15 13:49   ` Mark Brown
  2016-06-15 10:17 ` [PATCH v5 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information Juri Lelli
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi, Mark Brown

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@linaro.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)
---
 arch/arm64/kernel/topology.c | 145 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 145 insertions(+)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 694f6de..780c2c7 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -19,10 +19,152 @@
 #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 = kzalloc(sizeof(*raw_capacity) *
+					num_possible_cpus(), 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 {
+		pr_err("cpu_capacity: missing %s raw capacity "
+		       "(fallback to 1024 for all CPUs)\n",
+				cpu_node->full_name);
+		cap_parsing_failed = true;
+		kfree(raw_capacity);
+	}
+}
+
+static void normalize_cpu_capacity(void)
+{
+	u64 capacity;
+	int cpu;
+
+	if (WARN_ON(!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 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->max / 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;
+		}
+	}
+	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);
+#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 +176,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;
 		}
@@ -185,6 +328,8 @@ static int __init parse_dt_topology(void)
 	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] 19+ messages in thread

* [PATCH v5 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (3 preceding siblings ...)
  2016-06-15 10:17 ` [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 6/8] arm64, dts: add Juno r2 " Juri Lelli
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi, Pawel Moll, Ian Campbell,
	Kumar Gala, Liviu Dudau, Arnd Bergmann, Jon Medhurst,
	Olof Johansson, Robin Murphy

Add Juno cpu capacity-dmips-mhz bindings 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
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v1:
  - capacity-scale removed

Changes from v4:
  - binding changed to capacity-dmips-mhz
---
 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 dcfcf15..ad07815 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] 19+ messages in thread

* [PATCH v5 6/8] arm64, dts: add Juno r2 cpu capacity-dmips-mhz information
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (4 preceding siblings ...)
  2016-06-15 10:17 ` [PATCH v5 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 7/8] arm: add sysfs cpu_capacity attribute Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 8/8] arm64: " Juri Lelli
  7 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi, Pawel Moll, Ian Campbell,
	Kumar Gala, Liviu Dudau, Arnd Bergmann, Jon Medhurst,
	Olof Johansson, Robin Murphy

Add Juno r2 cpu capacity-dmips-mhz bindings 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
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---

Changes from v4:
  - new patch since Juno r2 dt has been merged
---
 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 88ecd61..823b614b 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] 19+ messages in thread

* [PATCH v5 7/8] arm: add sysfs cpu_capacity attribute
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (5 preceding siblings ...)
  2016-06-15 10:17 ` [PATCH v5 6/8] arm64, dts: add Juno r2 " Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  2016-06-15 10:17 ` [PATCH v5 8/8] arm64: " Juri Lelli
  7 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi

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>
---
 arch/arm/kernel/topology.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 2bab290..a240bbd 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -52,6 +52,74 @@ 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;
+
+		for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
+			set_capacity_scale(i, new_capacity);
+	}
+
+	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;
-- 
2.7.0

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

* [PATCH v5 8/8] arm64: add sysfs cpu_capacity attribute
  2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
                   ` (6 preceding siblings ...)
  2016-06-15 10:17 ` [PATCH v5 7/8] arm: add sysfs cpu_capacity attribute Juri Lelli
@ 2016-06-15 10:17 ` Juri Lelli
  7 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:17 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, sgurrappadi, Mark Brown

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@linaro.org>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
---
 arch/arm64/kernel/topology.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 780c2c7..33a35411 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -37,6 +37,74 @@ 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;
+
+		for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
+			set_capacity_scale(i, new_capacity);
+	}
+
+	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;
-- 
2.7.0

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

* Re: [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT
       [not found]   ` <CADRr18P=EOwpZTc-aS=4cCa8B3ObpuqpbNNv+w5Q4shXD6s7HQ@mail.gmail.com>
@ 2016-06-15 10:25     ` Juri Lelli
  0 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 10:25 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-kernel, linux-pm, LAK, devicetree, peterz, Vincent Guittot,
	robh+dt, Mark Rutland, linux, Sudeep Holla,
	Lorenzo Pieralisi (lorenzo.pieralisi@arm.com),
	Catalin Marinas, Will Deacon, Morten Rasmussen, Dietmar Eggemann,
	Mark Brown, sgurrappadi

On 15/06/16 11:20, Mark Brown wrote:
> On 15 June 2016 at 11:17, Juri Lelli <juri.lelli@arm.com> wrote:
> 
> 
> > Cc: Mark Brown <broonie@linaro.org>
> >
> 
> Please use broonie@kernel.org for any upstream work, I'm really not set up
> to handle upstream stuff on my Linaro address.

Sure. Will update the address.

Best,

- Juri

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
@ 2016-06-15 12:51   ` Vincent Guittot
  2016-06-15 14:24     ` Juri Lelli
  2016-06-15 14:04   ` Mark Brown
  2016-06-15 22:11   ` Rob Herring
  2 siblings, 1 reply; 19+ messages in thread
From: Vincent Guittot @ 2016-06-15 12:51 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,
	Sai Charan Gurrappadi, Pawel Moll, Ian Campbell, Kumar Gala,
	Maxime Ripard, Olof Johansson, Gregory CLEMENT, Paul Walmsley,
	Linus Walleij, Chen-Yu Tsai, Thomas Petazzoni

On 15 June 2016 at 12:17, Juri Lelli <juri.lelli@arm.com> wrote:
> 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
> 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
> ---
>  .../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 0000000..7582a13
> --- /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 (the scheduler in particular) for

not sure that it's worth mentioning the scheduler in particular here

> +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 aspersions 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. 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).

looks good to me

> +
> +===========================================
> +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 3f0cbbb..d79442d 100644
> --- a/Documentation/devicetree/bindings/arm/cpus.txt
> +++ b/Documentation/devicetree/bindings/arm/cpus.txt
> @@ -238,6 +238,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"
> @@ -461,3 +469,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	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT
  2016-06-15 10:17 ` [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
       [not found]   ` <CADRr18P=EOwpZTc-aS=4cCa8B3ObpuqpbNNv+w5Q4shXD6s7HQ@mail.gmail.com>
@ 2016-06-15 13:49   ` Mark Brown
  2016-06-15 14:48     ` Juri Lelli
  1 sibling, 1 reply; 19+ messages in thread
From: Mark Brown @ 2016-06-15 13:49 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,
	lorenzo.pieralisi, catalin.marinas, will.deacon,
	morten.rasmussen, dietmar.eggemann, sgurrappadi

[-- Attachment #1: Type: text/plain, Size: 855 bytes --]

On Wed, Jun 15, 2016 at 11:17:53AM +0100, Juri Lelli wrote:

> +		if (!raw_capacity) {
> +			raw_capacity = kzalloc(sizeof(*raw_capacity) *
> +					num_possible_cpus(), GFP_KERNEL);

kcalloc()?

> +			if (!raw_capacity) {
> +				pr_err("cpu_capacity: failed to allocate memory"
> +				       " for raw capacities\n");

It's normally better to avoid splitting errors message so people can
grep if they see the error.

> +	} else {
> +		pr_err("cpu_capacity: missing %s raw capacity "
> +		       "(fallback to 1024 for all CPUs)\n",
> +				cpu_node->full_name);

That's going to complain fairly loudly for all existing DTs isn't it and
it's kind of redundant if all the cores have the same capacity (which is
a very common case)?  How about printing an error only if we already
found one, or printing a single warning at the end if we didn't get
anything?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
  2016-06-15 12:51   ` Vincent Guittot
@ 2016-06-15 14:04   ` Mark Brown
  2016-06-15 14:22     ` Juri Lelli
  2016-06-15 22:11   ` Rob Herring
  2 siblings, 1 reply; 19+ messages in thread
From: Mark Brown @ 2016-06-15 14:04 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,
	lorenzo.pieralisi, catalin.marinas, will.deacon,
	morten.rasmussen, dietmar.eggemann, sgurrappadi, Pawel Moll,
	Ian Campbell, Kumar Gala, Maxime Ripard, Olof Johansson,
	Gregory CLEMENT, Paul Walmsley, Linus Walleij, Chen-Yu Tsai,
	Thomas Petazzoni

[-- Attachment #1: Type: text/plain, Size: 764 bytes --]

On Wed, Jun 15, 2016 at 11:17:50AM +0100, Juri Lelli wrote:

> +CPU capacities are obtained by running a suitable benchmark. This binding makes
> +no aspersions on the validity or suitability of any particular benchmark, the
> +final capacity should, however, be:

Makes no guarantees.  An aspersion is an insult!

> +CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
> +max frequency. 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.

Perhaps worth mentioning that caches and so on should be enabled (based
on previous experience with people doing bringup)?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 14:04   ` Mark Brown
@ 2016-06-15 14:22     ` Juri Lelli
  0 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 14:22 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-kernel, 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, sgurrappadi, Pawel Moll,
	Ian Campbell, Kumar Gala, Maxime Ripard, Olof Johansson,
	Gregory CLEMENT, Paul Walmsley, Linus Walleij, Chen-Yu Tsai,
	Thomas Petazzoni

On 15/06/16 15:04, Mark Brown wrote:
> On Wed, Jun 15, 2016 at 11:17:50AM +0100, Juri Lelli wrote:
> 
> > +CPU capacities are obtained by running a suitable benchmark. This binding makes
> > +no aspersions on the validity or suitability of any particular benchmark, the
> > +final capacity should, however, be:
> 
> Makes no guarantees.  An aspersion is an insult!
> 

Whoops! :-/

Sure, I'll change that.

> > +CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
> > +max frequency. 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.
> 
> Perhaps worth mentioning that caches and so on should be enabled (based
> on previous experience with people doing bringup)?

OK. I'll add something along this line.

Thanks,

- Juri

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 12:51   ` Vincent Guittot
@ 2016-06-15 14:24     ` Juri Lelli
  0 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 14:24 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,
	Sai Charan Gurrappadi, Pawel Moll, Ian Campbell, Kumar Gala,
	Maxime Ripard, Olof Johansson, Gregory CLEMENT, Paul Walmsley,
	Linus Walleij, Chen-Yu Tsai, Thomas Petazzoni

On 15/06/16 14:51, Vincent Guittot wrote:
> On 15 June 2016 at 12:17, Juri Lelli <juri.lelli@arm.com> wrote:

[...]

> > +==========================================
> > +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 (the scheduler in particular) for
> 
> not sure that it's worth mentioning the scheduler in particular here
> 

OK. I can remove that bit.

> > +it to be aware of such differences and take decisions accordingly.
> > +

[...]

> > +==========================================
> > +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).
> 
> looks good to me
> 

Great! Thanks for reviewing this.

Best,

- Juri

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

* Re: [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT
  2016-06-15 13:49   ` Mark Brown
@ 2016-06-15 14:48     ` Juri Lelli
  0 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-15 14:48 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-kernel, 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, sgurrappadi

On 15/06/16 14:49, Mark Brown wrote:
> On Wed, Jun 15, 2016 at 11:17:53AM +0100, Juri Lelli wrote:
> 
> > +		if (!raw_capacity) {
> > +			raw_capacity = kzalloc(sizeof(*raw_capacity) *
> > +					num_possible_cpus(), GFP_KERNEL);
> 
> kcalloc()?
> 

Right. Will change.

> > +			if (!raw_capacity) {
> > +				pr_err("cpu_capacity: failed to allocate memory"
> > +				       " for raw capacities\n");
> 
> It's normally better to avoid splitting errors message so people can
> grep if they see the error.
> 

Tried to avoid breaking 80 columns. But, we seem to have longer pr_err
strings already. I'll change that.

> > +	} else {
> > +		pr_err("cpu_capacity: missing %s raw capacity "
> > +		       "(fallback to 1024 for all CPUs)\n",
> > +				cpu_node->full_name);
> 
> That's going to complain fairly loudly for all existing DTs isn't it and
> it's kind of redundant if all the cores have the same capacity (which is
> a very common case)?  How about printing an error only if we already
> found one, or printing a single warning at the end if we didn't get
> anything?

Right, I'll change the condition for which pr_err is emitted. I think
the situation for which we care the most about is when we find partial
information in DT.

Thanks,

- Juri

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
  2016-06-15 12:51   ` Vincent Guittot
  2016-06-15 14:04   ` Mark Brown
@ 2016-06-15 22:11   ` Rob Herring
  2016-06-16  8:20     ` Juri Lelli
  2 siblings, 1 reply; 19+ messages in thread
From: Rob Herring @ 2016-06-15 22:11 UTC (permalink / raw)
  To: Juri Lelli
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	Vincent Guittot, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, dietmar.eggemann, Mark Brown, sgurrappadi,
	Pawel Moll, Ian Campbell, Kumar Gala, Maxime Ripard,
	Olof Johansson, Gregory CLEMENT, Paul Walmsley, Linus Walleij,
	Chen-Yu Tsai, Thomas Petazzoni

On Wed, Jun 15, 2016 at 5:17 AM, Juri Lelli <juri.lelli@arm.com> wrote:
> 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
> 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
> ---
>  .../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 0000000..7582a13
> --- /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 (the scheduler in particular) 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 aspersions 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. 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.

So the property says it represents DMIPS/MHz, but we take that and
"normalize" them back to a made up numbers? Perhaps that step should
be optional. Then paranoid Si vendors can put their fake numbers in
and end users can update the dts files with real numbers.

Is there any point in allowing people to pick their own scale? Why not
just 100 (as in percent)?

Rob

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-15 22:11   ` Rob Herring
@ 2016-06-16  8:20     ` Juri Lelli
  2016-06-22 16:51       ` Juri Lelli
  0 siblings, 1 reply; 19+ messages in thread
From: Juri Lelli @ 2016-06-16  8:20 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	Vincent Guittot, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, dietmar.eggemann, Mark Brown, sgurrappadi,
	Pawel Moll, Ian Campbell, Kumar Gala, Maxime Ripard,
	Olof Johansson, Gregory CLEMENT, Paul Walmsley, Linus Walleij,
	Chen-Yu Tsai, Thomas Petazzoni

Hi,

On 15/06/16 17:11, Rob Herring wrote:
> On Wed, Jun 15, 2016 at 5:17 AM, Juri Lelli <juri.lelli@arm.com> wrote:

[...]

> > +==========================================
> > +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 aspersions 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. 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.
> 
> So the property says it represents DMIPS/MHz, but we take that and
> "normalize" them back to a made up numbers?

The normalization step is required if one wants to prevent
cross-platform comparisons (I think that's what vendors generally want).
They are not made up, they still come from measured DMIPS/MHz values.

> Perhaps that step should
> be optional. Then paranoid Si vendors can put their fake numbers in
> and end users can update the dts files with real numbers.
> 

But, you can also decide to skip that step and put non normalized
numbers in. This documentation is advising people for what seems to be
be the most common way of coming up with values that, once in a DT,
won't be used to compare perf of different platforms.

Maybe we want to add a paragraph clearly stating this point?

> Is there any point in allowing people to pick their own scale? Why not
> just 100 (as in percent)?
> 

I think we agreed that not picking any particular scale is more flexible
and easier to use. For example, if there is a 2x factor between you cpus
you can simply put 1 and 2 there. But, if you need higher "resolution"
you can put whatever suits you better and we'll use the max as scale.

Thanks a lot for the review.

Best,

- Juri

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

* Re: [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings
  2016-06-16  8:20     ` Juri Lelli
@ 2016-06-22 16:51       ` Juri Lelli
  0 siblings, 0 replies; 19+ messages in thread
From: Juri Lelli @ 2016-06-22 16:51 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	Vincent Guittot, Mark Rutland, Russell King - ARM Linux,
	Sudeep Holla, Lorenzo Pieralisi, Catalin Marinas, Will Deacon,
	Morten Rasmussen, dietmar.eggemann, Mark Brown, sgurrappadi,
	Pawel Moll, Ian Campbell, Kumar Gala, Maxime Ripard,
	Olof Johansson, Gregory CLEMENT, Paul Walmsley, Linus Walleij,
	Chen-Yu Tsai, Thomas Petazzoni

Hi Rob,

On 16/06/16 09:20, Juri Lelli wrote:
> Hi,
> 
> On 15/06/16 17:11, Rob Herring wrote:
> > On Wed, Jun 15, 2016 at 5:17 AM, Juri Lelli <juri.lelli@arm.com> wrote:
> 
> [...]
> 
> > > +==========================================
> > > +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 aspersions 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. 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.
> > 
> > So the property says it represents DMIPS/MHz, but we take that and
> > "normalize" them back to a made up numbers?
> 
> The normalization step is required if one wants to prevent
> cross-platform comparisons (I think that's what vendors generally want).
> They are not made up, they still come from measured DMIPS/MHz values.
> 
> > Perhaps that step should
> > be optional. Then paranoid Si vendors can put their fake numbers in
> > and end users can update the dts files with real numbers.
> > 
> 
> But, you can also decide to skip that step and put non normalized
> numbers in. This documentation is advising people for what seems to be
> be the most common way of coming up with values that, once in a DT,
> won't be used to compare perf of different platforms.
> 
> Maybe we want to add a paragraph clearly stating this point?
> 
> > Is there any point in allowing people to pick their own scale? Why not
> > just 100 (as in percent)?
> > 
> 
> I think we agreed that not picking any particular scale is more flexible
> and easier to use. For example, if there is a 2x factor between you cpus
> you can simply put 1 and 2 there. But, if you need higher "resolution"
> you can put whatever suits you better and we'll use the max as scale.
> 
> Thanks a lot for the review.
> 

Do you have any further comments on this point?

Best,

- Juri

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

end of thread, other threads:[~2016-06-22 16:51 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-15 10:17 [PATCH v5 0/8] CPUs capacity information for heterogeneous systems Juri Lelli
2016-06-15 10:17 ` [PATCH v5 1/8] Documentation: arm: define DT cpu capacity-dmips-mhz bindings Juri Lelli
2016-06-15 12:51   ` Vincent Guittot
2016-06-15 14:24     ` Juri Lelli
2016-06-15 14:04   ` Mark Brown
2016-06-15 14:22     ` Juri Lelli
2016-06-15 22:11   ` Rob Herring
2016-06-16  8:20     ` Juri Lelli
2016-06-22 16:51       ` Juri Lelli
2016-06-15 10:17 ` [PATCH v5 2/8] arm: parse cpu capacity-dmips-mhz from DT Juri Lelli
2016-06-15 10:17 ` [PATCH v5 3/8] arm, dts: add TC2 cpu capacity-dmips-mhz information Juri Lelli
2016-06-15 10:17 ` [PATCH v5 4/8] arm64: parse cpu capacity-dmips-mhz from DT Juri Lelli
     [not found]   ` <CADRr18P=EOwpZTc-aS=4cCa8B3ObpuqpbNNv+w5Q4shXD6s7HQ@mail.gmail.com>
2016-06-15 10:25     ` Juri Lelli
2016-06-15 13:49   ` Mark Brown
2016-06-15 14:48     ` Juri Lelli
2016-06-15 10:17 ` [PATCH v5 5/8] arm64, dts: add Juno cpu capacity-dmips-mhz information Juri Lelli
2016-06-15 10:17 ` [PATCH v5 6/8] arm64, dts: add Juno r2 " Juri Lelli
2016-06-15 10:17 ` [PATCH v5 7/8] arm: add sysfs cpu_capacity attribute Juri Lelli
2016-06-15 10:17 ` [PATCH v5 8/8] arm64: " 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).