All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 00/27] PM/Domains: Cluster idle support for ARM SoCs
@ 2015-11-17 22:37 ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Hi all,

This series is an attempt at doing an end-to-end PSCI OS initiated solution for
SoC/Cluster idle for ARM v8 SoCs. The series is based on PM domains for CPUs
[1], which lays the foundation for IRQ safe domains and CPU domains that use
the IRQ safe property of a domain to power ON/OFF the domain when the CPUs are
in idle (either cpuidle or hotplug). This patchset is superset of [1] providing
a better picture of how the CPU domains are defined and used.  

The gist of this series is that the topology of CPU and the hierarchy is
provided in the DT for an SoC. A common library of functions help parse the DT
to initialize the generic PM domains and attach sub-domains and CPU devices to
those domains. On an ARM v8 SoC, the PSCI f/w controls the domains for low
power modes when the CPUs are in idle. CPUs call runtime PM suspend when
entering idle, which calls generic PM domains (genpd) that reference counts the
domain usage by devices/sub-domains in the domain. When the last CPU in the
domain powers down, genpd calls CPU PM domain core to power down the domain,
which in turn sets up PSCI core to pass the cluster idle states along with the
CPU idle state to the f/w.

PSCI v1.0 supports Platform coordinated and OS initiated modes. Platform
coordinated PSCI lets PSCI determine the state of the cluster based on votes
from individual CPUs. This simple solution may sometimes be inefficient, as the
PSCI f/w is unaware of the CPU and cluster sleep length and the QoS requirement
laid on the CPUs. OS initiated PSCI on the other hand lets Linux determine the
state of the cluster and the coherency domain and pass them as arguments to the
PSCI call when the last CPU enters idle. The complexity of determining the
state of the cluster and last-man reference counting rests with the kernel.

By defining CPU domains using genpd, both ARM v7 and v8 based architectures can
take advantage of the last man reference counting and cluster idle state
determination in genpd to save power - by opportunistically flushing CPU
caches, turning off supplementary hardware and powering off the CPU domain.
This patchset makes it easy for ARM v8 based PSCI f/w that supports OS
initiated do all that is needed from Linux by just specifying the CPU domain
hierarchy and idle states supported by the CPU domains in DT. ARM v7 SoCs that
control domains in Linux could still use this series in setting up CPU PM
domains for the CPUs, however, they would setup the hierarchy and supply the
domain power on/off callbacks.

This patchset builds upon genpd patches for multiple idle states from Axel [2]
and Marc [3] and Lorenzo to unify cpuidle signatures across ARM 32 and 64 [4].
I made a few amends to their patches to split the key parts relevant to this
efforts and rebase on top of 4.4-rc1. I have re-based this [7] on top of
v4.4-rc1 and tested using Kumar's patches, which has since then been replaced
with [5]. This series [7] has been tested on a QCOM APQ8016 Dragonboard with a
PSCI f/w that supports OS initiated mode.
 
Key topics for focus -
1. DT definition of cluster node in topology node.
2. DT definition of domain idle states - in comparison to arm,idle-state
3. Determining the next wake up of the CPU therefore the cluster from clock events.
4. Gen PD governor for CPU clusters.
5. Some parts are currently ARM specific (like the cpuidle parts), they could be
arch agnostic.
6. Optimizations to speed up the entire series.

Concerns -
Previous patches had raise concerns with latency added to the idle path. I have
not addressed them in this series. I focused on getting the full solution in
place at this time. A previous attempt at using runtime PM and genpd without
the use of locks is here [6]. I will re-focus my effort of making this suitable
for -RT kernel and optimizing the runtime paths and integrating them into a
future version.

Thanks,
Lina

[1]. https://lwn.net/Articles/656793/
[2]. https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1001509.html
[3]. https://lwn.net/Articles/658461/
[4]. http://www.spinics.net/lists/arm-kernel/msg451502.html
[5]. https://lkml.org/lkml/2015/10/26/651
[6]. https://patches.linaro.org/54565/
[7]. https://git.linaro.org/people/lina.iyer/linux-next.git/shortlog/refs/heads/genpd-psci-3

Axel Haslam (3):
  PM / Domains: core changes for multiple states
  PM / Domains: make governor select deepest state
  PM / Domains: remove old power on/off latencies.

Kumar Gala (2):
  arm64: dts: Add Qualcomm MSM8916, MTP8916, APQ8016, SBC8016 ids
  devicetree: bindings: Document qcom,msm-id and qcom,board-id

Lina Iyer (19):
  PM / Domain: Add additional state specific param
  PM / Domains: Read domain residency from DT
  PM / Domains: Support IRQ safe PM domains
  PM / Domains: Attempt runtime suspend of IRQ safe parent domain
  drivers: power: Introduce PM domains for CPUs/clusters
  drivers: cpu: Define CPU devices as IRQ safe
  ARM: cpuidle: Add runtime PM support for CPU idle
  tick: get next wakeup event for the CPU
  PM / Domains: Add next_wakeup to device's timing data
  ARM: cpuidle: Record the next wakeup event of the CPU
  drivers: cpu-pd: Record CPUs that are part of the domain
  drivers: cpu-pd: Add PM Domain governor for CPUs
  drivers: cpu-pd: Invoke CPU PM runtime on hotplug
  Documentation: ARM: topology: 'cluster' property for cluster nodes
  drivers: cpu-pd: Parse topology to setup CPU PM domains
  drivers: firmware: PSCI: Export psci_has_ext_power_state()
  ARM64: psci: Support cluster idle states for OS-Initated
  ARM64: dts: Add PSCI cpuidle support for MSM8916
  ARM64: dts: Define CPU power domain for MSM8916

Lorenzo Pieralisi (1):
  ARM: cpuidle: remove cpu parameter from the cpuidle_ops suspend hook

Marc Titinger (2):
  PM / Domains: Allow domain power states to be read from DT
  PM / Domains: add debugfs 'states' and 'timings' seq files

 Documentation/arm/cpu-domains.txt                  |  52 ++
 Documentation/devicetree/bindings/arm/msm/ids.txt  |  65 +++
 Documentation/devicetree/bindings/arm/topology.txt |   8 +
 .../devicetree/bindings/power/power_domain.txt     |  76 +++
 Documentation/power/devices.txt                    |  11 +-
 arch/arm/include/asm/cpuidle.h                     |   2 +-
 arch/arm/kernel/cpuidle.c                          |   2 +-
 arch/arm64/boot/dts/qcom/apq8016-sbc.dts           |   2 +
 arch/arm64/boot/dts/qcom/msm8916-mtp.dts           |   3 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |  76 +++
 arch/arm64/kernel/psci.c                           |  54 +-
 drivers/base/cpu.c                                 |   6 +-
 drivers/base/power/Makefile                        |   1 +
 drivers/base/power/cpu-pd.c                        | 507 ++++++++++++++++++
 drivers/base/power/domain.c                        | 589 +++++++++++++++++++--
 drivers/base/power/domain_governor.c               |  70 ++-
 drivers/cpuidle/cpuidle-arm.c                      |  13 +
 drivers/firmware/psci.c                            |   2 +-
 drivers/soc/qcom/spm.c                             |  10 +-
 include/dt-bindings/arm/qcom-ids.h                 |  33 ++
 include/linux/cpu-pd.h                             |  36 ++
 include/linux/pm_domain.h                          |  32 +-
 include/linux/psci.h                               |   1 +
 include/linux/tick.h                               |  10 +
 kernel/time/tick-sched.c                           |   8 +
 25 files changed, 1576 insertions(+), 93 deletions(-)
 create mode 100644 Documentation/arm/cpu-domains.txt
 create mode 100644 Documentation/devicetree/bindings/arm/msm/ids.txt
 create mode 100644 drivers/base/power/cpu-pd.c
 create mode 100644 include/dt-bindings/arm/qcom-ids.h
 create mode 100644 include/linux/cpu-pd.h

-- 
2.1.4

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

* [PATCH RFC 00/27] PM/Domains: Cluster idle support for ARM SoCs
@ 2015-11-17 22:37 ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,

This series is an attempt at doing an end-to-end PSCI OS initiated solution for
SoC/Cluster idle for ARM v8 SoCs. The series is based on PM domains for CPUs
[1], which lays the foundation for IRQ safe domains and CPU domains that use
the IRQ safe property of a domain to power ON/OFF the domain when the CPUs are
in idle (either cpuidle or hotplug). This patchset is superset of [1] providing
a better picture of how the CPU domains are defined and used.  

The gist of this series is that the topology of CPU and the hierarchy is
provided in the DT for an SoC. A common library of functions help parse the DT
to initialize the generic PM domains and attach sub-domains and CPU devices to
those domains. On an ARM v8 SoC, the PSCI f/w controls the domains for low
power modes when the CPUs are in idle. CPUs call runtime PM suspend when
entering idle, which calls generic PM domains (genpd) that reference counts the
domain usage by devices/sub-domains in the domain. When the last CPU in the
domain powers down, genpd calls CPU PM domain core to power down the domain,
which in turn sets up PSCI core to pass the cluster idle states along with the
CPU idle state to the f/w.

PSCI v1.0 supports Platform coordinated and OS initiated modes. Platform
coordinated PSCI lets PSCI determine the state of the cluster based on votes
from individual CPUs. This simple solution may sometimes be inefficient, as the
PSCI f/w is unaware of the CPU and cluster sleep length and the QoS requirement
laid on the CPUs. OS initiated PSCI on the other hand lets Linux determine the
state of the cluster and the coherency domain and pass them as arguments to the
PSCI call when the last CPU enters idle. The complexity of determining the
state of the cluster and last-man reference counting rests with the kernel.

By defining CPU domains using genpd, both ARM v7 and v8 based architectures can
take advantage of the last man reference counting and cluster idle state
determination in genpd to save power - by opportunistically flushing CPU
caches, turning off supplementary hardware and powering off the CPU domain.
This patchset makes it easy for ARM v8 based PSCI f/w that supports OS
initiated do all that is needed from Linux by just specifying the CPU domain
hierarchy and idle states supported by the CPU domains in DT. ARM v7 SoCs that
control domains in Linux could still use this series in setting up CPU PM
domains for the CPUs, however, they would setup the hierarchy and supply the
domain power on/off callbacks.

This patchset builds upon genpd patches for multiple idle states from Axel [2]
and Marc [3] and Lorenzo to unify cpuidle signatures across ARM 32 and 64 [4].
I made a few amends to their patches to split the key parts relevant to this
efforts and rebase on top of 4.4-rc1. I have re-based this [7] on top of
v4.4-rc1 and tested using Kumar's patches, which has since then been replaced
with [5]. This series [7] has been tested on a QCOM APQ8016 Dragonboard with a
PSCI f/w that supports OS initiated mode.
 
Key topics for focus -
1. DT definition of cluster node in topology node.
2. DT definition of domain idle states - in comparison to arm,idle-state
3. Determining the next wake up of the CPU therefore the cluster from clock events.
4. Gen PD governor for CPU clusters.
5. Some parts are currently ARM specific (like the cpuidle parts), they could be
arch agnostic.
6. Optimizations to speed up the entire series.

Concerns -
Previous patches had raise concerns with latency added to the idle path. I have
not addressed them in this series. I focused on getting the full solution in
place at this time. A previous attempt at using runtime PM and genpd without
the use of locks is here [6]. I will re-focus my effort of making this suitable
for -RT kernel and optimizing the runtime paths and integrating them into a
future version.

Thanks,
Lina

[1]. https://lwn.net/Articles/656793/
[2]. https://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1001509.html
[3]. https://lwn.net/Articles/658461/
[4]. http://www.spinics.net/lists/arm-kernel/msg451502.html
[5]. https://lkml.org/lkml/2015/10/26/651
[6]. https://patches.linaro.org/54565/
[7]. https://git.linaro.org/people/lina.iyer/linux-next.git/shortlog/refs/heads/genpd-psci-3

Axel Haslam (3):
  PM / Domains: core changes for multiple states
  PM / Domains: make governor select deepest state
  PM / Domains: remove old power on/off latencies.

Kumar Gala (2):
  arm64: dts: Add Qualcomm MSM8916, MTP8916, APQ8016, SBC8016 ids
  devicetree: bindings: Document qcom,msm-id and qcom,board-id

Lina Iyer (19):
  PM / Domain: Add additional state specific param
  PM / Domains: Read domain residency from DT
  PM / Domains: Support IRQ safe PM domains
  PM / Domains: Attempt runtime suspend of IRQ safe parent domain
  drivers: power: Introduce PM domains for CPUs/clusters
  drivers: cpu: Define CPU devices as IRQ safe
  ARM: cpuidle: Add runtime PM support for CPU idle
  tick: get next wakeup event for the CPU
  PM / Domains: Add next_wakeup to device's timing data
  ARM: cpuidle: Record the next wakeup event of the CPU
  drivers: cpu-pd: Record CPUs that are part of the domain
  drivers: cpu-pd: Add PM Domain governor for CPUs
  drivers: cpu-pd: Invoke CPU PM runtime on hotplug
  Documentation: ARM: topology: 'cluster' property for cluster nodes
  drivers: cpu-pd: Parse topology to setup CPU PM domains
  drivers: firmware: PSCI: Export psci_has_ext_power_state()
  ARM64: psci: Support cluster idle states for OS-Initated
  ARM64: dts: Add PSCI cpuidle support for MSM8916
  ARM64: dts: Define CPU power domain for MSM8916

Lorenzo Pieralisi (1):
  ARM: cpuidle: remove cpu parameter from the cpuidle_ops suspend hook

Marc Titinger (2):
  PM / Domains: Allow domain power states to be read from DT
  PM / Domains: add debugfs 'states' and 'timings' seq files

 Documentation/arm/cpu-domains.txt                  |  52 ++
 Documentation/devicetree/bindings/arm/msm/ids.txt  |  65 +++
 Documentation/devicetree/bindings/arm/topology.txt |   8 +
 .../devicetree/bindings/power/power_domain.txt     |  76 +++
 Documentation/power/devices.txt                    |  11 +-
 arch/arm/include/asm/cpuidle.h                     |   2 +-
 arch/arm/kernel/cpuidle.c                          |   2 +-
 arch/arm64/boot/dts/qcom/apq8016-sbc.dts           |   2 +
 arch/arm64/boot/dts/qcom/msm8916-mtp.dts           |   3 +
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |  76 +++
 arch/arm64/kernel/psci.c                           |  54 +-
 drivers/base/cpu.c                                 |   6 +-
 drivers/base/power/Makefile                        |   1 +
 drivers/base/power/cpu-pd.c                        | 507 ++++++++++++++++++
 drivers/base/power/domain.c                        | 589 +++++++++++++++++++--
 drivers/base/power/domain_governor.c               |  70 ++-
 drivers/cpuidle/cpuidle-arm.c                      |  13 +
 drivers/firmware/psci.c                            |   2 +-
 drivers/soc/qcom/spm.c                             |  10 +-
 include/dt-bindings/arm/qcom-ids.h                 |  33 ++
 include/linux/cpu-pd.h                             |  36 ++
 include/linux/pm_domain.h                          |  32 +-
 include/linux/psci.h                               |   1 +
 include/linux/tick.h                               |  10 +
 kernel/time/tick-sched.c                           |   8 +
 25 files changed, 1576 insertions(+), 93 deletions(-)
 create mode 100644 Documentation/arm/cpu-domains.txt
 create mode 100644 Documentation/devicetree/bindings/arm/msm/ids.txt
 create mode 100644 drivers/base/power/cpu-pd.c
 create mode 100644 include/dt-bindings/arm/qcom-ids.h
 create mode 100644 include/linux/cpu-pd.h

-- 
2.1.4

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

* [PATCH RFC 01/27] PM / Domains: core changes for multiple states
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Axel Haslam, Lina Iyer

From: Axel Haslam <ahaslam+renesas@baylibre.com>

From: Axel Haslam <ahaslam@baylibre.com>

Add the core changes to be able to declare multiple states.
When trying to set a power domain to off, genpd will be able to choose
from an array of states declared by the platform. The power on and off
latencies are now tied to a state.

States should be declared in ascending order from shallowest to deepest,
deepest meaning the state which takes longer to enter and exit.

the power_off and power_on function can use the 'state_idx' field of the
generic_pm_domain structure, to distinguish between the different states
and act accordingly.

Example:

static int pd1_power_on(struct generic_pm_domain *domain)
{
	/* domain->state_idx = state the domain is coming from */
}

static int pd1_power_off(struct generic_pm_domain *domain)
{
	/* domain->state_idx = desired powered off state */
}

const struct genpd_power_state pd_states[] = {
	{
		.name = "RET",
		.power_on_latency_ns = ON_LATENCY_FAST,
		.power_off_latency_ns = OFF_LATENCY_FAST,
	},
	{
		.name = "DEEP_RET",
		.power_on_latency_ns = ON_LATENCY_MED,
		.power_off_latency_ns = OFF_LATENCY_MED,
	},
	{
		.name = "OFF",
		.power_on_latency_ns = ON_LATENCY_SLOW,
		.power_off_latency_ns = OFF_LATENCY_SLOW,
	}
};

struct generic_pm_domain pd1 = {
	.name = "PD1",
	.power_on = pd1_power_on,
	.power_off = pd1_power_off,
	[...]
};

int xxx_init_pm_domain(){

	pd1->state = copy_of(pd_states);
	pd1->state_count = ARRAY_SIZE(pd_states);
	pm_genpd_init(pd1, true);

}

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
[Lina: Modified genpd state initialization and remove use of
save_state_latency_ns in genpd timing data]

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/domain.c          | 136 +++++++++++++++++++++++++++++++++--
 drivers/base/power/domain_governor.c |  13 +++-
 include/linux/pm_domain.h            |  10 +++
 3 files changed, 151 insertions(+), 8 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index e03b1ad..3242854 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -34,6 +34,12 @@
 	__ret;							\
 })
 
+#define GENPD_MAX_NAME_SIZE 20
+
+static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
+				       const struct genpd_power_state *st,
+				       unsigned int st_count);
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
@@ -102,6 +108,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
 
 static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
+	unsigned int state_idx = genpd->state_idx;
 	ktime_t time_start;
 	s64 elapsed_ns;
 	int ret;
@@ -118,10 +125,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 		return ret;
 
 	elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-	if (elapsed_ns <= genpd->power_on_latency_ns)
+	if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
 		return ret;
 
-	genpd->power_on_latency_ns = elapsed_ns;
+	genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
 	genpd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "on", elapsed_ns);
@@ -131,6 +138,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 
 static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 {
+	unsigned int state_idx = genpd->state_idx;
 	ktime_t time_start;
 	s64 elapsed_ns;
 	int ret;
@@ -147,10 +155,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 		return ret;
 
 	elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-	if (elapsed_ns <= genpd->power_off_latency_ns)
+	if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
 		return ret;
 
-	genpd->power_off_latency_ns = elapsed_ns;
+	genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
 	genpd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "off", elapsed_ns);
@@ -582,6 +590,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
 	    || atomic_read(&genpd->sd_count) > 0)
 		return;
 
+	/* Choose the deepest state when suspending */
+	genpd->state_idx = genpd->state_count - 1;
 	genpd_power_off(genpd, timed);
 
 	genpd->status = GPD_STATE_POWER_OFF;
@@ -1205,6 +1215,61 @@ static void genpd_free_dev_data(struct device *dev,
 	dev_pm_put_subsys_data(dev);
 }
 
+static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
+				   const struct genpd_power_state *st,
+				   unsigned int st_count)
+{
+	int ret = 0;
+	unsigned int i;
+
+	if (IS_ERR_OR_NULL(genpd)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (!st || (st_count < 1)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Allocate the local memory to keep the states for this genpd */
+	genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
+	if (!genpd->states) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < st_count; i++) {
+		genpd->states[i].power_on_latency_ns =
+			st[i].power_on_latency_ns;
+		genpd->states[i].power_off_latency_ns =
+			st[i].power_off_latency_ns;
+	}
+
+	/*
+	 * Copy the latency values To keep compatibility with
+	 * platforms that are not converted to use the multiple states.
+	 * This will be removed once all platforms are converted to use
+	 * multiple states. note that non converted platforms will use the
+	 * default single off state.
+	 */
+	if (genpd->power_on_latency_ns != 0)
+		genpd->states[0].power_on_latency_ns =
+				genpd->power_on_latency_ns;
+
+	if (genpd->power_off_latency_ns != 0)
+		genpd->states[0].power_off_latency_ns =
+				genpd->power_off_latency_ns;
+
+	genpd->state_count = st_count;
+
+	/* to save memory, Name allocation will happen if debug is enabled */
+	pm_genpd_alloc_states_names(genpd, st, st_count);
+
+err:
+	return ret;
+}
+
 /**
  * __pm_genpd_add_device - Add a device to an I/O PM domain.
  * @genpd: PM domain to add the device to.
@@ -1459,6 +1524,15 @@ static int pm_genpd_default_restore_state(struct device *dev)
 void pm_genpd_init(struct generic_pm_domain *genpd,
 		   struct dev_power_governor *gov, bool is_off)
 {
+	int ret;
+	static const struct genpd_power_state genpd_default_off[] = {
+		{
+			.name = "OFF",
+			.power_off_latency_ns = 0,
+			.power_on_latency_ns = 0,
+		},
+	};
+
 	if (IS_ERR_OR_NULL(genpd))
 		return;
 
@@ -1503,6 +1577,19 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 		genpd->dev_ops.start = pm_clk_resume;
 	}
 
+	/*
+	 * Allocate the default state if genpd states
+	 * are not already defined.
+	 */
+	if (!genpd->state_count) {
+		ret = genpd_alloc_states_data(genpd, genpd_default_off, 1);
+		if (ret)
+			return;
+	}
+
+	/* Assume the deepest state on init*/
+	genpd->state_idx = genpd->state_count - 1;
+
 	mutex_lock(&gpd_list_lock);
 	list_add(&genpd->gpd_list_node, &gpd_list);
 	mutex_unlock(&gpd_list_lock);
@@ -1822,6 +1909,33 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
 #include <linux/kobject.h>
 static struct dentry *pm_genpd_debugfs_dir;
 
+static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
+				       const struct genpd_power_state *st,
+				       unsigned int st_count)
+{
+	unsigned int i;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return -EINVAL;
+
+	if (genpd->state_count != st_count) {
+		pr_err("Invalid allocated state count\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < st_count; i++) {
+		genpd->states[i].name = kstrndup(st[i].name,
+				GENPD_MAX_NAME_SIZE, GFP_KERNEL);
+		if (!genpd->states[i].name) {
+			pr_err("%s Failed to allocate state %d name.\n",
+				genpd->name, i);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * TODO: This function is a slightly modified version of rtpm_status_show
  * from sysfs.c, so generalize it.
@@ -1855,6 +1969,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
 		[GPD_STATE_ACTIVE] = "on",
 		[GPD_STATE_POWER_OFF] = "off"
 	};
+	unsigned int state_idx = genpd->state_idx;
 	struct pm_domain_data *pm_data;
 	const char *kobj_path;
 	struct gpd_link *link;
@@ -1866,7 +1981,11 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
 	if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
 		goto exit;
-	seq_printf(s, "%-30s  %-15s ", genpd->name, status_lookup[genpd->status]);
+
+	seq_printf(s, "%-30s  %-15s  ", genpd->name,
+		   (genpd->status == GPD_STATE_POWER_OFF) ?
+		   genpd->states[state_idx].name :
+		   status_lookup[genpd->status]);
 
 	/*
 	 * Modifications on the list require holding locks on both
@@ -1954,4 +2073,11 @@ static void __exit pm_genpd_debug_exit(void)
 	debugfs_remove_recursive(pm_genpd_debugfs_dir);
 }
 __exitcall(pm_genpd_debug_exit);
+#else
+static inline int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
+					const struct genpd_power_state *st,
+					unsigned int st_count)
+{
+	return 0;
+}
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index e60dd12..b4984f5 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -125,8 +125,12 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 		return genpd->cached_power_down_ok;
 	}
 
-	off_on_time_ns = genpd->power_off_latency_ns +
-				genpd->power_on_latency_ns;
+	/*
+	 * Use the only available state, until multiple state support is added
+	 * to the governor.
+	 */
+	off_on_time_ns = genpd->states[0].power_off_latency_ns +
+				genpd->states[0].power_on_latency_ns;
 
 	min_off_time_ns = -1;
 	/*
@@ -203,8 +207,11 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	 * The difference between the computed minimum subdomain or device off
 	 * time and the time needed to turn the domain on is the maximum
 	 * theoretical time this domain can spend in the "off" state.
+	 * Use the only available state, until multiple state support is added
+	 * to the governor.
 	 */
-	genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
+	genpd->max_off_time_ns = min_off_time_ns -
+		genpd->states[0].power_on_latency_ns;
 	return true;
 }
 
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index ba4ced3..11763cf 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -37,6 +37,12 @@ struct gpd_dev_ops {
 	bool (*active_wakeup)(struct device *dev);
 };
 
+struct genpd_power_state {
+	char *name;
+	s64 power_off_latency_ns;
+	s64 power_on_latency_ns;
+};
+
 struct generic_pm_domain {
 	struct dev_pm_domain domain;	/* PM domain operations */
 	struct list_head gpd_list_node;	/* Node in the global PM domains list */
@@ -66,6 +72,10 @@ struct generic_pm_domain {
 	void (*detach_dev)(struct generic_pm_domain *domain,
 			   struct device *dev);
 	unsigned int flags;		/* Bit field of configs for genpd */
+	struct genpd_power_state *states;
+	unsigned int state_count; /* number of states */
+	unsigned int state_idx; /* state that genpd will go to when off */
+
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
-- 
2.1.4

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

* [PATCH RFC 01/27] PM / Domains: core changes for multiple states
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Axel Haslam <ahaslam+renesas@baylibre.com>

From: Axel Haslam <ahaslam@baylibre.com>

Add the core changes to be able to declare multiple states.
When trying to set a power domain to off, genpd will be able to choose
from an array of states declared by the platform. The power on and off
latencies are now tied to a state.

States should be declared in ascending order from shallowest to deepest,
deepest meaning the state which takes longer to enter and exit.

the power_off and power_on function can use the 'state_idx' field of the
generic_pm_domain structure, to distinguish between the different states
and act accordingly.

Example:

static int pd1_power_on(struct generic_pm_domain *domain)
{
	/* domain->state_idx = state the domain is coming from */
}

static int pd1_power_off(struct generic_pm_domain *domain)
{
	/* domain->state_idx = desired powered off state */
}

const struct genpd_power_state pd_states[] = {
	{
		.name = "RET",
		.power_on_latency_ns = ON_LATENCY_FAST,
		.power_off_latency_ns = OFF_LATENCY_FAST,
	},
	{
		.name = "DEEP_RET",
		.power_on_latency_ns = ON_LATENCY_MED,
		.power_off_latency_ns = OFF_LATENCY_MED,
	},
	{
		.name = "OFF",
		.power_on_latency_ns = ON_LATENCY_SLOW,
		.power_off_latency_ns = OFF_LATENCY_SLOW,
	}
};

struct generic_pm_domain pd1 = {
	.name = "PD1",
	.power_on = pd1_power_on,
	.power_off = pd1_power_off,
	[...]
};

int xxx_init_pm_domain(){

	pd1->state = copy_of(pd_states);
	pd1->state_count = ARRAY_SIZE(pd_states);
	pm_genpd_init(pd1, true);

}

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
[Lina: Modified genpd state initialization and remove use of
save_state_latency_ns in genpd timing data]

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/domain.c          | 136 +++++++++++++++++++++++++++++++++--
 drivers/base/power/domain_governor.c |  13 +++-
 include/linux/pm_domain.h            |  10 +++
 3 files changed, 151 insertions(+), 8 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index e03b1ad..3242854 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -34,6 +34,12 @@
 	__ret;							\
 })
 
+#define GENPD_MAX_NAME_SIZE 20
+
+static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
+				       const struct genpd_power_state *st,
+				       unsigned int st_count);
+
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
@@ -102,6 +108,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
 
 static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
+	unsigned int state_idx = genpd->state_idx;
 	ktime_t time_start;
 	s64 elapsed_ns;
 	int ret;
@@ -118,10 +125,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 		return ret;
 
 	elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-	if (elapsed_ns <= genpd->power_on_latency_ns)
+	if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
 		return ret;
 
-	genpd->power_on_latency_ns = elapsed_ns;
+	genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
 	genpd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "on", elapsed_ns);
@@ -131,6 +138,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 
 static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 {
+	unsigned int state_idx = genpd->state_idx;
 	ktime_t time_start;
 	s64 elapsed_ns;
 	int ret;
@@ -147,10 +155,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 		return ret;
 
 	elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
-	if (elapsed_ns <= genpd->power_off_latency_ns)
+	if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
 		return ret;
 
-	genpd->power_off_latency_ns = elapsed_ns;
+	genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
 	genpd->max_off_time_changed = true;
 	pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
 		 genpd->name, "off", elapsed_ns);
@@ -582,6 +590,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
 	    || atomic_read(&genpd->sd_count) > 0)
 		return;
 
+	/* Choose the deepest state when suspending */
+	genpd->state_idx = genpd->state_count - 1;
 	genpd_power_off(genpd, timed);
 
 	genpd->status = GPD_STATE_POWER_OFF;
@@ -1205,6 +1215,61 @@ static void genpd_free_dev_data(struct device *dev,
 	dev_pm_put_subsys_data(dev);
 }
 
+static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
+				   const struct genpd_power_state *st,
+				   unsigned int st_count)
+{
+	int ret = 0;
+	unsigned int i;
+
+	if (IS_ERR_OR_NULL(genpd)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (!st || (st_count < 1)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Allocate the local memory to keep the states for this genpd */
+	genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
+	if (!genpd->states) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < st_count; i++) {
+		genpd->states[i].power_on_latency_ns =
+			st[i].power_on_latency_ns;
+		genpd->states[i].power_off_latency_ns =
+			st[i].power_off_latency_ns;
+	}
+
+	/*
+	 * Copy the latency values To keep compatibility with
+	 * platforms that are not converted to use the multiple states.
+	 * This will be removed once all platforms are converted to use
+	 * multiple states. note that non converted platforms will use the
+	 * default single off state.
+	 */
+	if (genpd->power_on_latency_ns != 0)
+		genpd->states[0].power_on_latency_ns =
+				genpd->power_on_latency_ns;
+
+	if (genpd->power_off_latency_ns != 0)
+		genpd->states[0].power_off_latency_ns =
+				genpd->power_off_latency_ns;
+
+	genpd->state_count = st_count;
+
+	/* to save memory, Name allocation will happen if debug is enabled */
+	pm_genpd_alloc_states_names(genpd, st, st_count);
+
+err:
+	return ret;
+}
+
 /**
  * __pm_genpd_add_device - Add a device to an I/O PM domain.
  * @genpd: PM domain to add the device to.
@@ -1459,6 +1524,15 @@ static int pm_genpd_default_restore_state(struct device *dev)
 void pm_genpd_init(struct generic_pm_domain *genpd,
 		   struct dev_power_governor *gov, bool is_off)
 {
+	int ret;
+	static const struct genpd_power_state genpd_default_off[] = {
+		{
+			.name = "OFF",
+			.power_off_latency_ns = 0,
+			.power_on_latency_ns = 0,
+		},
+	};
+
 	if (IS_ERR_OR_NULL(genpd))
 		return;
 
@@ -1503,6 +1577,19 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 		genpd->dev_ops.start = pm_clk_resume;
 	}
 
+	/*
+	 * Allocate the default state if genpd states
+	 * are not already defined.
+	 */
+	if (!genpd->state_count) {
+		ret = genpd_alloc_states_data(genpd, genpd_default_off, 1);
+		if (ret)
+			return;
+	}
+
+	/* Assume the deepest state on init*/
+	genpd->state_idx = genpd->state_count - 1;
+
 	mutex_lock(&gpd_list_lock);
 	list_add(&genpd->gpd_list_node, &gpd_list);
 	mutex_unlock(&gpd_list_lock);
@@ -1822,6 +1909,33 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
 #include <linux/kobject.h>
 static struct dentry *pm_genpd_debugfs_dir;
 
+static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
+				       const struct genpd_power_state *st,
+				       unsigned int st_count)
+{
+	unsigned int i;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return -EINVAL;
+
+	if (genpd->state_count != st_count) {
+		pr_err("Invalid allocated state count\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < st_count; i++) {
+		genpd->states[i].name = kstrndup(st[i].name,
+				GENPD_MAX_NAME_SIZE, GFP_KERNEL);
+		if (!genpd->states[i].name) {
+			pr_err("%s Failed to allocate state %d name.\n",
+				genpd->name, i);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * TODO: This function is a slightly modified version of rtpm_status_show
  * from sysfs.c, so generalize it.
@@ -1855,6 +1969,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
 		[GPD_STATE_ACTIVE] = "on",
 		[GPD_STATE_POWER_OFF] = "off"
 	};
+	unsigned int state_idx = genpd->state_idx;
 	struct pm_domain_data *pm_data;
 	const char *kobj_path;
 	struct gpd_link *link;
@@ -1866,7 +1981,11 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
 	if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
 		goto exit;
-	seq_printf(s, "%-30s  %-15s ", genpd->name, status_lookup[genpd->status]);
+
+	seq_printf(s, "%-30s  %-15s  ", genpd->name,
+		   (genpd->status == GPD_STATE_POWER_OFF) ?
+		   genpd->states[state_idx].name :
+		   status_lookup[genpd->status]);
 
 	/*
 	 * Modifications on the list require holding locks on both
@@ -1954,4 +2073,11 @@ static void __exit pm_genpd_debug_exit(void)
 	debugfs_remove_recursive(pm_genpd_debugfs_dir);
 }
 __exitcall(pm_genpd_debug_exit);
+#else
+static inline int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
+					const struct genpd_power_state *st,
+					unsigned int st_count)
+{
+	return 0;
+}
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index e60dd12..b4984f5 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -125,8 +125,12 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 		return genpd->cached_power_down_ok;
 	}
 
-	off_on_time_ns = genpd->power_off_latency_ns +
-				genpd->power_on_latency_ns;
+	/*
+	 * Use the only available state, until multiple state support is added
+	 * to the governor.
+	 */
+	off_on_time_ns = genpd->states[0].power_off_latency_ns +
+				genpd->states[0].power_on_latency_ns;
 
 	min_off_time_ns = -1;
 	/*
@@ -203,8 +207,11 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	 * The difference between the computed minimum subdomain or device off
 	 * time and the time needed to turn the domain on is the maximum
 	 * theoretical time this domain can spend in the "off" state.
+	 * Use the only available state, until multiple state support is added
+	 * to the governor.
 	 */
-	genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
+	genpd->max_off_time_ns = min_off_time_ns -
+		genpd->states[0].power_on_latency_ns;
 	return true;
 }
 
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index ba4ced3..11763cf 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -37,6 +37,12 @@ struct gpd_dev_ops {
 	bool (*active_wakeup)(struct device *dev);
 };
 
+struct genpd_power_state {
+	char *name;
+	s64 power_off_latency_ns;
+	s64 power_on_latency_ns;
+};
+
 struct generic_pm_domain {
 	struct dev_pm_domain domain;	/* PM domain operations */
 	struct list_head gpd_list_node;	/* Node in the global PM domains list */
@@ -66,6 +72,10 @@ struct generic_pm_domain {
 	void (*detach_dev)(struct generic_pm_domain *domain,
 			   struct device *dev);
 	unsigned int flags;		/* Bit field of configs for genpd */
+	struct genpd_power_state *states;
+	unsigned int state_count; /* number of states */
+	unsigned int state_idx; /* state that genpd will go to when off */
+
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
-- 
2.1.4

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

* [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Marc Titinger, Lina Iyer

From: Marc Titinger <mtitinger+renesas@baylibre.com>

From: Marc Titinger <mtitinger@baylibre.com>

This patch allows cluster-level idle-states to being soaked in as
generic domain power states, in order for the domain governor to chose
the most efficient power state compatible with the device constraints.
Similarly, devices can register power-states into the cluster domain, in
a manner consistent with idle-states.

This is a attempt to address device-retention states for devices that
are not hooked to runtime-pm, but feature a retention state handled by
the same firmware that handles idle-states. For instance a L2 caches.

With Juno, in this example the idle-state 'cluster-sleep-0 ' is known
from each cluster generic domain, as the deepest sate.

cat /sys/kernel/debug/pm_genpd/*

Domain             State name        Enter (ns) / Exit (ns)
-------------------------------------------------------------
a53_pd               cluster-sleep-0      1500000 / 800000
a57_pd               cluster-sleep-0      1500000 / 800000

domain                      status pstate     slaves
/device                                      runtime status
-----------------------------------------------------------------------
a53_pd                          on
/devices/system/cpu/cpu0                            active
/devices/system/cpu/cpu3                            suspended
/devices/system/cpu/cpu4                            suspended
/devices/system/cpu/cpu5                            suspended
/devices/platform/D1                                suspended
a57_pd                          cluster-sleep-0
/devices/system/cpu/cpu1                            suspended
/devices/system/cpu/cpu2                            suspended

Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
[Lina: removed dependency on dynamic states, simplified initalization,
added of_pm_genpd_init() API]
---
 .../devicetree/bindings/power/power_domain.txt     |  63 ++++++++++
 drivers/base/power/domain.c                        | 128 +++++++++++++++++++++
 include/linux/pm_domain.h                          |   6 +
 3 files changed, 197 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index 025b5e7..e2f542e 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -29,6 +29,44 @@ Optional properties:
    specified by this binding. More details about power domain specifier are
    available in the next section.
 
+- power-states : A phandle of an idle-state that shall be soaked into a
+                generic domain power state. The power-state shall be
+		compatible with "linux,domain-state".
+
+==Power state==
+
+A PM domain power state describes an idle state of a domain and must be
+have the following properties -
+
+	- compatible
+		Usage: Required
+		Value type: <stringlist>
+		Definition: Must be "linux,domain-state"
+
+	- entry-latency-us
+		Usage: Not required if wakeup-latency-us is provided.
+		Value type: <prop-encoded-array>
+		Definition: u32 value representing worst case latency in
+		microseconds required to enter the idle state.
+		The exit-latency-us duration may be guaranteed
+		only after entry-latency-us has passed.
+
+	- exit-latency-us
+		Usage: Not required if wakeup-latency-us is provided.
+		Value type: <prop-encoded-array>
+		Definition: u32 value representing worst case latency
+		in microseconds required to exit the idle state.
+
+	- wakeup-latency-us:
+		Usage: Not required if entry-latency-us and exit-latency-us
+		are provided.
+		Value type: <prop-encoded-array>
+		Definition: u32 value representing maximum delay between the
+		signaling the wakeup of the domain and the domain resuming
+		regular operation.
+		If omitted, this is assumed to be equal to:
+			entry-latency-us + exit-latency-us
+
 Example:
 
 	power: power-controller@12340000 {
@@ -55,6 +93,31 @@ Example 2:
 		#power-domain-cells = <1>;
 	};
 
+Example 3:
+
+	pm-domains {
+		a57_pd: a57_pd@ {
+			/* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/
+			compatible = "arm,pd","arm,cortex-a57";
+			#power-domain-cells = <0>;
+			power-states = <&CLUSTER_SLEEP_0>;
+		};
+
+		a53_pd: a53_pd@ {
+			/* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/
+			compatible = "arm,pd","arm,cortex-a53";
+			#power-domain-cells = <0>;
+			power-states = <&CLUSTER_SLEEP_0>;
+		};
+
+		CLUSTER_SLEEP_0: power-state@0 {
+			compatible = "pm-domain,power-state";
+			entry-latency-us = <1000>;
+			exit-latency-us = <2000>;
+		};
+	};
+
+
 The nodes above define two power controllers: 'parent' and 'child'.
 Domains created by the 'child' power controller are subdomains of '0' power
 domain provided by the 'parent' power controller.
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3242854..fe1be88 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -35,6 +35,7 @@
 })
 
 #define GENPD_MAX_NAME_SIZE 20
+#define GENPD_MAX_DOMAIN_STATES 10
 
 static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
 				       const struct genpd_power_state *st,
@@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev)
 	return cb ? cb(dev) : 0;
 }
 
+static const struct of_device_id power_state_match[] = {
+	{ .compatible = "linux,domain-state" },
+	{ }
+};
+
+static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
+					   struct device_node *state_node)
+{
+	const struct of_device_id *match_id;
+	int err = 0;
+	u32 latency;
+
+	match_id = of_match_node(power_state_match, state_node);
+	if (!match_id)
+		return -ENODEV;
+
+	err = of_property_read_u32(state_node, "wakeup-latency-us", &latency);
+	if (err) {
+		u32 entry_latency, exit_latency;
+
+		err = of_property_read_u32(state_node, "entry-latency-us",
+					   &entry_latency);
+		if (err) {
+			pr_debug(" * %s missing entry-latency-us property\n",
+				 state_node->full_name);
+			return -EINVAL;
+		}
+
+		err = of_property_read_u32(state_node, "exit-latency-us",
+					   &exit_latency);
+		if (err) {
+			pr_debug(" * %s missing exit-latency-us property\n",
+				 state_node->full_name);
+			return -EINVAL;
+		}
+		/*
+		 * If wakeup-latency-us is missing, default to entry+exit
+		 * latencies as defined in idle states bindings
+		 */
+		latency = entry_latency + exit_latency;
+	}
+
+	genpd_state->power_on_latency_ns = 1000 * latency;
+
+	err = of_property_read_u32(state_node, "entry-latency-us", &latency);
+	if (err) {
+		pr_debug(" * %s missing min-residency-us property\n",
+			 state_node->full_name);
+		return -EINVAL;
+	}
+
+	genpd_state->power_off_latency_ns = 1000 * latency;
+
+	return 0;
+}
+
+static int of_genpd_device_parse_states(struct device_node *np,
+				 struct genpd_power_state *genpd_states,
+				 int *state_count)
+{
+	struct device_node *state_node;
+	int i, err = 0;
+
+	for (i = 0;; i++) {
+		struct genpd_power_state genpd_state;
+
+		state_node = of_parse_phandle(np, "power-states", i);
+		if (!state_node)
+			break;
+
+		if (i == GENPD_MAX_DOMAIN_STATES) {
+			err = -ENOMEM;
+			break;
+		}
+
+		err = of_get_genpd_power_state(&genpd_state, state_node);
+		if (err) {
+			pr_err
+			    ("Parsing idle state node %s failed with err %d\n",
+			     state_node->full_name, err);
+			err = -EINVAL;
+			break;
+		}
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+		genpd_state.name = kstrndup(state_node->full_name,
+					    GENPD_MAX_NAME_SIZE, GFP_KERNEL);
+		if (!genpd_state.name)
+			err = -ENOMEM;
+#endif
+		of_node_put(state_node);
+		memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state));
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+		kfree(genpd_state.name);
+#endif
+	}
+	*state_count = i;
+	return err;
+}
+
 /**
  * pm_genpd_init - Initialize a generic I/O PM domain object.
  * @genpd: PM domain object to initialize.
@@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 }
 EXPORT_SYMBOL_GPL(pm_genpd_init);
 
+int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
+		   struct dev_power_governor *gov, bool is_off)
+{
+	struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } };
+	int state_count = GENPD_MAX_DOMAIN_STATES;
+	int ret;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return -EINVAL;
+
+	ret = of_genpd_device_parse_states(dn, states, &state_count);
+	if (ret) {
+		pr_err("Error parsing genpd states for %s\n", genpd->name);
+		return ret;
+	}
+
+	ret = genpd_alloc_states_data(genpd, states, state_count);
+	if (ret) {
+		pr_err("Failed to allocate states for %s\n", genpd->name);
+		return ret;
+	}
+
+	pm_genpd_init(genpd, gov, is_off);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_pm_genpd_init);
+
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 11763cf..e425911 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
 					void *data);
 
 int genpd_dev_pm_attach(struct device *dev);
+int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
+		   struct dev_power_governor *gov, bool is_off);
 #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
 static inline int __of_genpd_add_provider(struct device_node *np,
 					genpd_xlate_t xlate, void *data)
@@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev)
 {
 	return -ENODEV;
 }
+
+static inline int of_pm_genpd_init(struct device_node *dn,
+		struct generic_pm_domain *genpd,
+		struct dev_power_governor *gov, bool is_off) {}
 #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
 
 static inline int of_genpd_add_provider_simple(struct device_node *np,
-- 
2.1.4

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

* [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Titinger <mtitinger+renesas@baylibre.com>

From: Marc Titinger <mtitinger@baylibre.com>

This patch allows cluster-level idle-states to being soaked in as
generic domain power states, in order for the domain governor to chose
the most efficient power state compatible with the device constraints.
Similarly, devices can register power-states into the cluster domain, in
a manner consistent with idle-states.

This is a attempt to address device-retention states for devices that
are not hooked to runtime-pm, but feature a retention state handled by
the same firmware that handles idle-states. For instance a L2 caches.

With Juno, in this example the idle-state 'cluster-sleep-0 ' is known
from each cluster generic domain, as the deepest sate.

cat /sys/kernel/debug/pm_genpd/*

Domain             State name        Enter (ns) / Exit (ns)
-------------------------------------------------------------
a53_pd               cluster-sleep-0      1500000 / 800000
a57_pd               cluster-sleep-0      1500000 / 800000

domain                      status pstate     slaves
/device                                      runtime status
-----------------------------------------------------------------------
a53_pd                          on
/devices/system/cpu/cpu0                            active
/devices/system/cpu/cpu3                            suspended
/devices/system/cpu/cpu4                            suspended
/devices/system/cpu/cpu5                            suspended
/devices/platform/D1                                suspended
a57_pd                          cluster-sleep-0
/devices/system/cpu/cpu1                            suspended
/devices/system/cpu/cpu2                            suspended

Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
[Lina: removed dependency on dynamic states, simplified initalization,
added of_pm_genpd_init() API]
---
 .../devicetree/bindings/power/power_domain.txt     |  63 ++++++++++
 drivers/base/power/domain.c                        | 128 +++++++++++++++++++++
 include/linux/pm_domain.h                          |   6 +
 3 files changed, 197 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index 025b5e7..e2f542e 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -29,6 +29,44 @@ Optional properties:
    specified by this binding. More details about power domain specifier are
    available in the next section.
 
+- power-states : A phandle of an idle-state that shall be soaked into a
+                generic domain power state. The power-state shall be
+		compatible with "linux,domain-state".
+
+==Power state==
+
+A PM domain power state describes an idle state of a domain and must be
+have the following properties -
+
+	- compatible
+		Usage: Required
+		Value type: <stringlist>
+		Definition: Must be "linux,domain-state"
+
+	- entry-latency-us
+		Usage: Not required if wakeup-latency-us is provided.
+		Value type: <prop-encoded-array>
+		Definition: u32 value representing worst case latency in
+		microseconds required to enter the idle state.
+		The exit-latency-us duration may be guaranteed
+		only after entry-latency-us has passed.
+
+	- exit-latency-us
+		Usage: Not required if wakeup-latency-us is provided.
+		Value type: <prop-encoded-array>
+		Definition: u32 value representing worst case latency
+		in microseconds required to exit the idle state.
+
+	- wakeup-latency-us:
+		Usage: Not required if entry-latency-us and exit-latency-us
+		are provided.
+		Value type: <prop-encoded-array>
+		Definition: u32 value representing maximum delay between the
+		signaling the wakeup of the domain and the domain resuming
+		regular operation.
+		If omitted, this is assumed to be equal to:
+			entry-latency-us + exit-latency-us
+
 Example:
 
 	power: power-controller at 12340000 {
@@ -55,6 +93,31 @@ Example 2:
 		#power-domain-cells = <1>;
 	};
 
+Example 3:
+
+	pm-domains {
+		a57_pd: a57_pd@ {
+			/* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/
+			compatible = "arm,pd","arm,cortex-a57";
+			#power-domain-cells = <0>;
+			power-states = <&CLUSTER_SLEEP_0>;
+		};
+
+		a53_pd: a53_pd@ {
+			/* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/
+			compatible = "arm,pd","arm,cortex-a53";
+			#power-domain-cells = <0>;
+			power-states = <&CLUSTER_SLEEP_0>;
+		};
+
+		CLUSTER_SLEEP_0: power-state at 0 {
+			compatible = "pm-domain,power-state";
+			entry-latency-us = <1000>;
+			exit-latency-us = <2000>;
+		};
+	};
+
+
 The nodes above define two power controllers: 'parent' and 'child'.
 Domains created by the 'child' power controller are subdomains of '0' power
 domain provided by the 'parent' power controller.
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3242854..fe1be88 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -35,6 +35,7 @@
 })
 
 #define GENPD_MAX_NAME_SIZE 20
+#define GENPD_MAX_DOMAIN_STATES 10
 
 static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
 				       const struct genpd_power_state *st,
@@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev)
 	return cb ? cb(dev) : 0;
 }
 
+static const struct of_device_id power_state_match[] = {
+	{ .compatible = "linux,domain-state" },
+	{ }
+};
+
+static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
+					   struct device_node *state_node)
+{
+	const struct of_device_id *match_id;
+	int err = 0;
+	u32 latency;
+
+	match_id = of_match_node(power_state_match, state_node);
+	if (!match_id)
+		return -ENODEV;
+
+	err = of_property_read_u32(state_node, "wakeup-latency-us", &latency);
+	if (err) {
+		u32 entry_latency, exit_latency;
+
+		err = of_property_read_u32(state_node, "entry-latency-us",
+					   &entry_latency);
+		if (err) {
+			pr_debug(" * %s missing entry-latency-us property\n",
+				 state_node->full_name);
+			return -EINVAL;
+		}
+
+		err = of_property_read_u32(state_node, "exit-latency-us",
+					   &exit_latency);
+		if (err) {
+			pr_debug(" * %s missing exit-latency-us property\n",
+				 state_node->full_name);
+			return -EINVAL;
+		}
+		/*
+		 * If wakeup-latency-us is missing, default to entry+exit
+		 * latencies as defined in idle states bindings
+		 */
+		latency = entry_latency + exit_latency;
+	}
+
+	genpd_state->power_on_latency_ns = 1000 * latency;
+
+	err = of_property_read_u32(state_node, "entry-latency-us", &latency);
+	if (err) {
+		pr_debug(" * %s missing min-residency-us property\n",
+			 state_node->full_name);
+		return -EINVAL;
+	}
+
+	genpd_state->power_off_latency_ns = 1000 * latency;
+
+	return 0;
+}
+
+static int of_genpd_device_parse_states(struct device_node *np,
+				 struct genpd_power_state *genpd_states,
+				 int *state_count)
+{
+	struct device_node *state_node;
+	int i, err = 0;
+
+	for (i = 0;; i++) {
+		struct genpd_power_state genpd_state;
+
+		state_node = of_parse_phandle(np, "power-states", i);
+		if (!state_node)
+			break;
+
+		if (i == GENPD_MAX_DOMAIN_STATES) {
+			err = -ENOMEM;
+			break;
+		}
+
+		err = of_get_genpd_power_state(&genpd_state, state_node);
+		if (err) {
+			pr_err
+			    ("Parsing idle state node %s failed with err %d\n",
+			     state_node->full_name, err);
+			err = -EINVAL;
+			break;
+		}
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+		genpd_state.name = kstrndup(state_node->full_name,
+					    GENPD_MAX_NAME_SIZE, GFP_KERNEL);
+		if (!genpd_state.name)
+			err = -ENOMEM;
+#endif
+		of_node_put(state_node);
+		memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state));
+#ifdef CONFIG_PM_ADVANCED_DEBUG
+		kfree(genpd_state.name);
+#endif
+	}
+	*state_count = i;
+	return err;
+}
+
 /**
  * pm_genpd_init - Initialize a generic I/O PM domain object.
  * @genpd: PM domain object to initialize.
@@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 }
 EXPORT_SYMBOL_GPL(pm_genpd_init);
 
+int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
+		   struct dev_power_governor *gov, bool is_off)
+{
+	struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } };
+	int state_count = GENPD_MAX_DOMAIN_STATES;
+	int ret;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return -EINVAL;
+
+	ret = of_genpd_device_parse_states(dn, states, &state_count);
+	if (ret) {
+		pr_err("Error parsing genpd states for %s\n", genpd->name);
+		return ret;
+	}
+
+	ret = genpd_alloc_states_data(genpd, states, state_count);
+	if (ret) {
+		pr_err("Failed to allocate states for %s\n", genpd->name);
+		return ret;
+	}
+
+	pm_genpd_init(genpd, gov, is_off);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_pm_genpd_init);
+
 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
 /*
  * Device Tree based PM domain providers.
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 11763cf..e425911 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
 					void *data);
 
 int genpd_dev_pm_attach(struct device *dev);
+int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
+		   struct dev_power_governor *gov, bool is_off);
 #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
 static inline int __of_genpd_add_provider(struct device_node *np,
 					genpd_xlate_t xlate, void *data)
@@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev)
 {
 	return -ENODEV;
 }
+
+static inline int of_pm_genpd_init(struct device_node *dn,
+		struct generic_pm_domain *genpd,
+		struct dev_power_governor *gov, bool is_off) {}
 #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
 
 static inline int of_genpd_add_provider_simple(struct device_node *np,
-- 
2.1.4

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

* [PATCH RFC 03/27] PM / Domain: Add additional state specific param
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Allow domain states to hold additional state related data in a u32
value. This may be used by the platform driver.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/power/power_domain.txt | 6 ++++++
 drivers/base/power/domain.c                              | 6 ++++++
 include/linux/pm_domain.h                                | 1 +
 3 files changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index e2f542e..ecfaf44 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -67,6 +67,12 @@ have the following properties -
 		If omitted, this is assumed to be equal to:
 			entry-latency-us + exit-latency-us
 
+	- state-param:
+		Usage: Optional
+		Value type: <prop-encoded-array>
+		Definition: A u32 value as defined by the state. May be used
+		by the driver to hold state related u32 data.
+
 Example:
 
 	power: power-controller@12340000 {
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index fe1be88..3fb4c93 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1245,6 +1245,7 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
 			st[i].power_on_latency_ns;
 		genpd->states[i].power_off_latency_ns =
 			st[i].power_off_latency_ns;
+		genpd->states[i].param = st[i].param;
 	}
 
 	/*
@@ -1527,6 +1528,7 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 	const struct of_device_id *match_id;
 	int err = 0;
 	u32 latency;
+	u32 param;
 
 	match_id = of_match_node(power_state_match, state_node);
 	if (!match_id)
@@ -1567,6 +1569,10 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 		return -EINVAL;
 	}
 
+	err = of_property_read_u32(state_node, "state-param", &param);
+	if (!err)
+		genpd_state->param = param;
+
 	genpd_state->power_off_latency_ns = 1000 * latency;
 
 	return 0;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index e425911..15df24c 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -41,6 +41,7 @@ struct genpd_power_state {
 	char *name;
 	s64 power_off_latency_ns;
 	s64 power_on_latency_ns;
+	u32 param;
 };
 
 struct generic_pm_domain {
-- 
2.1.4


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

* [PATCH RFC 03/27] PM / Domain: Add additional state specific param
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Allow domain states to hold additional state related data in a u32
value. This may be used by the platform driver.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/power/power_domain.txt | 6 ++++++
 drivers/base/power/domain.c                              | 6 ++++++
 include/linux/pm_domain.h                                | 1 +
 3 files changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index e2f542e..ecfaf44 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -67,6 +67,12 @@ have the following properties -
 		If omitted, this is assumed to be equal to:
 			entry-latency-us + exit-latency-us
 
+	- state-param:
+		Usage: Optional
+		Value type: <prop-encoded-array>
+		Definition: A u32 value as defined by the state. May be used
+		by the driver to hold state related u32 data.
+
 Example:
 
 	power: power-controller at 12340000 {
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index fe1be88..3fb4c93 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1245,6 +1245,7 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
 			st[i].power_on_latency_ns;
 		genpd->states[i].power_off_latency_ns =
 			st[i].power_off_latency_ns;
+		genpd->states[i].param = st[i].param;
 	}
 
 	/*
@@ -1527,6 +1528,7 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 	const struct of_device_id *match_id;
 	int err = 0;
 	u32 latency;
+	u32 param;
 
 	match_id = of_match_node(power_state_match, state_node);
 	if (!match_id)
@@ -1567,6 +1569,10 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 		return -EINVAL;
 	}
 
+	err = of_property_read_u32(state_node, "state-param", &param);
+	if (!err)
+		genpd_state->param = param;
+
 	genpd_state->power_off_latency_ns = 1000 * latency;
 
 	return 0;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index e425911..15df24c 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -41,6 +41,7 @@ struct genpd_power_state {
 	char *name;
 	s64 power_off_latency_ns;
 	s64 power_on_latency_ns;
+	u32 param;
 };
 
 struct generic_pm_domain {
-- 
2.1.4

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

* [PATCH RFC 04/27] PM / Domains: make governor select deepest state
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Axel Haslam

From: Axel Haslam <ahaslam+renesas@baylibre.com>

Now that the structures of genpd can support multiple state definitions,
add the logic in the governor to select the deepest possible state when
powering down.

For this, create the new function power_down_ok_for_state which will test
if a particular state will not violate the devices and sub-domains
constraints.

default_power_down_ok is modified to try each state starting from the
deepest until a valid state is found or there are no more states to test.

the resulting state will be valid until there are latency or constraint
changes, thus, we can avoid looping every power_down, and use the cached
results instead.

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
---
 drivers/base/power/domain_governor.c | 75 +++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 30 deletions(-)

diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index b4984f5..ad69dc0 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -98,7 +98,8 @@ static bool default_stop_ok(struct device *dev)
  *
  * This routine must be executed under the PM domain's lock.
  */
-static bool default_power_down_ok(struct dev_pm_domain *pd)
+static bool power_down_ok_for_state(struct dev_pm_domain *pd,
+				     unsigned int state)
 {
 	struct generic_pm_domain *genpd = pd_to_genpd(pd);
 	struct gpd_link *link;
@@ -106,31 +107,9 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	s64 min_off_time_ns;
 	s64 off_on_time_ns;
 
-	if (genpd->max_off_time_changed) {
-		struct gpd_link *link;
+	off_on_time_ns = genpd->states[state].power_off_latency_ns +
+		genpd->states[state].power_on_latency_ns;
 
-		/*
-		 * We have to invalidate the cached results for the masters, so
-		 * use the observation that default_power_down_ok() is not
-		 * going to be called for any master until this instance
-		 * returns.
-		 */
-		list_for_each_entry(link, &genpd->slave_links, slave_node)
-			link->master->max_off_time_changed = true;
-
-		genpd->max_off_time_changed = false;
-		genpd->cached_power_down_ok = false;
-		genpd->max_off_time_ns = -1;
-	} else {
-		return genpd->cached_power_down_ok;
-	}
-
-	/*
-	 * Use the only available state, until multiple state support is added
-	 * to the governor.
-	 */
-	off_on_time_ns = genpd->states[0].power_off_latency_ns +
-				genpd->states[0].power_on_latency_ns;
 
 	min_off_time_ns = -1;
 	/*
@@ -193,8 +172,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 			min_off_time_ns = constraint_ns;
 	}
 
-	genpd->cached_power_down_ok = true;
-
 	/*
 	 * If the computed minimum device off time is negative, there are no
 	 * latency constraints, so the domain can spend arbitrary time in the
@@ -207,14 +184,52 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	 * The difference between the computed minimum subdomain or device off
 	 * time and the time needed to turn the domain on is the maximum
 	 * theoretical time this domain can spend in the "off" state.
-	 * Use the only available state, until multiple state support is added
-	 * to the governor.
 	 */
 	genpd->max_off_time_ns = min_off_time_ns -
-		genpd->states[0].power_on_latency_ns;
+			genpd->states[state].power_on_latency_ns;
 	return true;
 }
 
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
+	unsigned int last_state_idx = genpd->state_count - 1;
+	struct gpd_link *link;
+	bool retval = false;
+	unsigned int i;
+
+	/*
+	 * if there was no change on max_off_time, we can return the
+	 * cached value and we dont need to find a new target_state
+	 */
+	if (!genpd->max_off_time_changed)
+		return genpd->cached_power_down_ok;
+
+	/*
+	 * We have to invalidate the cached results for the masters, so
+	 * use the observation that default_power_down_ok() is not
+	 * going to be called for any master until this instance
+	 * returns.
+	 */
+	list_for_each_entry(link, &genpd->slave_links, slave_node)
+		link->master->max_off_time_changed = true;
+
+	genpd->max_off_time_ns = -1;
+	genpd->max_off_time_changed = false;
+
+	/* find a state to power down to, starting from the deepest */
+	for (i = 0; i < genpd->state_count; i++) {
+		if (power_down_ok_for_state(pd, last_state_idx - i)) {
+			genpd->state_idx = last_state_idx - i;
+			retval = true;
+			break;
+		}
+	}
+
+	genpd->cached_power_down_ok = retval;
+	return retval;
+}
+
 static bool always_on_power_down_ok(struct dev_pm_domain *domain)
 {
 	return false;
-- 
2.1.4


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

* [PATCH RFC 04/27] PM / Domains: make governor select deepest state
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Axel Haslam <ahaslam+renesas@baylibre.com>

Now that the structures of genpd can support multiple state definitions,
add the logic in the governor to select the deepest possible state when
powering down.

For this, create the new function power_down_ok_for_state which will test
if a particular state will not violate the devices and sub-domains
constraints.

default_power_down_ok is modified to try each state starting from the
deepest until a valid state is found or there are no more states to test.

the resulting state will be valid until there are latency or constraint
changes, thus, we can avoid looping every power_down, and use the cached
results instead.

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
---
 drivers/base/power/domain_governor.c | 75 +++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 30 deletions(-)

diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index b4984f5..ad69dc0 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -98,7 +98,8 @@ static bool default_stop_ok(struct device *dev)
  *
  * This routine must be executed under the PM domain's lock.
  */
-static bool default_power_down_ok(struct dev_pm_domain *pd)
+static bool power_down_ok_for_state(struct dev_pm_domain *pd,
+				     unsigned int state)
 {
 	struct generic_pm_domain *genpd = pd_to_genpd(pd);
 	struct gpd_link *link;
@@ -106,31 +107,9 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	s64 min_off_time_ns;
 	s64 off_on_time_ns;
 
-	if (genpd->max_off_time_changed) {
-		struct gpd_link *link;
+	off_on_time_ns = genpd->states[state].power_off_latency_ns +
+		genpd->states[state].power_on_latency_ns;
 
-		/*
-		 * We have to invalidate the cached results for the masters, so
-		 * use the observation that default_power_down_ok() is not
-		 * going to be called for any master until this instance
-		 * returns.
-		 */
-		list_for_each_entry(link, &genpd->slave_links, slave_node)
-			link->master->max_off_time_changed = true;
-
-		genpd->max_off_time_changed = false;
-		genpd->cached_power_down_ok = false;
-		genpd->max_off_time_ns = -1;
-	} else {
-		return genpd->cached_power_down_ok;
-	}
-
-	/*
-	 * Use the only available state, until multiple state support is added
-	 * to the governor.
-	 */
-	off_on_time_ns = genpd->states[0].power_off_latency_ns +
-				genpd->states[0].power_on_latency_ns;
 
 	min_off_time_ns = -1;
 	/*
@@ -193,8 +172,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 			min_off_time_ns = constraint_ns;
 	}
 
-	genpd->cached_power_down_ok = true;
-
 	/*
 	 * If the computed minimum device off time is negative, there are no
 	 * latency constraints, so the domain can spend arbitrary time in the
@@ -207,14 +184,52 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
 	 * The difference between the computed minimum subdomain or device off
 	 * time and the time needed to turn the domain on is the maximum
 	 * theoretical time this domain can spend in the "off" state.
-	 * Use the only available state, until multiple state support is added
-	 * to the governor.
 	 */
 	genpd->max_off_time_ns = min_off_time_ns -
-		genpd->states[0].power_on_latency_ns;
+			genpd->states[state].power_on_latency_ns;
 	return true;
 }
 
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
+	unsigned int last_state_idx = genpd->state_count - 1;
+	struct gpd_link *link;
+	bool retval = false;
+	unsigned int i;
+
+	/*
+	 * if there was no change on max_off_time, we can return the
+	 * cached value and we dont need to find a new target_state
+	 */
+	if (!genpd->max_off_time_changed)
+		return genpd->cached_power_down_ok;
+
+	/*
+	 * We have to invalidate the cached results for the masters, so
+	 * use the observation that default_power_down_ok() is not
+	 * going to be called for any master until this instance
+	 * returns.
+	 */
+	list_for_each_entry(link, &genpd->slave_links, slave_node)
+		link->master->max_off_time_changed = true;
+
+	genpd->max_off_time_ns = -1;
+	genpd->max_off_time_changed = false;
+
+	/* find a state to power down to, starting from the deepest */
+	for (i = 0; i < genpd->state_count; i++) {
+		if (power_down_ok_for_state(pd, last_state_idx - i)) {
+			genpd->state_idx = last_state_idx - i;
+			retval = true;
+			break;
+		}
+	}
+
+	genpd->cached_power_down_ok = retval;
+	return retval;
+}
+
 static bool always_on_power_down_ok(struct dev_pm_domain *domain)
 {
 	return false;
-- 
2.1.4

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

* [PATCH RFC 05/27] PM / Domains: remove old power on/off latencies.
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Axel Haslam

From: Axel Haslam <ahaslam+renesas@baylibre.com>

Now that all known users have been converted to use state latencies,
we can remove the latency field in the generic_pm_domain structure.

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
---
 drivers/base/power/domain.c | 15 ---------------
 include/linux/pm_domain.h   |  2 --
 2 files changed, 17 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3fb4c93..c300293 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1248,21 +1248,6 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
 		genpd->states[i].param = st[i].param;
 	}
 
-	/*
-	 * Copy the latency values To keep compatibility with
-	 * platforms that are not converted to use the multiple states.
-	 * This will be removed once all platforms are converted to use
-	 * multiple states. note that non converted platforms will use the
-	 * default single off state.
-	 */
-	if (genpd->power_on_latency_ns != 0)
-		genpd->states[0].power_on_latency_ns =
-				genpd->power_on_latency_ns;
-
-	if (genpd->power_off_latency_ns != 0)
-		genpd->states[0].power_off_latency_ns =
-				genpd->power_off_latency_ns;
-
 	genpd->state_count = st_count;
 
 	/* to save memory, Name allocation will happen if debug is enabled */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 15df24c..108a4b3 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -61,9 +61,7 @@ struct generic_pm_domain {
 	unsigned int prepared_count;	/* Suspend counter of prepared devices */
 	bool suspend_power_off;	/* Power status before system suspend */
 	int (*power_off)(struct generic_pm_domain *domain);
-	s64 power_off_latency_ns;
 	int (*power_on)(struct generic_pm_domain *domain);
-	s64 power_on_latency_ns;
 	struct gpd_dev_ops dev_ops;
 	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */
 	bool max_off_time_changed;
-- 
2.1.4

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

* [PATCH RFC 05/27] PM / Domains: remove old power on/off latencies.
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Axel Haslam <ahaslam+renesas@baylibre.com>

Now that all known users have been converted to use state latencies,
we can remove the latency field in the generic_pm_domain structure.

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
---
 drivers/base/power/domain.c | 15 ---------------
 include/linux/pm_domain.h   |  2 --
 2 files changed, 17 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 3fb4c93..c300293 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1248,21 +1248,6 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
 		genpd->states[i].param = st[i].param;
 	}
 
-	/*
-	 * Copy the latency values To keep compatibility with
-	 * platforms that are not converted to use the multiple states.
-	 * This will be removed once all platforms are converted to use
-	 * multiple states. note that non converted platforms will use the
-	 * default single off state.
-	 */
-	if (genpd->power_on_latency_ns != 0)
-		genpd->states[0].power_on_latency_ns =
-				genpd->power_on_latency_ns;
-
-	if (genpd->power_off_latency_ns != 0)
-		genpd->states[0].power_off_latency_ns =
-				genpd->power_off_latency_ns;
-
 	genpd->state_count = st_count;
 
 	/* to save memory, Name allocation will happen if debug is enabled */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 15df24c..108a4b3 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -61,9 +61,7 @@ struct generic_pm_domain {
 	unsigned int prepared_count;	/* Suspend counter of prepared devices */
 	bool suspend_power_off;	/* Power status before system suspend */
 	int (*power_off)(struct generic_pm_domain *domain);
-	s64 power_off_latency_ns;
 	int (*power_on)(struct generic_pm_domain *domain);
-	s64 power_on_latency_ns;
 	struct gpd_dev_ops dev_ops;
 	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */
 	bool max_off_time_changed;
-- 
2.1.4

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

* [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger

From: Marc Titinger <mtitinger@baylibre.com>

This purpose of these debug seq-files is to help investigate
generic power domain state transitions, based on device constraints.
requires the "multiple states" patches from Axel Haslam.

also rename 'summary' from 'pm_genpd_summary'

sample output for 'states'
==========================

  Domain             State name        Eval = 2200nter + Exit = Min_off_on (ns)
-----------------------------------------------------------------------
a53_pd               cluster-sleep-0      1500000+800000=2300000
a57_pd               d1-retention         1000000+800000=1800000
a57_pd               cluster-sleep-0      1500000+800000=2300000

sample output for 'timings'
===========================

    Domain Devices, Timings in ns
                       Stop/Start Save/Restore, Effective
----------------------------------------------------  ---
a53_pd
    /cpus/cpu@100        1060  /660    1580  /1940  ,0 (cached stop)
    /cpus/cpu@101        1060  /740    1520  /1600  ,0 (cached stop)
    /cpus/cpu@102        880   /620    1380  /1780  ,0 (cached stop)
    /cpus/cpu@103        1080  /640    1340  /1600  ,0 (cached stop)
a57_pd
    /cpus/cpu@0          1160  /740    3280  /1800  ,0 (cached stop)
    /cpus/cpu@1          780   /1400   1440  /2080  ,0 (cached stop)
    /D1                  600   /540    7140  /6420  ,2199460 (cached stop)

Signed-off-by: Marc Titinger <mtitinger@baylibre.com>
---
 drivers/base/power/domain.c | 115 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 107 insertions(+), 8 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index c300293..9a0df09 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2169,21 +2169,120 @@ static const struct file_operations pm_genpd_summary_fops = {
 	.release = single_release,
 };
 
+static int pm_genpd_states_show(struct seq_file *s, void *data)
+{
+	struct generic_pm_domain *genpd;
+
+	seq_puts(s,
+		 "\n  Domain             State name        Enter + Exit = Min_off_on (ns)\n");
+	seq_puts(s,
+		 "-----------------------------------------------------------------------\n");
+
+	list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+
+		int i;
+
+		for (i = 0; i < genpd->state_count; i++) {
+			seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
+				   genpd->name,
+				   genpd->states[i].name,
+				   genpd->states[i].power_on_latency_ns,
+				   genpd->states[i].power_off_latency_ns,
+				   genpd->states[i].power_off_latency_ns
+				   + genpd->states[i].power_on_latency_ns);
+		}
+
+	}
+
+	seq_puts(s, "\n");
+
+	return 0;
+}
+
+static int pm_genpd_states_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pm_genpd_states_show, NULL);
+}
+
+static const struct file_operations pm_genpd_states_fops = {
+	.open = pm_genpd_states_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int pm_genpd_timing_show(struct seq_file *s, void *data)
+{
+	struct generic_pm_domain *genpd;
+
+	seq_puts(s, "\n    Domain Devices, Timings in ns\n");
+	seq_puts(s,
+		 "                       Stop/Start Save/Restore, Effective\n");
+	seq_puts(s,
+		 "----------------------------------------------------  ---\n");
+
+	list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+		struct pm_domain_data *pm_data;
+
+		seq_printf(s, "%-30s", genpd->name);
+
+		list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
+			struct gpd_timing_data *td = &to_gpd_data(pm_data)->td;
+
+			if (!pm_data->dev->of_node)
+				continue;
+
+			seq_printf(s,
+				   "\n    %-20s %-6lld/%-6lld %-6lld/%-6lld,%lld %s%s",
+				   pm_data->dev->of_node->full_name,
+				   td->stop_latency_ns, td->start_latency_ns,
+				   td->save_state_latency_ns,
+				   td->restore_state_latency_ns,
+				   td->effective_constraint_ns,
+				   td->cached_stop_ok ? "(cached stop) " : "",
+				   td->constraint_changed ? "(changed)" : "");
+		}
+		seq_puts(s, "\n");
+	}
+	return 0;
+}
+
+static int pm_genpd_timing_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pm_genpd_timing_show, NULL);
+}
+
+static const struct file_operations pm_genpd_timing_fops = {
+	.open = pm_genpd_timing_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static int __init pm_genpd_debug_init(void)
 {
-	struct dentry *d;
+	struct dentry *d = NULL;
 
 	pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
 
-	if (!pm_genpd_debugfs_dir)
-		return -ENOMEM;
+	if (pm_genpd_debugfs_dir)
+		d = debugfs_create_file("summary", S_IRUGO,
+				pm_genpd_debugfs_dir, NULL,
+				&pm_genpd_summary_fops);
+	if (d)
+		d = debugfs_create_file("states", S_IRUGO,
+				pm_genpd_debugfs_dir, NULL,
+				&pm_genpd_states_fops);
+	if (d)
+		d = debugfs_create_file("timings", S_IRUGO,
+				pm_genpd_debugfs_dir, NULL,
+				&pm_genpd_timing_fops);
+	if (d)
+		return 0;
 
-	d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
-			pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops);
-	if (!d)
-		return -ENOMEM;
+	debugfs_remove_recursive(pm_genpd_debugfs_dir /*can be null*/);
 
-	return 0;
+	return -ENOMEM;
 }
 late_initcall(pm_genpd_debug_init);
 
-- 
2.1.4


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

* [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Titinger <mtitinger@baylibre.com>

This purpose of these debug seq-files is to help investigate
generic power domain state transitions, based on device constraints.
requires the "multiple states" patches from Axel Haslam.

also rename 'summary' from 'pm_genpd_summary'

sample output for 'states'
==========================

  Domain             State name        Eval = 2200nter + Exit = Min_off_on (ns)
-----------------------------------------------------------------------
a53_pd               cluster-sleep-0      1500000+800000=2300000
a57_pd               d1-retention         1000000+800000=1800000
a57_pd               cluster-sleep-0      1500000+800000=2300000

sample output for 'timings'
===========================

    Domain Devices, Timings in ns
                       Stop/Start Save/Restore, Effective
----------------------------------------------------  ---
a53_pd
    /cpus/cpu at 100        1060  /660    1580  /1940  ,0 (cached stop)
    /cpus/cpu at 101        1060  /740    1520  /1600  ,0 (cached stop)
    /cpus/cpu at 102        880   /620    1380  /1780  ,0 (cached stop)
    /cpus/cpu at 103        1080  /640    1340  /1600  ,0 (cached stop)
a57_pd
    /cpus/cpu at 0          1160  /740    3280  /1800  ,0 (cached stop)
    /cpus/cpu at 1          780   /1400   1440  /2080  ,0 (cached stop)
    /D1                  600   /540    7140  /6420  ,2199460 (cached stop)

Signed-off-by: Marc Titinger <mtitinger@baylibre.com>
---
 drivers/base/power/domain.c | 115 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 107 insertions(+), 8 deletions(-)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index c300293..9a0df09 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2169,21 +2169,120 @@ static const struct file_operations pm_genpd_summary_fops = {
 	.release = single_release,
 };
 
+static int pm_genpd_states_show(struct seq_file *s, void *data)
+{
+	struct generic_pm_domain *genpd;
+
+	seq_puts(s,
+		 "\n  Domain             State name        Enter + Exit = Min_off_on (ns)\n");
+	seq_puts(s,
+		 "-----------------------------------------------------------------------\n");
+
+	list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+
+		int i;
+
+		for (i = 0; i < genpd->state_count; i++) {
+			seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
+				   genpd->name,
+				   genpd->states[i].name,
+				   genpd->states[i].power_on_latency_ns,
+				   genpd->states[i].power_off_latency_ns,
+				   genpd->states[i].power_off_latency_ns
+				   + genpd->states[i].power_on_latency_ns);
+		}
+
+	}
+
+	seq_puts(s, "\n");
+
+	return 0;
+}
+
+static int pm_genpd_states_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pm_genpd_states_show, NULL);
+}
+
+static const struct file_operations pm_genpd_states_fops = {
+	.open = pm_genpd_states_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int pm_genpd_timing_show(struct seq_file *s, void *data)
+{
+	struct generic_pm_domain *genpd;
+
+	seq_puts(s, "\n    Domain Devices, Timings in ns\n");
+	seq_puts(s,
+		 "                       Stop/Start Save/Restore, Effective\n");
+	seq_puts(s,
+		 "----------------------------------------------------  ---\n");
+
+	list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
+		struct pm_domain_data *pm_data;
+
+		seq_printf(s, "%-30s", genpd->name);
+
+		list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
+			struct gpd_timing_data *td = &to_gpd_data(pm_data)->td;
+
+			if (!pm_data->dev->of_node)
+				continue;
+
+			seq_printf(s,
+				   "\n    %-20s %-6lld/%-6lld %-6lld/%-6lld,%lld %s%s",
+				   pm_data->dev->of_node->full_name,
+				   td->stop_latency_ns, td->start_latency_ns,
+				   td->save_state_latency_ns,
+				   td->restore_state_latency_ns,
+				   td->effective_constraint_ns,
+				   td->cached_stop_ok ? "(cached stop) " : "",
+				   td->constraint_changed ? "(changed)" : "");
+		}
+		seq_puts(s, "\n");
+	}
+	return 0;
+}
+
+static int pm_genpd_timing_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pm_genpd_timing_show, NULL);
+}
+
+static const struct file_operations pm_genpd_timing_fops = {
+	.open = pm_genpd_timing_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static int __init pm_genpd_debug_init(void)
 {
-	struct dentry *d;
+	struct dentry *d = NULL;
 
 	pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
 
-	if (!pm_genpd_debugfs_dir)
-		return -ENOMEM;
+	if (pm_genpd_debugfs_dir)
+		d = debugfs_create_file("summary", S_IRUGO,
+				pm_genpd_debugfs_dir, NULL,
+				&pm_genpd_summary_fops);
+	if (d)
+		d = debugfs_create_file("states", S_IRUGO,
+				pm_genpd_debugfs_dir, NULL,
+				&pm_genpd_states_fops);
+	if (d)
+		d = debugfs_create_file("timings", S_IRUGO,
+				pm_genpd_debugfs_dir, NULL,
+				&pm_genpd_timing_fops);
+	if (d)
+		return 0;
 
-	d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
-			pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops);
-	if (!d)
-		return -ENOMEM;
+	debugfs_remove_recursive(pm_genpd_debugfs_dir /*can be null*/);
 
-	return 0;
+	return -ENOMEM;
 }
 late_initcall(pm_genpd_debug_init);
 
-- 
2.1.4

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

* [PATCH RFC 07/27] PM / Domains: Read domain residency from DT
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Domains that have expensive suspend resume operations, may require a
certain amount of time be spent in an idle state to reap the power
saving benefit. Such domains, may provide the residency requirement for
a domain state.

Read the residency for a domain state from the DT. A domain governor may
use this information in determining the state for the domain.

Cc: Axel Haslam <ahaslam@baylibre.com>
Cc: Marc Titinger <mtitinger@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/power/power_domain.txt | 7 +++++++
 drivers/base/power/domain.c                              | 6 ++++++
 include/linux/pm_domain.h                                | 1 +
 3 files changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index ecfaf44..d71da29 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -67,6 +67,13 @@ have the following properties -
 		If omitted, this is assumed to be equal to:
 			entry-latency-us + exit-latency-us
 
+	- residency-us:
+		Usage: Optional
+		Value type: <prop-encoded-array>
+		Definition: A u32 value representing the time for which a
+		domain must be idle in the state to reap power saving benefits
+		of entering the state.
+
 	- state-param:
 		Usage: Optional
 		Value type: <prop-encoded-array>
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 9a0df09..abc81bd 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1245,6 +1245,7 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
 			st[i].power_on_latency_ns;
 		genpd->states[i].power_off_latency_ns =
 			st[i].power_off_latency_ns;
+		genpd->states[i].residency_ns = st[i].residency_ns;
 		genpd->states[i].param = st[i].param;
 	}
 
@@ -1513,6 +1514,7 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 	const struct of_device_id *match_id;
 	int err = 0;
 	u32 latency;
+	u32 residency;
 	u32 param;
 
 	match_id = of_match_node(power_state_match, state_node);
@@ -1554,6 +1556,10 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 		return -EINVAL;
 	}
 
+	err = of_property_read_u32(state_node, "residency-us", &residency);
+	if (!err)
+		genpd_state->residency_ns = 1000 * residency;
+
 	err = of_property_read_u32(state_node, "state-param", &param);
 	if (!err)
 		genpd_state->param = param;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 108a4b3..fed024a 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -41,6 +41,7 @@ struct genpd_power_state {
 	char *name;
 	s64 power_off_latency_ns;
 	s64 power_on_latency_ns;
+	s64 residency_ns;
 	u32 param;
 };
 
-- 
2.1.4

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

* [PATCH RFC 07/27] PM / Domains: Read domain residency from DT
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Domains that have expensive suspend resume operations, may require a
certain amount of time be spent in an idle state to reap the power
saving benefit. Such domains, may provide the residency requirement for
a domain state.

Read the residency for a domain state from the DT. A domain governor may
use this information in determining the state for the domain.

Cc: Axel Haslam <ahaslam@baylibre.com>
Cc: Marc Titinger <mtitinger@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/power/power_domain.txt | 7 +++++++
 drivers/base/power/domain.c                              | 6 ++++++
 include/linux/pm_domain.h                                | 1 +
 3 files changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index ecfaf44..d71da29 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -67,6 +67,13 @@ have the following properties -
 		If omitted, this is assumed to be equal to:
 			entry-latency-us + exit-latency-us
 
+	- residency-us:
+		Usage: Optional
+		Value type: <prop-encoded-array>
+		Definition: A u32 value representing the time for which a
+		domain must be idle in the state to reap power saving benefits
+		of entering the state.
+
 	- state-param:
 		Usage: Optional
 		Value type: <prop-encoded-array>
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 9a0df09..abc81bd 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1245,6 +1245,7 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
 			st[i].power_on_latency_ns;
 		genpd->states[i].power_off_latency_ns =
 			st[i].power_off_latency_ns;
+		genpd->states[i].residency_ns = st[i].residency_ns;
 		genpd->states[i].param = st[i].param;
 	}
 
@@ -1513,6 +1514,7 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 	const struct of_device_id *match_id;
 	int err = 0;
 	u32 latency;
+	u32 residency;
 	u32 param;
 
 	match_id = of_match_node(power_state_match, state_node);
@@ -1554,6 +1556,10 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
 		return -EINVAL;
 	}
 
+	err = of_property_read_u32(state_node, "residency-us", &residency);
+	if (!err)
+		genpd_state->residency_ns = 1000 * residency;
+
 	err = of_property_read_u32(state_node, "state-param", &param);
 	if (!err)
 		genpd_state->param = param;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 108a4b3..fed024a 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -41,6 +41,7 @@ struct genpd_power_state {
 	char *name;
 	s64 power_off_latency_ns;
 	s64 power_on_latency_ns;
+	s64 residency_ns;
 	u32 param;
 };
 
-- 
2.1.4

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer,
	Rafael J. Wysocki

Generic Power Domains currently support turning on/off only in process
context. This prevents the usage of PM domains for domains that could be
powered on/off in a context where IRQs are disabled. Many such domains
exist today and do not get powered off, when the IRQ safe devices in
that domain are powered off, because of this limitation.

However, not all domains can operate in IRQ safe contexts. Genpd
therefore, has to support both cases where the domain may or may not
operate in IRQ safe contexts. Configuring genpd to use an appropriate
lock for that domain, would allow domains that have IRQ safe devices to
runtime suspend and resume, in atomic context.

To achieve domain specific locking, set the domain's ->flag to
GENPD_FLAG_IRQ_SAFE while defining the domain. This indicates that genpd
should use a spinlock instead of a mutex for locking the domain. Locking
is abstracted through genpd_lock() and genpd_unlock() functions that use
the flag to determine the appropriate lock to be used for that domain.
Domains that have lower latency to suspend and resume and can operate
with IRQs disabled may now be able to save power, when the component
devices and sub-domains are idle at runtime.

The restriction this imposes on the domain hierarchy is that sub-domains
and all devices in the IRQ safe domain's hierarchy also have to be IRQ
safe, so that we dont try to lock a mutex, while holding a spinlock.
Non-IRQ safe domains may continue to have devices and sub-domains that
may or may not be IRQ safe.

Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Kevin Hilman <khilman@linaro.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Krzysztof Kozłowski <k.kozlowski@samsung.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/power/devices.txt |  11 ++-
 drivers/base/power/domain.c     | 197 ++++++++++++++++++++++++++++++++--------
 include/linux/pm_domain.h       |  12 ++-
 3 files changed, 178 insertions(+), 42 deletions(-)

diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 8ba6625..bde6141 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -607,7 +607,16 @@ individually.  Instead, a set of devices sharing a power resource can be put
 into a low-power state together at the same time by turning off the shared
 power resource.  Of course, they also need to be put into the full-power state
 together, by turning the shared power resource on.  A set of devices with this
-property is often referred to as a power domain.
+property is often referred to as a power domain. A power domain may also be
+nested inside another power domain.
+
+Devices, by default, operate in process context and if a device can operate in
+IRQ safe context, has to be explicitly set as IRQ safe. Power domains by
+default, operate in process context but could have devices that are IRQ safe.
+Such power domains cannot be powered on/off during runtime PM. On the other
+hand, an IRQ safe PM domain that can be powered on/off and suspended or resumed
+in an atomic context, may contain IRQ safe devices. Such domains may only
+contain IRQ safe devices or IRQ safe sub-domains.
 
 Support for power domains is provided through the pm_domain field of struct
 device.  This field is a pointer to an object of type struct dev_pm_domain,
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index abc81bd..8df43f8 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -44,6 +44,80 @@ static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
+static inline int genpd_lock_nosleep(struct generic_pm_domain *genpd,
+					unsigned int subclass)
+	__acquires(&genpd->slock)
+{
+	unsigned long flags;
+
+	if (subclass > 0)
+		spin_lock_irqsave_nested(&genpd->slock, flags, subclass);
+	else
+		spin_lock_irqsave(&genpd->slock, flags);
+
+	genpd->lock_flags = flags;
+	return 0;
+}
+
+static inline void genpd_unlock_nosleep(struct generic_pm_domain *genpd)
+	__releases(&genpd->slock)
+{
+	spin_unlock_irqrestore(&genpd->slock, genpd->lock_flags);
+}
+
+static inline int genpd_lock_irq(struct generic_pm_domain *genpd,
+					unsigned int subclass)
+	__acquires(&genpd->mlock)
+{
+	if (subclass > 0)
+		mutex_lock_nested(&genpd->mlock, subclass);
+	else
+		mutex_lock(&genpd->mlock);
+	return 0;
+}
+
+static inline int genpd_lock_interruptible_irq(struct generic_pm_domain *genpd)
+	__acquires(&genpd->mlock)
+{
+	return mutex_lock_interruptible(&genpd->mlock);
+}
+
+static inline void genpd_unlock_irq(struct generic_pm_domain *genpd)
+	__releases(&genpd->mlock)
+{
+	mutex_unlock(&genpd->mlock);
+}
+
+static inline int genpd_lock(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_lock_nosleep(genpd, 0)
+			: genpd_lock_irq(genpd, 0);
+}
+
+static inline int genpd_lock_nested(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_lock_nosleep(genpd, SINGLE_DEPTH_NESTING)
+			: genpd_lock_irq(genpd, SINGLE_DEPTH_NESTING);
+}
+
+static inline int genpd_lock_interruptible(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_lock_nosleep(genpd, 0)
+			: genpd_lock_interruptible_irq(genpd);
+}
+
+static inline void genpd_unlock(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_unlock_nosleep(genpd)
+			: genpd_unlock_irq(genpd);
+}
+
+static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
+		struct generic_pm_domain *genpd)
+{
+	return dev->power.irq_safe && !genpd->irq_safe;
+}
+
 /*
  * Get the generic PM domain for a particular struct device.
  * This validates the struct device pointer, the PM domain pointer,
@@ -238,9 +312,9 @@ static int genpd_poweron(struct generic_pm_domain *genpd)
 {
 	int ret;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	ret = __genpd_poweron(genpd);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 	return ret;
 }
 
@@ -282,9 +356,9 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 		spin_unlock_irq(&dev->power.lock);
 
 		if (!IS_ERR(genpd)) {
-			mutex_lock(&genpd->lock);
+			genpd_lock(genpd);
 			genpd->max_off_time_changed = true;
-			mutex_unlock(&genpd->lock);
+			genpd_unlock(genpd);
 		}
 
 		dev = dev->parent;
@@ -330,8 +404,17 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
 		if (stat > PM_QOS_FLAGS_NONE)
 			return -EBUSY;
 
-		if (!pm_runtime_suspended(pdd->dev) || pdd->dev->power.irq_safe)
+		/*
+		 * We do not want to power off the domain if the device is
+		 * not suspended or an IRQ safe device is part of this
+		 * non-IRQ safe domain.
+		 */
+		if (!pm_runtime_suspended(pdd->dev) ||
+			irq_safe_dev_in_no_sleep_domain(pdd->dev, genpd))
 			not_suspended++;
+		WARN_ONCE(irq_safe_dev_in_no_sleep_domain(pdd->dev, genpd),
+				"PM domain %s will not be powered off\n",
+				genpd->name);
 	}
 
 	if (not_suspended > 1 || (not_suspended == 1 && is_async))
@@ -381,9 +464,9 @@ static void genpd_power_off_work_fn(struct work_struct *work)
 
 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	genpd_poweroff(genpd, true);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 }
 
 /**
@@ -437,15 +520,18 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 	}
 
 	/*
-	 * If power.irq_safe is set, this routine will be run with interrupts
-	 * off, so it can't use mutexes.
+	 * If power.irq_safe is set, this routine may be run with
+	 * IRQ disabled, so suspend only if the power domain is
+	 * irq_safe.
 	 */
-	if (dev->power.irq_safe)
+	WARN_ONCE(irq_safe_dev_in_no_sleep_domain(dev, genpd),
+			"genpd %s will not be powered off\n", genpd->name);
+	if (irq_safe_dev_in_no_sleep_domain(dev, genpd))
 		return 0;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	genpd_poweroff(genpd, false);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	return 0;
 }
@@ -473,15 +559,18 @@ static int pm_genpd_runtime_resume(struct device *dev)
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	/* If power.irq_safe, the PM domain is never powered off. */
-	if (dev->power.irq_safe) {
+	/*
+	 * As we dont power off a non IRQ safe domain, which holds
+	 * an IRQ safe device, we dont need to restore power to it.
+	 */
+	if (dev->power.irq_safe && !genpd->irq_safe) {
 		timed = false;
 		goto out;
 	}
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	ret = __genpd_poweron(genpd);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (ret)
 		return ret;
@@ -695,14 +784,14 @@ static int pm_genpd_prepare(struct device *dev)
 	if (resume_needed(dev, genpd))
 		pm_runtime_resume(dev);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (genpd->prepared_count++ == 0) {
 		genpd->suspended_count = 0;
 		genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
 	}
 
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (genpd->suspend_power_off) {
 		pm_runtime_put_noidle(dev);
@@ -720,12 +809,12 @@ static int pm_genpd_prepare(struct device *dev)
 
 	ret = pm_generic_prepare(dev);
 	if (ret) {
-		mutex_lock(&genpd->lock);
+		genpd_lock(genpd);
 
 		if (--genpd->prepared_count == 0)
 			genpd->suspend_power_off = false;
 
-		mutex_unlock(&genpd->lock);
+		genpd_unlock(genpd);
 		pm_runtime_enable(dev);
 	}
 
@@ -1083,13 +1172,13 @@ static void pm_genpd_complete(struct device *dev)
 	if (IS_ERR(genpd))
 		return;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	run_complete = !genpd->suspend_power_off;
 	if (--genpd->prepared_count == 0)
 		genpd->suspend_power_off = false;
 
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (run_complete) {
 		pm_generic_complete(dev);
@@ -1275,11 +1364,18 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
 		return -EINVAL;
 
+	if (genpd->irq_safe && !dev->power.irq_safe) {
+		dev_err(dev,
+			"PM Domain %s is IRQ safe; device has to IRQ safe.\n",
+			genpd->name);
+		return -EINVAL;
+	}
+
 	gpd_data = genpd_alloc_dev_data(dev, genpd, td);
 	if (IS_ERR(gpd_data))
 		return PTR_ERR(gpd_data);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (genpd->prepared_count > 0) {
 		ret = -EAGAIN;
@@ -1296,7 +1392,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
 
  out:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (ret)
 		genpd_free_dev_data(dev, gpd_data);
@@ -1328,7 +1424,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 	gpd_data = to_gpd_data(pdd);
 	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (genpd->prepared_count > 0) {
 		ret = -EAGAIN;
@@ -1343,14 +1439,14 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 
 	list_del_init(&pdd->list_node);
 
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	genpd_free_dev_data(dev, gpd_data);
 
 	return 0;
 
  out:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 	dev_pm_qos_add_notifier(dev, &gpd_data->nb);
 
 	return ret;
@@ -1371,12 +1467,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 	    || genpd == subdomain)
 		return -EINVAL;
 
+	/*
+	 * If the domain can be powered on/off in an IRQ safe
+	 * context, ensure that the subdomain can also be
+	 * powered on/off in that context.
+	 */
+	if (genpd->irq_safe && !subdomain->irq_safe) {
+		WARN("Sub-domain (%s) in an IRQ-safe domain (%s) has to be IRQ safe\n",
+				subdomain->name, genpd->name);
+		return -EINVAL;
+	}
+
 	link = kzalloc(sizeof(*link), GFP_KERNEL);
 	if (!link)
 		return -ENOMEM;
 
-	mutex_lock(&genpd->lock);
-	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
+	genpd_lock(genpd);
+	genpd_lock_nested(subdomain);
 
 	if (genpd->status == GPD_STATE_POWER_OFF
 	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
@@ -1399,8 +1506,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 		genpd_sd_counter_inc(genpd);
 
  out:
-	mutex_unlock(&subdomain->lock);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(subdomain);
+	genpd_unlock(genpd);
 	if (ret)
 		kfree(link);
 	return ret;
@@ -1421,7 +1528,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
 		pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
@@ -1434,7 +1541,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 		if (link->slave != subdomain)
 			continue;
 
-		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
+		genpd_lock_nested(subdomain);
 
 		list_del(&link->master_node);
 		list_del(&link->slave_node);
@@ -1442,14 +1549,14 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 		if (subdomain->status != GPD_STATE_POWER_OFF)
 			genpd_sd_counter_dec(genpd);
 
-		mutex_unlock(&subdomain->lock);
+		genpd_unlock(subdomain);
 
 		ret = 0;
 		break;
 	}
 
 out:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	return ret;
 }
@@ -1612,6 +1719,17 @@ static int of_genpd_device_parse_states(struct device_node *np,
 	return err;
 }
 
+static void genpd_lock_init(struct generic_pm_domain *genpd)
+{
+	if (genpd->flags & GENPD_FLAG_IRQ_SAFE) {
+		spin_lock_init(&genpd->slock);
+		genpd->irq_safe = true;
+	} else {
+		mutex_init(&genpd->mlock);
+		genpd->irq_safe = false;
+	}
+}
+
 /**
  * pm_genpd_init - Initialize a generic I/O PM domain object.
  * @genpd: PM domain object to initialize.
@@ -1636,7 +1754,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 	INIT_LIST_HEAD(&genpd->master_links);
 	INIT_LIST_HEAD(&genpd->slave_links);
 	INIT_LIST_HEAD(&genpd->dev_list);
-	mutex_init(&genpd->lock);
+	genpd_lock_init(genpd);
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 	atomic_set(&genpd->sd_count, 0);
@@ -2100,7 +2218,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
 	struct gpd_link *link;
 	int ret;
 
-	ret = mutex_lock_interruptible(&genpd->lock);
+	ret = genpd_lock_interruptible(genpd);
 	if (ret)
 		return -ERESTARTSYS;
 
@@ -2124,7 +2242,8 @@ static int pm_genpd_summary_one(struct seq_file *s,
 	}
 
 	list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
-		kobj_path = kobject_get_path(&pm_data->dev->kobj, GFP_KERNEL);
+		kobj_path = kobject_get_path(&pm_data->dev->kobj,
+				genpd->irq_safe ? GFP_ATOMIC : GFP_KERNEL);
 		if (kobj_path == NULL)
 			continue;
 
@@ -2135,7 +2254,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
 	seq_puts(s, "\n");
 exit:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	return 0;
 }
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index fed024a..f1329ea 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -15,9 +15,11 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/notifier.h>
+#include <linux/spinlock.h>
 
 /* Defines used for the flags field in the struct generic_pm_domain */
 #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
+#define GENPD_FLAG_IRQ_SAFE	(1U << 1) /* PM domain operates in atomic */
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
@@ -51,7 +53,6 @@ struct generic_pm_domain {
 	struct list_head master_links;	/* Links with PM domain as a master */
 	struct list_head slave_links;	/* Links with PM domain as a slave */
 	struct list_head dev_list;	/* List of devices */
-	struct mutex lock;
 	struct dev_power_governor *gov;
 	struct work_struct power_off_work;
 	const char *name;
@@ -75,7 +76,14 @@ struct generic_pm_domain {
 	struct genpd_power_state *states;
 	unsigned int state_count; /* number of states */
 	unsigned int state_idx; /* state that genpd will go to when off */
-
+	bool irq_safe;
+	union {
+		struct mutex mlock;
+		struct {
+			spinlock_t slock;
+			unsigned long lock_flags;
+		};
+	};
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
-- 
2.1.4

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Generic Power Domains currently support turning on/off only in process
context. This prevents the usage of PM domains for domains that could be
powered on/off in a context where IRQs are disabled. Many such domains
exist today and do not get powered off, when the IRQ safe devices in
that domain are powered off, because of this limitation.

However, not all domains can operate in IRQ safe contexts. Genpd
therefore, has to support both cases where the domain may or may not
operate in IRQ safe contexts. Configuring genpd to use an appropriate
lock for that domain, would allow domains that have IRQ safe devices to
runtime suspend and resume, in atomic context.

To achieve domain specific locking, set the domain's ->flag to
GENPD_FLAG_IRQ_SAFE while defining the domain. This indicates that genpd
should use a spinlock instead of a mutex for locking the domain. Locking
is abstracted through genpd_lock() and genpd_unlock() functions that use
the flag to determine the appropriate lock to be used for that domain.
Domains that have lower latency to suspend and resume and can operate
with IRQs disabled may now be able to save power, when the component
devices and sub-domains are idle at runtime.

The restriction this imposes on the domain hierarchy is that sub-domains
and all devices in the IRQ safe domain's hierarchy also have to be IRQ
safe, so that we dont try to lock a mutex, while holding a spinlock.
Non-IRQ safe domains may continue to have devices and sub-domains that
may or may not be IRQ safe.

Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Kevin Hilman <khilman@linaro.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Krzysztof Koz?owski <k.kozlowski@samsung.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/power/devices.txt |  11 ++-
 drivers/base/power/domain.c     | 197 ++++++++++++++++++++++++++++++++--------
 include/linux/pm_domain.h       |  12 ++-
 3 files changed, 178 insertions(+), 42 deletions(-)

diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 8ba6625..bde6141 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -607,7 +607,16 @@ individually.  Instead, a set of devices sharing a power resource can be put
 into a low-power state together at the same time by turning off the shared
 power resource.  Of course, they also need to be put into the full-power state
 together, by turning the shared power resource on.  A set of devices with this
-property is often referred to as a power domain.
+property is often referred to as a power domain. A power domain may also be
+nested inside another power domain.
+
+Devices, by default, operate in process context and if a device can operate in
+IRQ safe context, has to be explicitly set as IRQ safe. Power domains by
+default, operate in process context but could have devices that are IRQ safe.
+Such power domains cannot be powered on/off during runtime PM. On the other
+hand, an IRQ safe PM domain that can be powered on/off and suspended or resumed
+in an atomic context, may contain IRQ safe devices. Such domains may only
+contain IRQ safe devices or IRQ safe sub-domains.
 
 Support for power domains is provided through the pm_domain field of struct
 device.  This field is a pointer to an object of type struct dev_pm_domain,
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index abc81bd..8df43f8 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -44,6 +44,80 @@ static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
+static inline int genpd_lock_nosleep(struct generic_pm_domain *genpd,
+					unsigned int subclass)
+	__acquires(&genpd->slock)
+{
+	unsigned long flags;
+
+	if (subclass > 0)
+		spin_lock_irqsave_nested(&genpd->slock, flags, subclass);
+	else
+		spin_lock_irqsave(&genpd->slock, flags);
+
+	genpd->lock_flags = flags;
+	return 0;
+}
+
+static inline void genpd_unlock_nosleep(struct generic_pm_domain *genpd)
+	__releases(&genpd->slock)
+{
+	spin_unlock_irqrestore(&genpd->slock, genpd->lock_flags);
+}
+
+static inline int genpd_lock_irq(struct generic_pm_domain *genpd,
+					unsigned int subclass)
+	__acquires(&genpd->mlock)
+{
+	if (subclass > 0)
+		mutex_lock_nested(&genpd->mlock, subclass);
+	else
+		mutex_lock(&genpd->mlock);
+	return 0;
+}
+
+static inline int genpd_lock_interruptible_irq(struct generic_pm_domain *genpd)
+	__acquires(&genpd->mlock)
+{
+	return mutex_lock_interruptible(&genpd->mlock);
+}
+
+static inline void genpd_unlock_irq(struct generic_pm_domain *genpd)
+	__releases(&genpd->mlock)
+{
+	mutex_unlock(&genpd->mlock);
+}
+
+static inline int genpd_lock(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_lock_nosleep(genpd, 0)
+			: genpd_lock_irq(genpd, 0);
+}
+
+static inline int genpd_lock_nested(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_lock_nosleep(genpd, SINGLE_DEPTH_NESTING)
+			: genpd_lock_irq(genpd, SINGLE_DEPTH_NESTING);
+}
+
+static inline int genpd_lock_interruptible(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_lock_nosleep(genpd, 0)
+			: genpd_lock_interruptible_irq(genpd);
+}
+
+static inline void genpd_unlock(struct generic_pm_domain *genpd)
+{
+	return genpd->irq_safe ? genpd_unlock_nosleep(genpd)
+			: genpd_unlock_irq(genpd);
+}
+
+static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
+		struct generic_pm_domain *genpd)
+{
+	return dev->power.irq_safe && !genpd->irq_safe;
+}
+
 /*
  * Get the generic PM domain for a particular struct device.
  * This validates the struct device pointer, the PM domain pointer,
@@ -238,9 +312,9 @@ static int genpd_poweron(struct generic_pm_domain *genpd)
 {
 	int ret;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	ret = __genpd_poweron(genpd);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 	return ret;
 }
 
@@ -282,9 +356,9 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 		spin_unlock_irq(&dev->power.lock);
 
 		if (!IS_ERR(genpd)) {
-			mutex_lock(&genpd->lock);
+			genpd_lock(genpd);
 			genpd->max_off_time_changed = true;
-			mutex_unlock(&genpd->lock);
+			genpd_unlock(genpd);
 		}
 
 		dev = dev->parent;
@@ -330,8 +404,17 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
 		if (stat > PM_QOS_FLAGS_NONE)
 			return -EBUSY;
 
-		if (!pm_runtime_suspended(pdd->dev) || pdd->dev->power.irq_safe)
+		/*
+		 * We do not want to power off the domain if the device is
+		 * not suspended or an IRQ safe device is part of this
+		 * non-IRQ safe domain.
+		 */
+		if (!pm_runtime_suspended(pdd->dev) ||
+			irq_safe_dev_in_no_sleep_domain(pdd->dev, genpd))
 			not_suspended++;
+		WARN_ONCE(irq_safe_dev_in_no_sleep_domain(pdd->dev, genpd),
+				"PM domain %s will not be powered off\n",
+				genpd->name);
 	}
 
 	if (not_suspended > 1 || (not_suspended == 1 && is_async))
@@ -381,9 +464,9 @@ static void genpd_power_off_work_fn(struct work_struct *work)
 
 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	genpd_poweroff(genpd, true);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 }
 
 /**
@@ -437,15 +520,18 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 	}
 
 	/*
-	 * If power.irq_safe is set, this routine will be run with interrupts
-	 * off, so it can't use mutexes.
+	 * If power.irq_safe is set, this routine may be run with
+	 * IRQ disabled, so suspend only if the power domain is
+	 * irq_safe.
 	 */
-	if (dev->power.irq_safe)
+	WARN_ONCE(irq_safe_dev_in_no_sleep_domain(dev, genpd),
+			"genpd %s will not be powered off\n", genpd->name);
+	if (irq_safe_dev_in_no_sleep_domain(dev, genpd))
 		return 0;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	genpd_poweroff(genpd, false);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	return 0;
 }
@@ -473,15 +559,18 @@ static int pm_genpd_runtime_resume(struct device *dev)
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	/* If power.irq_safe, the PM domain is never powered off. */
-	if (dev->power.irq_safe) {
+	/*
+	 * As we dont power off a non IRQ safe domain, which holds
+	 * an IRQ safe device, we dont need to restore power to it.
+	 */
+	if (dev->power.irq_safe && !genpd->irq_safe) {
 		timed = false;
 		goto out;
 	}
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 	ret = __genpd_poweron(genpd);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (ret)
 		return ret;
@@ -695,14 +784,14 @@ static int pm_genpd_prepare(struct device *dev)
 	if (resume_needed(dev, genpd))
 		pm_runtime_resume(dev);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (genpd->prepared_count++ == 0) {
 		genpd->suspended_count = 0;
 		genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
 	}
 
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (genpd->suspend_power_off) {
 		pm_runtime_put_noidle(dev);
@@ -720,12 +809,12 @@ static int pm_genpd_prepare(struct device *dev)
 
 	ret = pm_generic_prepare(dev);
 	if (ret) {
-		mutex_lock(&genpd->lock);
+		genpd_lock(genpd);
 
 		if (--genpd->prepared_count == 0)
 			genpd->suspend_power_off = false;
 
-		mutex_unlock(&genpd->lock);
+		genpd_unlock(genpd);
 		pm_runtime_enable(dev);
 	}
 
@@ -1083,13 +1172,13 @@ static void pm_genpd_complete(struct device *dev)
 	if (IS_ERR(genpd))
 		return;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	run_complete = !genpd->suspend_power_off;
 	if (--genpd->prepared_count == 0)
 		genpd->suspend_power_off = false;
 
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (run_complete) {
 		pm_generic_complete(dev);
@@ -1275,11 +1364,18 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
 		return -EINVAL;
 
+	if (genpd->irq_safe && !dev->power.irq_safe) {
+		dev_err(dev,
+			"PM Domain %s is IRQ safe; device has to IRQ safe.\n",
+			genpd->name);
+		return -EINVAL;
+	}
+
 	gpd_data = genpd_alloc_dev_data(dev, genpd, td);
 	if (IS_ERR(gpd_data))
 		return PTR_ERR(gpd_data);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (genpd->prepared_count > 0) {
 		ret = -EAGAIN;
@@ -1296,7 +1392,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
 
  out:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	if (ret)
 		genpd_free_dev_data(dev, gpd_data);
@@ -1328,7 +1424,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 	gpd_data = to_gpd_data(pdd);
 	dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (genpd->prepared_count > 0) {
 		ret = -EAGAIN;
@@ -1343,14 +1439,14 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 
 	list_del_init(&pdd->list_node);
 
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	genpd_free_dev_data(dev, gpd_data);
 
 	return 0;
 
  out:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 	dev_pm_qos_add_notifier(dev, &gpd_data->nb);
 
 	return ret;
@@ -1371,12 +1467,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 	    || genpd == subdomain)
 		return -EINVAL;
 
+	/*
+	 * If the domain can be powered on/off in an IRQ safe
+	 * context, ensure that the subdomain can also be
+	 * powered on/off in that context.
+	 */
+	if (genpd->irq_safe && !subdomain->irq_safe) {
+		WARN("Sub-domain (%s) in an IRQ-safe domain (%s) has to be IRQ safe\n",
+				subdomain->name, genpd->name);
+		return -EINVAL;
+	}
+
 	link = kzalloc(sizeof(*link), GFP_KERNEL);
 	if (!link)
 		return -ENOMEM;
 
-	mutex_lock(&genpd->lock);
-	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
+	genpd_lock(genpd);
+	genpd_lock_nested(subdomain);
 
 	if (genpd->status == GPD_STATE_POWER_OFF
 	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
@@ -1399,8 +1506,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 		genpd_sd_counter_inc(genpd);
 
  out:
-	mutex_unlock(&subdomain->lock);
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(subdomain);
+	genpd_unlock(genpd);
 	if (ret)
 		kfree(link);
 	return ret;
@@ -1421,7 +1528,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
 		return -EINVAL;
 
-	mutex_lock(&genpd->lock);
+	genpd_lock(genpd);
 
 	if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
 		pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
@@ -1434,7 +1541,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 		if (link->slave != subdomain)
 			continue;
 
-		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
+		genpd_lock_nested(subdomain);
 
 		list_del(&link->master_node);
 		list_del(&link->slave_node);
@@ -1442,14 +1549,14 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 		if (subdomain->status != GPD_STATE_POWER_OFF)
 			genpd_sd_counter_dec(genpd);
 
-		mutex_unlock(&subdomain->lock);
+		genpd_unlock(subdomain);
 
 		ret = 0;
 		break;
 	}
 
 out:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	return ret;
 }
@@ -1612,6 +1719,17 @@ static int of_genpd_device_parse_states(struct device_node *np,
 	return err;
 }
 
+static void genpd_lock_init(struct generic_pm_domain *genpd)
+{
+	if (genpd->flags & GENPD_FLAG_IRQ_SAFE) {
+		spin_lock_init(&genpd->slock);
+		genpd->irq_safe = true;
+	} else {
+		mutex_init(&genpd->mlock);
+		genpd->irq_safe = false;
+	}
+}
+
 /**
  * pm_genpd_init - Initialize a generic I/O PM domain object.
  * @genpd: PM domain object to initialize.
@@ -1636,7 +1754,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
 	INIT_LIST_HEAD(&genpd->master_links);
 	INIT_LIST_HEAD(&genpd->slave_links);
 	INIT_LIST_HEAD(&genpd->dev_list);
-	mutex_init(&genpd->lock);
+	genpd_lock_init(genpd);
 	genpd->gov = gov;
 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
 	atomic_set(&genpd->sd_count, 0);
@@ -2100,7 +2218,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
 	struct gpd_link *link;
 	int ret;
 
-	ret = mutex_lock_interruptible(&genpd->lock);
+	ret = genpd_lock_interruptible(genpd);
 	if (ret)
 		return -ERESTARTSYS;
 
@@ -2124,7 +2242,8 @@ static int pm_genpd_summary_one(struct seq_file *s,
 	}
 
 	list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
-		kobj_path = kobject_get_path(&pm_data->dev->kobj, GFP_KERNEL);
+		kobj_path = kobject_get_path(&pm_data->dev->kobj,
+				genpd->irq_safe ? GFP_ATOMIC : GFP_KERNEL);
 		if (kobj_path == NULL)
 			continue;
 
@@ -2135,7 +2254,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
 
 	seq_puts(s, "\n");
 exit:
-	mutex_unlock(&genpd->lock);
+	genpd_unlock(genpd);
 
 	return 0;
 }
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index fed024a..f1329ea 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -15,9 +15,11 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/notifier.h>
+#include <linux/spinlock.h>
 
 /* Defines used for the flags field in the struct generic_pm_domain */
 #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
+#define GENPD_FLAG_IRQ_SAFE	(1U << 1) /* PM domain operates in atomic */
 
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
@@ -51,7 +53,6 @@ struct generic_pm_domain {
 	struct list_head master_links;	/* Links with PM domain as a master */
 	struct list_head slave_links;	/* Links with PM domain as a slave */
 	struct list_head dev_list;	/* List of devices */
-	struct mutex lock;
 	struct dev_power_governor *gov;
 	struct work_struct power_off_work;
 	const char *name;
@@ -75,7 +76,14 @@ struct generic_pm_domain {
 	struct genpd_power_state *states;
 	unsigned int state_count; /* number of states */
 	unsigned int state_idx; /* state that genpd will go to when off */
-
+	bool irq_safe;
+	union {
+		struct mutex mlock;
+		struct {
+			spinlock_t slock;
+			unsigned long lock_flags;
+		};
+	};
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
-- 
2.1.4

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

* [PATCH RFC 09/27] PM / Domains: Attempt runtime suspend of IRQ safe parent domain
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

When a sub-domain is powered off, attempt powering off the parent
domains to maximize power savings. A sub-domain that is IRQ safe may
however have a parent that is not IRQ safe and therefore cannot be
powered down in atomic context that the sub-domain may be powered off.

An IRQ safe sub-domain may attempt to power down the parent domain in a
synchronous call, if the parent is also IRQ safe.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/domain.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 8df43f8..0310e2b 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -44,6 +44,8 @@ static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
+static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async);
+
 static inline int genpd_lock_nosleep(struct generic_pm_domain *genpd,
 					unsigned int subclass)
 	__acquires(&genpd->slock)
@@ -298,6 +300,13 @@ static int __genpd_poweron(struct generic_pm_domain *genpd)
 					&genpd->slave_links,
 					slave_node) {
 		genpd_sd_counter_dec(link->master);
+
+		/* Assume masters that are non-irq safe are always-on */
+		if (genpd->irq_safe && link->master->irq_safe) {
+			genpd_poweroff(link->master, false);
+			continue;
+		}
+
 		genpd_queue_power_off_work(link->master);
 	}
 
@@ -448,6 +457,13 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_dec(link->master);
+
+		/* Assume masters that are non-irq safe are always-on */
+		if (genpd->irq_safe && link->master->irq_safe) {
+			genpd_poweroff(link->master, false);
+			continue;
+		}
+
 		genpd_queue_power_off_work(link->master);
 	}
 
-- 
2.1.4


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

* [PATCH RFC 09/27] PM / Domains: Attempt runtime suspend of IRQ safe parent domain
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

When a sub-domain is powered off, attempt powering off the parent
domains to maximize power savings. A sub-domain that is IRQ safe may
however have a parent that is not IRQ safe and therefore cannot be
powered down in atomic context that the sub-domain may be powered off.

An IRQ safe sub-domain may attempt to power down the parent domain in a
synchronous call, if the parent is also IRQ safe.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/domain.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 8df43f8..0310e2b 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -44,6 +44,8 @@ static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
+static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async);
+
 static inline int genpd_lock_nosleep(struct generic_pm_domain *genpd,
 					unsigned int subclass)
 	__acquires(&genpd->slock)
@@ -298,6 +300,13 @@ static int __genpd_poweron(struct generic_pm_domain *genpd)
 					&genpd->slave_links,
 					slave_node) {
 		genpd_sd_counter_dec(link->master);
+
+		/* Assume masters that are non-irq safe are always-on */
+		if (genpd->irq_safe && link->master->irq_safe) {
+			genpd_poweroff(link->master, false);
+			continue;
+		}
+
 		genpd_queue_power_off_work(link->master);
 	}
 
@@ -448,6 +457,13 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
 
 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
 		genpd_sd_counter_dec(link->master);
+
+		/* Assume masters that are non-irq safe are always-on */
+		if (genpd->irq_safe && link->master->irq_safe) {
+			genpd_poweroff(link->master, false);
+			continue;
+		}
+
 		genpd_queue_power_off_work(link->master);
 	}
 
-- 
2.1.4

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

* [PATCH RFC 10/27] drivers: power: Introduce PM domains for CPUs/clusters
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Daniel Lezcano

Define and add Generic PM domains (genpd) for CPU clusters. Many new
SoCs group CPUs as clusters. Clusters share common resources like power
rails, caches, VFP, Coresight etc. When all CPUs in the cluster are
idle, these shared resources may also be put in their idle state.

The idle time between the last CPU entering idle and a CPU resuming
execution is an opportunity for these shared resources to be powered
down. Generic PM domain provides a framework for defining such power
domains and attach devices to the domain. When the devices in the domain
are idle at runtime, the domain would also be suspended and resumed
before the first of the devices resume execution.

We define a generic PM domain for each cluster and attach CPU devices in
the cluster to that PM domain. The DT definitions for the SoC describe
this relationship. Genpd callbacks for power_on and power_off can then
be used to power up/down the shared resources for the domain.

Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Kevin Hilman <khilman@linaro.org>
Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/arm/cpu-domains.txt |  52 +++++++++
 drivers/base/power/Makefile       |   1 +
 drivers/base/power/cpu-pd.c       | 231 ++++++++++++++++++++++++++++++++++++++
 include/linux/cpu-pd.h            |  32 ++++++
 4 files changed, 316 insertions(+)
 create mode 100644 Documentation/arm/cpu-domains.txt
 create mode 100644 drivers/base/power/cpu-pd.c
 create mode 100644 include/linux/cpu-pd.h

diff --git a/Documentation/arm/cpu-domains.txt b/Documentation/arm/cpu-domains.txt
new file mode 100644
index 0000000..ef5f215
--- /dev/null
+++ b/Documentation/arm/cpu-domains.txt
@@ -0,0 +1,52 @@
+CPU Clusters and PM domain
+
+Newer CPUs are grouped in a SoC as clusters. A cluster in addition to the
+CPUs may have caches, GIC, VFP and architecture specific power controller to
+power the cluster. A cluster may also be nested in another cluster, the
+hierarchy of which is depicted in the device tree. CPUIdle frameworks enables
+the CPUs to determine the sleep time and enter low power state to save power
+during periods of idle. CPUs in a cluster may enter and exit idle state
+independently. During the time when all the CPUs are in idle state, the
+cluster can safely be in idle state as well. When the last of the CPUs is
+powered off as a result of idle, the cluster may also be powered down, but the
+domain must be powered on before the first of the CPUs in the cluster resumes
+execution.
+
+SoCs can power down the CPU and resume execution in a few uSecs and the domain
+that powers the CPU cluster also have comparable idle latencies. The CPU WFI
+signal in ARM CPUs is used as a hardware trigger for the cluster hardware to
+enter their idle state. The hardware can be programmed in advance to put the
+cluster in the desired idle state befitting the wakeup latency requested by
+the CPUs. When all the CPUs in a cluster have executed their WFI instruction,
+the state machine for the power controller may put the cluster components in
+their power down or idle state. Generally, the domains would power on with the
+hardware sensing the CPU's interrupts. The domains may however, need to be
+reconfigured by the CPU to remain active, until the last CPU is ready to enter
+idle again. To power down a cluster, it is generally required to power down
+all the CPUs. The caches would also need to be flushed. The hardware state of
+some of the components may need to be saved and restored when powered back on.
+SoC vendors may also have hardware specific configuration that must be done
+before the cluster can be powered off. When the cluster is powered off,
+notifications may be sent out to other SoC components to scale down or even
+power off their resources.
+
+Power management domains represent relationship of devices and their power
+controllers. They are represented in the DT as domain consumers and providers.
+A device may have a domain provider and a domain provider may support multiple
+domain consumers. Domains like clusters, may also be nested inside one
+another. A domain that has no active consumer, may be powered off and any
+resuming consumer would trigger the domain back to active. Parent domains may
+be powered off when the child domains are powered off. The CPU cluster can be
+fashioned as a PM domain. When the CPU devices are powered off, the PM domain
+may be powered off.
+
+The code in Generic PM domains handles the hierarchy of devices, domains and
+the reference counting of objects leading to last man down and first man up.
+The CPU domains core code defines PM domains for each CPU cluster and attaches
+the domains' CPU devices to as specified in the DT. Platform drivers may use
+the following API to register their CPU PM domains.
+
+of_init_cpu_pm_domain() -
+Provides a single step registration of the CPU PM domain and attach CPUs to
+the genpd. Platform drivers may additionally register callbacks for power_on
+and power_off operations.
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 5998c53..59cb3ef 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP)	+= main.o wakeup.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
 obj-$(CONFIG_PM_OPP)	+= opp/
 obj-$(CONFIG_PM_GENERIC_DOMAINS)	+=  domain.o domain_governor.o
+obj-$(CONFIG_PM_GENERIC_DOMAINS_OF)	+= cpu-pd.o
 obj-$(CONFIG_HAVE_CLK)	+= clock_ops.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
new file mode 100644
index 0000000..9758b8d
--- /dev/null
+++ b/drivers/base/power/cpu-pd.c
@@ -0,0 +1,231 @@
+/*
+ * CPU Generic PM Domain.
+ *
+ * Copyright (C) 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpu-pd.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/rculist.h>
+#include <linux/slab.h>
+
+#define CPU_PD_NAME_MAX 36
+
+/* List of CPU PM domains we care about */
+static LIST_HEAD(of_cpu_pd_list);
+static DEFINE_SPINLOCK(cpu_pd_list_lock);
+
+static inline
+struct cpu_pm_domain *to_cpu_pd(struct generic_pm_domain *d)
+{
+	struct cpu_pm_domain *pd;
+	struct cpu_pm_domain *res = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(pd, &of_cpu_pd_list, link)
+		if (pd->genpd == d) {
+			res = pd;
+			break;
+		}
+	rcu_read_unlock();
+
+	return res;
+}
+
+static int cpu_pd_power_off(struct generic_pm_domain *genpd)
+{
+	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
+
+	if (pd->plat_ops.power_off)
+		pd->plat_ops.power_off(genpd);
+
+	/*
+	 * Notify CPU PM domain power down
+	 * TODO: Call the notificated directly from here.
+	 */
+	cpu_cluster_pm_enter();
+
+	return 0;
+}
+
+static int cpu_pd_power_on(struct generic_pm_domain *genpd)
+{
+	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
+
+	if (pd->plat_ops.power_on)
+		pd->plat_ops.power_on(genpd);
+
+	/* Notify CPU PM domain power up */
+	cpu_cluster_pm_exit();
+
+	return 0;
+}
+
+static void run_cpu(void *unused)
+{
+	struct device *cpu_dev = get_cpu_device(smp_processor_id());
+
+	/* We are running, increment the usage count */
+	pm_runtime_get_noresume(cpu_dev);
+}
+
+static int of_pm_domain_attach_cpus(struct device_node *dn)
+{
+	int cpuid, ret;
+
+	/* Find any CPU nodes with a phandle to this power domain */
+	for_each_possible_cpu(cpuid) {
+		struct device *cpu_dev;
+		struct device_node *cpu_pd;
+
+		cpu_dev = get_cpu_device(cpuid);
+		if (!cpu_dev) {
+			pr_warn("%s: Unable to get device for CPU%d\n",
+					__func__, cpuid);
+			return -ENODEV;
+		}
+
+		/* Only attach CPUs that are part of this domain */
+		cpu_pd = of_parse_phandle(cpu_dev->of_node, "power-domains", 0);
+		if (cpu_pd != dn)
+			continue;
+
+		if (cpu_online(cpuid)) {
+			pm_runtime_set_active(cpu_dev);
+			/*
+			 * Execute the below on that 'cpu' to ensure that the
+			 * reference counting is correct. It's possible that
+			 * while this code is executing, the 'cpu' may be
+			 * powered down, but we may incorrectly increment the
+			 * usage. By executing the get_cpu on the 'cpu',
+			 * we can ensure that the 'cpu' and its usage count are
+			 * matched.
+			 */
+			smp_call_function_single(cpuid, run_cpu, NULL, true);
+		} else {
+			pm_runtime_set_suspended(cpu_dev);
+		}
+
+		ret = genpd_dev_pm_attach(cpu_dev);
+		if (ret) {
+			dev_warn(cpu_dev,
+				"%s: Unable to attach to power-domain: %d\n",
+				__func__, ret);
+		} else {
+			pm_runtime_enable(cpu_dev);
+			dev_dbg(cpu_dev, "Attached CPU%d to domain\n", cpuid);
+		}
+	}
+
+	return 0;
+}
+
+int of_register_cpu_pm_domain(struct device_node *dn,
+		struct cpu_pm_domain *pd)
+{
+	int ret;
+
+	if (!pd || !pd->genpd)
+		return -EINVAL;
+
+	/*
+	 * The platform should not set up the genpd callbacks.
+	 * They should setup the pd->plat_ops instead.
+	 */
+	WARN_ON(pd->genpd->power_off);
+	WARN_ON(pd->genpd->power_on);
+
+	pd->genpd->power_off = cpu_pd_power_off;
+	pd->genpd->power_on = cpu_pd_power_on;
+	pd->genpd->flags |= GENPD_FLAG_IRQ_SAFE;
+
+	INIT_LIST_HEAD_RCU(&pd->link);
+	spin_lock(&cpu_pd_list_lock);
+	list_add_rcu(&pd->link, &of_cpu_pd_list);
+	spin_unlock(&cpu_pd_list_lock);
+	pd->dn = dn;
+
+	/* Register the CPU genpd */
+	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
+	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
+	if (ret) {
+		pr_err("Unable to initialize domain %s\n", dn->full_name);
+		return ret;
+	}
+
+	ret = of_genpd_add_provider_simple(dn, pd->genpd);
+	if (ret)
+		pr_warn("Unable to add genpd %s as provider\n",
+				pd->genpd->name);
+
+	/* Attach the CPUs to the CPU PM domain */
+	ret = of_pm_domain_attach_cpus(dn);
+	if (ret)
+		of_genpd_del_provider(dn);
+
+	return ret;
+}
+
+/**
+ * of_init_cpu_pm_domain() - Initialize a CPU PM domain using the CPU pd
+ * provided
+ * @dn: PM domain provider device node
+ * @ops: CPU PM domain platform specific ops for callback
+ *
+ * This is a single step initialize the CPU PM domain with defaults,
+ * also register the genpd and attach CPUs to the genpd.
+ */
+struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
+				const struct cpu_pd_ops *ops)
+{
+	struct cpu_pm_domain *pd;
+	int ret;
+
+	if (!of_device_is_available(dn))
+		return ERR_PTR(-ENODEV);
+
+	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return ERR_PTR(-ENOMEM);
+
+	pd->genpd = kzalloc(sizeof(*(pd->genpd)), GFP_KERNEL);
+	if (!pd->genpd) {
+		kfree(pd);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pd->genpd->name = kstrndup(dn->full_name, CPU_PD_NAME_MAX, GFP_KERNEL);
+	if (!pd->genpd->name) {
+		kfree(pd->genpd);
+		kfree(pd);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (ops) {
+		pd->plat_ops.power_off = ops->power_off;
+		pd->plat_ops.power_on = ops->power_on;
+	}
+
+	ret = of_register_cpu_pm_domain(dn, pd);
+	if (ret) {
+		kfree(pd->genpd->name);
+		kfree(pd->genpd);
+		kfree(pd);
+		return ERR_PTR(ret);
+	}
+
+	return pd->genpd;
+}
+EXPORT_SYMBOL(of_init_cpu_pm_domain);
diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
new file mode 100644
index 0000000..a2a217d
--- /dev/null
+++ b/include/linux/cpu-pd.h
@@ -0,0 +1,32 @@
+/*
+ * include/linux/cpu-pd.h
+ *
+ * Copyright (C) 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CPU_PD_H__
+#define __CPU_PD_H__
+
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/pm_domain.h>
+
+struct cpu_pd_ops {
+	int (*power_off)(struct generic_pm_domain *genpd);
+	int (*power_on)(struct generic_pm_domain *genpd);
+};
+
+struct cpu_pm_domain {
+	struct list_head link;
+	struct generic_pm_domain *genpd;
+	struct device_node *dn;
+	struct cpu_pd_ops plat_ops;
+};
+
+struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
+		const struct cpu_pd_ops *ops);
+#endif /* __CPU_PD_H__ */
-- 
2.1.4

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

* [PATCH RFC 10/27] drivers: power: Introduce PM domains for CPUs/clusters
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Define and add Generic PM domains (genpd) for CPU clusters. Many new
SoCs group CPUs as clusters. Clusters share common resources like power
rails, caches, VFP, Coresight etc. When all CPUs in the cluster are
idle, these shared resources may also be put in their idle state.

The idle time between the last CPU entering idle and a CPU resuming
execution is an opportunity for these shared resources to be powered
down. Generic PM domain provides a framework for defining such power
domains and attach devices to the domain. When the devices in the domain
are idle at runtime, the domain would also be suspended and resumed
before the first of the devices resume execution.

We define a generic PM domain for each cluster and attach CPU devices in
the cluster to that PM domain. The DT definitions for the SoC describe
this relationship. Genpd callbacks for power_on and power_off can then
be used to power up/down the shared resources for the domain.

Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Kevin Hilman <khilman@linaro.org>
Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/arm/cpu-domains.txt |  52 +++++++++
 drivers/base/power/Makefile       |   1 +
 drivers/base/power/cpu-pd.c       | 231 ++++++++++++++++++++++++++++++++++++++
 include/linux/cpu-pd.h            |  32 ++++++
 4 files changed, 316 insertions(+)
 create mode 100644 Documentation/arm/cpu-domains.txt
 create mode 100644 drivers/base/power/cpu-pd.c
 create mode 100644 include/linux/cpu-pd.h

diff --git a/Documentation/arm/cpu-domains.txt b/Documentation/arm/cpu-domains.txt
new file mode 100644
index 0000000..ef5f215
--- /dev/null
+++ b/Documentation/arm/cpu-domains.txt
@@ -0,0 +1,52 @@
+CPU Clusters and PM domain
+
+Newer CPUs are grouped in a SoC as clusters. A cluster in addition to the
+CPUs may have caches, GIC, VFP and architecture specific power controller to
+power the cluster. A cluster may also be nested in another cluster, the
+hierarchy of which is depicted in the device tree. CPUIdle frameworks enables
+the CPUs to determine the sleep time and enter low power state to save power
+during periods of idle. CPUs in a cluster may enter and exit idle state
+independently. During the time when all the CPUs are in idle state, the
+cluster can safely be in idle state as well. When the last of the CPUs is
+powered off as a result of idle, the cluster may also be powered down, but the
+domain must be powered on before the first of the CPUs in the cluster resumes
+execution.
+
+SoCs can power down the CPU and resume execution in a few uSecs and the domain
+that powers the CPU cluster also have comparable idle latencies. The CPU WFI
+signal in ARM CPUs is used as a hardware trigger for the cluster hardware to
+enter their idle state. The hardware can be programmed in advance to put the
+cluster in the desired idle state befitting the wakeup latency requested by
+the CPUs. When all the CPUs in a cluster have executed their WFI instruction,
+the state machine for the power controller may put the cluster components in
+their power down or idle state. Generally, the domains would power on with the
+hardware sensing the CPU's interrupts. The domains may however, need to be
+reconfigured by the CPU to remain active, until the last CPU is ready to enter
+idle again. To power down a cluster, it is generally required to power down
+all the CPUs. The caches would also need to be flushed. The hardware state of
+some of the components may need to be saved and restored when powered back on.
+SoC vendors may also have hardware specific configuration that must be done
+before the cluster can be powered off. When the cluster is powered off,
+notifications may be sent out to other SoC components to scale down or even
+power off their resources.
+
+Power management domains represent relationship of devices and their power
+controllers. They are represented in the DT as domain consumers and providers.
+A device may have a domain provider and a domain provider may support multiple
+domain consumers. Domains like clusters, may also be nested inside one
+another. A domain that has no active consumer, may be powered off and any
+resuming consumer would trigger the domain back to active. Parent domains may
+be powered off when the child domains are powered off. The CPU cluster can be
+fashioned as a PM domain. When the CPU devices are powered off, the PM domain
+may be powered off.
+
+The code in Generic PM domains handles the hierarchy of devices, domains and
+the reference counting of objects leading to last man down and first man up.
+The CPU domains core code defines PM domains for each CPU cluster and attaches
+the domains' CPU devices to as specified in the DT. Platform drivers may use
+the following API to register their CPU PM domains.
+
+of_init_cpu_pm_domain() -
+Provides a single step registration of the CPU PM domain and attach CPUs to
+the genpd. Platform drivers may additionally register callbacks for power_on
+and power_off operations.
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 5998c53..59cb3ef 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP)	+= main.o wakeup.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
 obj-$(CONFIG_PM_OPP)	+= opp/
 obj-$(CONFIG_PM_GENERIC_DOMAINS)	+=  domain.o domain_governor.o
+obj-$(CONFIG_PM_GENERIC_DOMAINS_OF)	+= cpu-pd.o
 obj-$(CONFIG_HAVE_CLK)	+= clock_ops.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
new file mode 100644
index 0000000..9758b8d
--- /dev/null
+++ b/drivers/base/power/cpu-pd.c
@@ -0,0 +1,231 @@
+/*
+ * CPU Generic PM Domain.
+ *
+ * Copyright (C) 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpu-pd.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/rculist.h>
+#include <linux/slab.h>
+
+#define CPU_PD_NAME_MAX 36
+
+/* List of CPU PM domains we care about */
+static LIST_HEAD(of_cpu_pd_list);
+static DEFINE_SPINLOCK(cpu_pd_list_lock);
+
+static inline
+struct cpu_pm_domain *to_cpu_pd(struct generic_pm_domain *d)
+{
+	struct cpu_pm_domain *pd;
+	struct cpu_pm_domain *res = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(pd, &of_cpu_pd_list, link)
+		if (pd->genpd == d) {
+			res = pd;
+			break;
+		}
+	rcu_read_unlock();
+
+	return res;
+}
+
+static int cpu_pd_power_off(struct generic_pm_domain *genpd)
+{
+	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
+
+	if (pd->plat_ops.power_off)
+		pd->plat_ops.power_off(genpd);
+
+	/*
+	 * Notify CPU PM domain power down
+	 * TODO: Call the notificated directly from here.
+	 */
+	cpu_cluster_pm_enter();
+
+	return 0;
+}
+
+static int cpu_pd_power_on(struct generic_pm_domain *genpd)
+{
+	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
+
+	if (pd->plat_ops.power_on)
+		pd->plat_ops.power_on(genpd);
+
+	/* Notify CPU PM domain power up */
+	cpu_cluster_pm_exit();
+
+	return 0;
+}
+
+static void run_cpu(void *unused)
+{
+	struct device *cpu_dev = get_cpu_device(smp_processor_id());
+
+	/* We are running, increment the usage count */
+	pm_runtime_get_noresume(cpu_dev);
+}
+
+static int of_pm_domain_attach_cpus(struct device_node *dn)
+{
+	int cpuid, ret;
+
+	/* Find any CPU nodes with a phandle to this power domain */
+	for_each_possible_cpu(cpuid) {
+		struct device *cpu_dev;
+		struct device_node *cpu_pd;
+
+		cpu_dev = get_cpu_device(cpuid);
+		if (!cpu_dev) {
+			pr_warn("%s: Unable to get device for CPU%d\n",
+					__func__, cpuid);
+			return -ENODEV;
+		}
+
+		/* Only attach CPUs that are part of this domain */
+		cpu_pd = of_parse_phandle(cpu_dev->of_node, "power-domains", 0);
+		if (cpu_pd != dn)
+			continue;
+
+		if (cpu_online(cpuid)) {
+			pm_runtime_set_active(cpu_dev);
+			/*
+			 * Execute the below on that 'cpu' to ensure that the
+			 * reference counting is correct. It's possible that
+			 * while this code is executing, the 'cpu' may be
+			 * powered down, but we may incorrectly increment the
+			 * usage. By executing the get_cpu on the 'cpu',
+			 * we can ensure that the 'cpu' and its usage count are
+			 * matched.
+			 */
+			smp_call_function_single(cpuid, run_cpu, NULL, true);
+		} else {
+			pm_runtime_set_suspended(cpu_dev);
+		}
+
+		ret = genpd_dev_pm_attach(cpu_dev);
+		if (ret) {
+			dev_warn(cpu_dev,
+				"%s: Unable to attach to power-domain: %d\n",
+				__func__, ret);
+		} else {
+			pm_runtime_enable(cpu_dev);
+			dev_dbg(cpu_dev, "Attached CPU%d to domain\n", cpuid);
+		}
+	}
+
+	return 0;
+}
+
+int of_register_cpu_pm_domain(struct device_node *dn,
+		struct cpu_pm_domain *pd)
+{
+	int ret;
+
+	if (!pd || !pd->genpd)
+		return -EINVAL;
+
+	/*
+	 * The platform should not set up the genpd callbacks.
+	 * They should setup the pd->plat_ops instead.
+	 */
+	WARN_ON(pd->genpd->power_off);
+	WARN_ON(pd->genpd->power_on);
+
+	pd->genpd->power_off = cpu_pd_power_off;
+	pd->genpd->power_on = cpu_pd_power_on;
+	pd->genpd->flags |= GENPD_FLAG_IRQ_SAFE;
+
+	INIT_LIST_HEAD_RCU(&pd->link);
+	spin_lock(&cpu_pd_list_lock);
+	list_add_rcu(&pd->link, &of_cpu_pd_list);
+	spin_unlock(&cpu_pd_list_lock);
+	pd->dn = dn;
+
+	/* Register the CPU genpd */
+	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
+	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
+	if (ret) {
+		pr_err("Unable to initialize domain %s\n", dn->full_name);
+		return ret;
+	}
+
+	ret = of_genpd_add_provider_simple(dn, pd->genpd);
+	if (ret)
+		pr_warn("Unable to add genpd %s as provider\n",
+				pd->genpd->name);
+
+	/* Attach the CPUs to the CPU PM domain */
+	ret = of_pm_domain_attach_cpus(dn);
+	if (ret)
+		of_genpd_del_provider(dn);
+
+	return ret;
+}
+
+/**
+ * of_init_cpu_pm_domain() - Initialize a CPU PM domain using the CPU pd
+ * provided
+ * @dn: PM domain provider device node
+ * @ops: CPU PM domain platform specific ops for callback
+ *
+ * This is a single step initialize the CPU PM domain with defaults,
+ * also register the genpd and attach CPUs to the genpd.
+ */
+struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
+				const struct cpu_pd_ops *ops)
+{
+	struct cpu_pm_domain *pd;
+	int ret;
+
+	if (!of_device_is_available(dn))
+		return ERR_PTR(-ENODEV);
+
+	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return ERR_PTR(-ENOMEM);
+
+	pd->genpd = kzalloc(sizeof(*(pd->genpd)), GFP_KERNEL);
+	if (!pd->genpd) {
+		kfree(pd);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pd->genpd->name = kstrndup(dn->full_name, CPU_PD_NAME_MAX, GFP_KERNEL);
+	if (!pd->genpd->name) {
+		kfree(pd->genpd);
+		kfree(pd);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (ops) {
+		pd->plat_ops.power_off = ops->power_off;
+		pd->plat_ops.power_on = ops->power_on;
+	}
+
+	ret = of_register_cpu_pm_domain(dn, pd);
+	if (ret) {
+		kfree(pd->genpd->name);
+		kfree(pd->genpd);
+		kfree(pd);
+		return ERR_PTR(ret);
+	}
+
+	return pd->genpd;
+}
+EXPORT_SYMBOL(of_init_cpu_pm_domain);
diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
new file mode 100644
index 0000000..a2a217d
--- /dev/null
+++ b/include/linux/cpu-pd.h
@@ -0,0 +1,32 @@
+/*
+ * include/linux/cpu-pd.h
+ *
+ * Copyright (C) 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CPU_PD_H__
+#define __CPU_PD_H__
+
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/pm_domain.h>
+
+struct cpu_pd_ops {
+	int (*power_off)(struct generic_pm_domain *genpd);
+	int (*power_on)(struct generic_pm_domain *genpd);
+};
+
+struct cpu_pm_domain {
+	struct list_head link;
+	struct generic_pm_domain *genpd;
+	struct device_node *dn;
+	struct cpu_pd_ops plat_ops;
+};
+
+struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
+		const struct cpu_pd_ops *ops);
+#endif /* __CPU_PD_H__ */
-- 
2.1.4

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

* [PATCH RFC 11/27] drivers: cpu: Define CPU devices as IRQ safe
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

CPUs may be powered off from CPUIdle or hotplug and are called with
IRQ's disabled. Define CPU devices as IRQ safe, so they may be runtime
suspended/resumed.

Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/cpu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 91bbb19..6633210 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/cpufeature.h>
 #include <linux/tick.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 
@@ -371,10 +372,11 @@ int register_cpu(struct cpu *cpu, int num)
 	if (cpu->hotpluggable)
 		cpu->dev.groups = hotplugable_cpu_attr_groups;
 	error = device_register(&cpu->dev);
-	if (!error)
+	if (!error) {
+		pm_runtime_irq_safe(&cpu->dev);
 		per_cpu(cpu_sys_devices, num) = &cpu->dev;
-	if (!error)
 		register_cpu_under_node(num, cpu_to_node(num));
+	}
 
 	return error;
 }
-- 
2.1.4

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

* [PATCH RFC 11/27] drivers: cpu: Define CPU devices as IRQ safe
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

CPUs may be powered off from CPUIdle or hotplug and are called with
IRQ's disabled. Define CPU devices as IRQ safe, so they may be runtime
suspended/resumed.

Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/cpu.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 91bbb19..6633210 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/cpufeature.h>
 #include <linux/tick.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 
@@ -371,10 +372,11 @@ int register_cpu(struct cpu *cpu, int num)
 	if (cpu->hotpluggable)
 		cpu->dev.groups = hotplugable_cpu_attr_groups;
 	error = device_register(&cpu->dev);
-	if (!error)
+	if (!error) {
+		pm_runtime_irq_safe(&cpu->dev);
 		per_cpu(cpu_sys_devices, num) = &cpu->dev;
-	if (!error)
 		register_cpu_under_node(num, cpu_to_node(num));
+	}
 
 	return error;
 }
-- 
2.1.4

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

* [PATCH RFC 12/27] ARM: cpuidle: remove cpu parameter from the cpuidle_ops suspend hook
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Russell King,
	Daniel Lezcano

From: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

The suspend() hook in the cpuidle_ops struct is always called on
the cpu entering idle, which means that the cpu parameter passed
to the suspend hook always corresponds to the local cpu, making
it somewhat redundant.

This patch removes the logical cpu parameter from the ARM
cpuidle_ops.suspend hook and updates all the existing kernel
implementations to reflect this change.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Lina Iyer <lina.iyer@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 arch/arm/include/asm/cpuidle.h |  2 +-
 arch/arm/kernel/cpuidle.c      |  2 +-
 drivers/soc/qcom/spm.c         | 10 +++++-----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
index 0f84249..3848259 100644
--- a/arch/arm/include/asm/cpuidle.h
+++ b/arch/arm/include/asm/cpuidle.h
@@ -30,7 +30,7 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
 struct device_node;
 
 struct cpuidle_ops {
-	int (*suspend)(int cpu, unsigned long arg);
+	int (*suspend)(unsigned long arg);
 	int (*init)(struct device_node *, int cpu);
 };
 
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
index 318da33..703926e 100644
--- a/arch/arm/kernel/cpuidle.c
+++ b/arch/arm/kernel/cpuidle.c
@@ -56,7 +56,7 @@ int arm_cpuidle_suspend(int index)
 	int cpu = smp_processor_id();
 
 	if (cpuidle_ops[cpu].suspend)
-		ret = cpuidle_ops[cpu].suspend(cpu, index);
+		ret = cpuidle_ops[cpu].suspend(index);
 
 	return ret;
 }
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index b04b05a..0ad66fa 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -116,7 +116,7 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
 
 static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);
 
-typedef int (*idle_fn)(int);
+typedef int (*idle_fn)(void);
 static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);
 
 static inline void spm_register_write(struct spm_driver_data *drv,
@@ -179,10 +179,10 @@ static int qcom_pm_collapse(unsigned long int unused)
 	return -1;
 }
 
-static int qcom_cpu_spc(int cpu)
+static int qcom_cpu_spc(void)
 {
 	int ret;
-	struct spm_driver_data *drv = per_cpu(cpu_spm_drv, cpu);
+	struct spm_driver_data *drv = __this_cpu_read(cpu_spm_drv);
 
 	spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
 	ret = cpu_suspend(0, qcom_pm_collapse);
@@ -197,9 +197,9 @@ static int qcom_cpu_spc(int cpu)
 	return ret;
 }
 
-static int qcom_idle_enter(int cpu, unsigned long index)
+static int qcom_idle_enter(unsigned long index)
 {
-	return per_cpu(qcom_idle_ops, cpu)[index](cpu);
+	return __this_cpu_read(qcom_idle_ops)[index]();
 }
 
 static const struct of_device_id qcom_idle_state_match[] __initconst = {
-- 
2.1.4


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

* [PATCH RFC 12/27] ARM: cpuidle: remove cpu parameter from the cpuidle_ops suspend hook
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

The suspend() hook in the cpuidle_ops struct is always called on
the cpu entering idle, which means that the cpu parameter passed
to the suspend hook always corresponds to the local cpu, making
it somewhat redundant.

This patch removes the logical cpu parameter from the ARM
cpuidle_ops.suspend hook and updates all the existing kernel
implementations to reflect this change.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Lina Iyer <lina.iyer@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 arch/arm/include/asm/cpuidle.h |  2 +-
 arch/arm/kernel/cpuidle.c      |  2 +-
 drivers/soc/qcom/spm.c         | 10 +++++-----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
index 0f84249..3848259 100644
--- a/arch/arm/include/asm/cpuidle.h
+++ b/arch/arm/include/asm/cpuidle.h
@@ -30,7 +30,7 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
 struct device_node;
 
 struct cpuidle_ops {
-	int (*suspend)(int cpu, unsigned long arg);
+	int (*suspend)(unsigned long arg);
 	int (*init)(struct device_node *, int cpu);
 };
 
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
index 318da33..703926e 100644
--- a/arch/arm/kernel/cpuidle.c
+++ b/arch/arm/kernel/cpuidle.c
@@ -56,7 +56,7 @@ int arm_cpuidle_suspend(int index)
 	int cpu = smp_processor_id();
 
 	if (cpuidle_ops[cpu].suspend)
-		ret = cpuidle_ops[cpu].suspend(cpu, index);
+		ret = cpuidle_ops[cpu].suspend(index);
 
 	return ret;
 }
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index b04b05a..0ad66fa 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -116,7 +116,7 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
 
 static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);
 
-typedef int (*idle_fn)(int);
+typedef int (*idle_fn)(void);
 static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);
 
 static inline void spm_register_write(struct spm_driver_data *drv,
@@ -179,10 +179,10 @@ static int qcom_pm_collapse(unsigned long int unused)
 	return -1;
 }
 
-static int qcom_cpu_spc(int cpu)
+static int qcom_cpu_spc(void)
 {
 	int ret;
-	struct spm_driver_data *drv = per_cpu(cpu_spm_drv, cpu);
+	struct spm_driver_data *drv = __this_cpu_read(cpu_spm_drv);
 
 	spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
 	ret = cpu_suspend(0, qcom_pm_collapse);
@@ -197,9 +197,9 @@ static int qcom_cpu_spc(int cpu)
 	return ret;
 }
 
-static int qcom_idle_enter(int cpu, unsigned long index)
+static int qcom_idle_enter(unsigned long index)
 {
-	return per_cpu(qcom_idle_ops, cpu)[index](cpu);
+	return __this_cpu_read(qcom_idle_ops)[index]();
 }
 
 static const struct of_device_id qcom_idle_state_match[] __initconst = {
-- 
2.1.4

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

* [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Daniel Lezcano

Notify runtime PM when the CPU is going to be powered off in the idle
state. This allows for runtime PM suspend/resume of the CPU as well as
its PM domain.

Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 545069d..8e72a23 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -11,13 +11,16 @@
 
 #define pr_fmt(fmt) "CPUidle arm: " fmt
 
+#include <linux/cpu.h>
 #include <linux/cpuidle.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_pm.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 
 #include <asm/cpuidle.h>
 
@@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 
 	ret = cpu_pm_enter();
 	if (!ret) {
+		struct device *cpu_dev = get_cpu_device(dev->cpu);
+
+		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
+
 		/*
 		 * Pass idle state index to cpu_suspend which in turn will
 		 * call the CPU ops suspend protocol with idle index as a
@@ -52,6 +59,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 		 */
 		arm_cpuidle_suspend(idx);
 
+		RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
 		cpu_pm_exit();
 	}
 
-- 
2.1.4

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

* [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Notify runtime PM when the CPU is going to be powered off in the idle
state. This allows for runtime PM suspend/resume of the CPU as well as
its PM domain.

Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 545069d..8e72a23 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -11,13 +11,16 @@
 
 #define pr_fmt(fmt) "CPUidle arm: " fmt
 
+#include <linux/cpu.h>
 #include <linux/cpuidle.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_pm.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 
 #include <asm/cpuidle.h>
 
@@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 
 	ret = cpu_pm_enter();
 	if (!ret) {
+		struct device *cpu_dev = get_cpu_device(dev->cpu);
+
+		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
+
 		/*
 		 * Pass idle state index to cpu_suspend which in turn will
 		 * call the CPU ops suspend protocol with idle index as a
@@ -52,6 +59,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 		 */
 		arm_cpuidle_suspend(idx);
 
+		RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
 		cpu_pm_exit();
 	}
 
-- 
2.1.4

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

* [PATCH RFC 14/27] tick: get next wakeup event for the CPU
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer,
	Thomas Gleixner

CPUidle governors use the sleep time of the CPU to determine the idle
state of the CPU. However, to determine a common sleep time between CPUs
that enter idle at different times, the tick_nohz_get_sleep_length() API
is not very helpful.

Add API to read the next event for the CPU. The value can be evaluated
at any time to determine the remaining sleep time of the CPU.

Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 include/linux/tick.h     | 10 ++++++++++
 kernel/time/tick-sched.c |  8 ++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/linux/tick.h b/include/linux/tick.h
index e312219..6db3e52 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -103,6 +103,7 @@ extern void tick_nohz_idle_enter(void);
 extern void tick_nohz_idle_exit(void);
 extern void tick_nohz_irq_exit(void);
 extern ktime_t tick_nohz_get_sleep_length(void);
+extern ktime_t tick_nohz_get_next_wakeup(void);
 extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
 extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time);
 #else /* !CONFIG_NO_HZ_COMMON */
@@ -116,6 +117,15 @@ static inline ktime_t tick_nohz_get_sleep_length(void)
 
 	return len;
 }
+
+static inline ktime_t tick_nohz_get_next_wakeup(void)
+{
+	ktime_t len = { .tv64 = NSEC_PER_SEC/HZ };
+
+	/* Next wake up is the tick period, assume it starts now */
+	return ktime_add(len, ktime_get());
+}
+
 static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
 static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; }
 #endif /* !CONFIG_NO_HZ_COMMON */
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7c7ec45..e130edd 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -870,6 +870,14 @@ ktime_t tick_nohz_get_sleep_length(void)
 	return ts->sleep_length;
 }
 
+ktime_t tick_nohz_get_next_wakeup(void)
+{
+	struct clock_event_device *dev =
+			__this_cpu_read(tick_cpu_device.evtdev);
+
+	return dev->next_event;
+}
+
 static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
 {
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-- 
2.1.4


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

* [PATCH RFC 14/27] tick: get next wakeup event for the CPU
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

CPUidle governors use the sleep time of the CPU to determine the idle
state of the CPU. However, to determine a common sleep time between CPUs
that enter idle at different times, the tick_nohz_get_sleep_length() API
is not very helpful.

Add API to read the next event for the CPU. The value can be evaluated
at any time to determine the remaining sleep time of the CPU.

Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 include/linux/tick.h     | 10 ++++++++++
 kernel/time/tick-sched.c |  8 ++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/linux/tick.h b/include/linux/tick.h
index e312219..6db3e52 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -103,6 +103,7 @@ extern void tick_nohz_idle_enter(void);
 extern void tick_nohz_idle_exit(void);
 extern void tick_nohz_irq_exit(void);
 extern ktime_t tick_nohz_get_sleep_length(void);
+extern ktime_t tick_nohz_get_next_wakeup(void);
 extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
 extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time);
 #else /* !CONFIG_NO_HZ_COMMON */
@@ -116,6 +117,15 @@ static inline ktime_t tick_nohz_get_sleep_length(void)
 
 	return len;
 }
+
+static inline ktime_t tick_nohz_get_next_wakeup(void)
+{
+	ktime_t len = { .tv64 = NSEC_PER_SEC/HZ };
+
+	/* Next wake up is the tick period, assume it starts now */
+	return ktime_add(len, ktime_get());
+}
+
 static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; }
 static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; }
 #endif /* !CONFIG_NO_HZ_COMMON */
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7c7ec45..e130edd 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -870,6 +870,14 @@ ktime_t tick_nohz_get_sleep_length(void)
 	return ts->sleep_length;
 }
 
+ktime_t tick_nohz_get_next_wakeup(void)
+{
+	struct clock_event_device *dev =
+			__this_cpu_read(tick_cpu_device.evtdev);
+
+	return dev->next_event;
+}
+
 static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
 {
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-- 
2.1.4

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

* [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Allow devices that know when their next wakeup event is, to record save
it as part of timing data. A genpd governor may use this data to
determine if suspending the domain is going to affect the QoS of its
devices.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 include/linux/pm_domain.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index f1329ea..9ac089d 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/notifier.h>
 #include <linux/spinlock.h>
+#include <linux/ktime.h>
 
 /* Defines used for the flags field in the struct generic_pm_domain */
 #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
@@ -104,6 +105,7 @@ struct gpd_timing_data {
 	s64 effective_constraint_ns;
 	bool constraint_changed;
 	bool cached_stop_ok;
+	ktime_t next_wakeup;
 };
 
 struct pm_domain_data {
-- 
2.1.4

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

* [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Allow devices that know when their next wakeup event is, to record save
it as part of timing data. A genpd governor may use this data to
determine if suspending the domain is going to affect the QoS of its
devices.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 include/linux/pm_domain.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index f1329ea..9ac089d 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/notifier.h>
 #include <linux/spinlock.h>
+#include <linux/ktime.h>
 
 /* Defines used for the flags field in the struct generic_pm_domain */
 #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
@@ -104,6 +105,7 @@ struct gpd_timing_data {
 	s64 effective_constraint_ns;
 	bool constraint_changed;
 	bool cached_stop_ok;
+	ktime_t next_wakeup;
 };
 
 struct pm_domain_data {
-- 
2.1.4

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

* [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Reading the next wakeup of the CPU can only be realiably done only from
that CPU. In the idle enter path record the next wake up of the CPU. The
information is useful to determine the sleep time left for the CPU.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/cpuidle/cpuidle-arm.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 8e72a23..b3133ef 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -18,9 +18,11 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
+#include <linux/tick.h>
 
 #include <asm/cpuidle.h>
 
@@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 	ret = cpu_pm_enter();
 	if (!ret) {
 		struct device *cpu_dev = get_cpu_device(dev->cpu);
+		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
 
+		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
 		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
 
 		/*
@@ -60,6 +64,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 		arm_cpuidle_suspend(idx);
 
 		RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
+		gpd->td.next_wakeup.tv64 = 0;
 		cpu_pm_exit();
 	}
 
-- 
2.1.4


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

* [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Reading the next wakeup of the CPU can only be realiably done only from
that CPU. In the idle enter path record the next wake up of the CPU. The
information is useful to determine the sleep time left for the CPU.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/cpuidle/cpuidle-arm.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 8e72a23..b3133ef 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -18,9 +18,11 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
+#include <linux/tick.h>
 
 #include <asm/cpuidle.h>
 
@@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 	ret = cpu_pm_enter();
 	if (!ret) {
 		struct device *cpu_dev = get_cpu_device(dev->cpu);
+		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
 
+		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
 		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
 
 		/*
@@ -60,6 +64,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
 		arm_cpuidle_suspend(idx);
 
 		RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
+		gpd->td.next_wakeup.tv64 = 0;
 		cpu_pm_exit();
 	}
 
-- 
2.1.4

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

* [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

In order to power down the heirarchy of the CPU domain, the domain needs
information about the CPUs in that domain hierarchy . A domain that has
sub-domains containing CPU devices, will need information about all the
CPUs in the sub-domains as well.

Introduce of_attach_cpu_pm_domain() to allow CPU domains to be attached
to its parent domain and the information on CPUs attached directly or
indirectly be bubbled up the hierarchy.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/cpu-pd.h      |  3 ++
 2 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index 9758b8d..617ce54 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -18,6 +18,7 @@
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/pm_qos.h>
 #include <linux/rculist.h>
 #include <linux/slab.h>
 
@@ -44,6 +45,27 @@ struct cpu_pm_domain *to_cpu_pd(struct generic_pm_domain *d)
 	return res;
 }
 
+/**
+ * get_cpus_in_domain() - Recursively parse CPUs in a domain.
+ */
+static void get_cpus_in_domain(struct generic_pm_domain *genpd,
+		struct cpumask *mask)
+{
+	struct gpd_link *link;
+	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
+	struct generic_pm_domain *sd;
+
+	if (!cpumask_empty(pd->cpus) && mask != pd->cpus) {
+		cpumask_or(mask, pd->cpus, mask);
+		return;
+	}
+
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		sd = link->slave;
+		get_cpus_in_domain(sd, mask);
+	}
+}
+
 static int cpu_pd_power_off(struct generic_pm_domain *genpd)
 {
 	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
@@ -81,7 +103,8 @@ static void run_cpu(void *unused)
 	pm_runtime_get_noresume(cpu_dev);
 }
 
-static int of_pm_domain_attach_cpus(struct device_node *dn)
+static int of_pm_domain_attach_cpus(struct device_node *dn,
+		struct cpu_pm_domain *pd)
 {
 	int cpuid, ret;
 
@@ -126,6 +149,7 @@ static int of_pm_domain_attach_cpus(struct device_node *dn)
 		} else {
 			pm_runtime_enable(cpu_dev);
 			dev_dbg(cpu_dev, "Attached CPU%d to domain\n", cpuid);
+			cpumask_set_cpu(cpuid, pd->cpus);
 		}
 	}
 
@@ -171,7 +195,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
 				pd->genpd->name);
 
 	/* Attach the CPUs to the CPU PM domain */
-	ret = of_pm_domain_attach_cpus(dn);
+	ret = of_pm_domain_attach_cpus(dn, pd);
 	if (ret)
 		of_genpd_del_provider(dn);
 
@@ -213,6 +237,13 @@ struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 		return ERR_PTR(-ENOMEM);
 	}
 
+	if (!zalloc_cpumask_var(&pd->cpus, GFP_KERNEL)) {
+		kfree(pd->genpd->name);
+		kfree(pd->genpd);
+		kfree(pd);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	if (ops) {
 		pd->plat_ops.power_off = ops->power_off;
 		pd->plat_ops.power_on = ops->power_on;
@@ -222,6 +253,7 @@ struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 	if (ret) {
 		kfree(pd->genpd->name);
 		kfree(pd->genpd);
+		kfree(pd->cpus);
 		kfree(pd);
 		return ERR_PTR(ret);
 	}
@@ -229,3 +261,63 @@ struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 	return pd->genpd;
 }
 EXPORT_SYMBOL(of_init_cpu_pm_domain);
+
+/**
+ * of_attach_cpu_pm_domain() - Attach a CPU PM domain to its parent
+ * @dn: The device node of the CPU PM domain that needs to be attached
+ *
+ * The platform code can use this simplfied function to parse the domain
+ * provider of this device node and attach the genpd associated with @dn
+ * to it parents.
+ *
+ * Note: Both @dn and its domain provider must be initialized using
+ * of_init_cpu_pm_domain.
+ */
+int of_attach_cpu_pm_domain(struct device_node *dn)
+{
+	struct of_phandle_args args;
+	struct generic_pm_domain *genpd, *parent;
+	struct cpu_pm_domain *pd;
+	int ret;
+
+	args.np = dn;
+	args.args_count = 0;
+
+	genpd = of_genpd_get_from_provider(&args);
+	if (IS_ERR(genpd))
+		return -EINVAL;
+
+	if (!to_cpu_pd(genpd)) {
+		pr_warn("%s: domain %s is not a CPU domain\n",
+				__func__, genpd->name);
+		return -EINVAL;
+	}
+
+	ret = of_parse_phandle_with_args(dn, "power-domains",
+			"#power-domain-cells", 0, &args);
+	if (ret < 0)
+		return ret;
+
+	parent = of_genpd_get_from_provider(&args);
+	if (IS_ERR(parent))
+		return -EINVAL;
+
+	pd = to_cpu_pd(parent);
+	if (!pd) {
+		pr_warn("%s: domain (%s) parent (%s) is non-CPU domain\n",
+				__func__, genpd->name, parent->name);
+		return -EINVAL;
+	}
+
+	ret = pm_genpd_add_subdomain(genpd, parent);
+	if (ret) {
+		pr_err("%s: Unable to add sub-domain (%s) to parent (%s)\n",
+				__func__, genpd->name, parent->name);
+		return ret;
+	}
+
+	get_cpus_in_domain(parent, pd->cpus);
+
+	return 0;
+}
+EXPORT_SYMBOL(of_attach_cpu_pm_domain);
diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
index a2a217d..489ee2f 100644
--- a/include/linux/cpu-pd.h
+++ b/include/linux/cpu-pd.h
@@ -11,6 +11,7 @@
 #ifndef __CPU_PD_H__
 #define __CPU_PD_H__
 
+#include <linux/cpumask.h>
 #include <linux/list.h>
 #include <linux/of.h>
 #include <linux/pm_domain.h>
@@ -25,8 +26,10 @@ struct cpu_pm_domain {
 	struct generic_pm_domain *genpd;
 	struct device_node *dn;
 	struct cpu_pd_ops plat_ops;
+	cpumask_var_t cpus;
 };
 
 struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 		const struct cpu_pd_ops *ops);
+int of_attach_cpu_pm_domain(struct device_node *dn);
 #endif /* __CPU_PD_H__ */
-- 
2.1.4

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

* [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

In order to power down the heirarchy of the CPU domain, the domain needs
information about the CPUs in that domain hierarchy . A domain that has
sub-domains containing CPU devices, will need information about all the
CPUs in the sub-domains as well.

Introduce of_attach_cpu_pm_domain() to allow CPU domains to be attached
to its parent domain and the information on CPUs attached directly or
indirectly be bubbled up the hierarchy.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/cpu-pd.h      |  3 ++
 2 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index 9758b8d..617ce54 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -18,6 +18,7 @@
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <linux/pm_qos.h>
 #include <linux/rculist.h>
 #include <linux/slab.h>
 
@@ -44,6 +45,27 @@ struct cpu_pm_domain *to_cpu_pd(struct generic_pm_domain *d)
 	return res;
 }
 
+/**
+ * get_cpus_in_domain() - Recursively parse CPUs in a domain.
+ */
+static void get_cpus_in_domain(struct generic_pm_domain *genpd,
+		struct cpumask *mask)
+{
+	struct gpd_link *link;
+	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
+	struct generic_pm_domain *sd;
+
+	if (!cpumask_empty(pd->cpus) && mask != pd->cpus) {
+		cpumask_or(mask, pd->cpus, mask);
+		return;
+	}
+
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		sd = link->slave;
+		get_cpus_in_domain(sd, mask);
+	}
+}
+
 static int cpu_pd_power_off(struct generic_pm_domain *genpd)
 {
 	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
@@ -81,7 +103,8 @@ static void run_cpu(void *unused)
 	pm_runtime_get_noresume(cpu_dev);
 }
 
-static int of_pm_domain_attach_cpus(struct device_node *dn)
+static int of_pm_domain_attach_cpus(struct device_node *dn,
+		struct cpu_pm_domain *pd)
 {
 	int cpuid, ret;
 
@@ -126,6 +149,7 @@ static int of_pm_domain_attach_cpus(struct device_node *dn)
 		} else {
 			pm_runtime_enable(cpu_dev);
 			dev_dbg(cpu_dev, "Attached CPU%d to domain\n", cpuid);
+			cpumask_set_cpu(cpuid, pd->cpus);
 		}
 	}
 
@@ -171,7 +195,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
 				pd->genpd->name);
 
 	/* Attach the CPUs to the CPU PM domain */
-	ret = of_pm_domain_attach_cpus(dn);
+	ret = of_pm_domain_attach_cpus(dn, pd);
 	if (ret)
 		of_genpd_del_provider(dn);
 
@@ -213,6 +237,13 @@ struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 		return ERR_PTR(-ENOMEM);
 	}
 
+	if (!zalloc_cpumask_var(&pd->cpus, GFP_KERNEL)) {
+		kfree(pd->genpd->name);
+		kfree(pd->genpd);
+		kfree(pd);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	if (ops) {
 		pd->plat_ops.power_off = ops->power_off;
 		pd->plat_ops.power_on = ops->power_on;
@@ -222,6 +253,7 @@ struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 	if (ret) {
 		kfree(pd->genpd->name);
 		kfree(pd->genpd);
+		kfree(pd->cpus);
 		kfree(pd);
 		return ERR_PTR(ret);
 	}
@@ -229,3 +261,63 @@ struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 	return pd->genpd;
 }
 EXPORT_SYMBOL(of_init_cpu_pm_domain);
+
+/**
+ * of_attach_cpu_pm_domain() - Attach a CPU PM domain to its parent
+ * @dn: The device node of the CPU PM domain that needs to be attached
+ *
+ * The platform code can use this simplfied function to parse the domain
+ * provider of this device node and attach the genpd associated with @dn
+ * to it parents.
+ *
+ * Note: Both @dn and its domain provider must be initialized using
+ * of_init_cpu_pm_domain.
+ */
+int of_attach_cpu_pm_domain(struct device_node *dn)
+{
+	struct of_phandle_args args;
+	struct generic_pm_domain *genpd, *parent;
+	struct cpu_pm_domain *pd;
+	int ret;
+
+	args.np = dn;
+	args.args_count = 0;
+
+	genpd = of_genpd_get_from_provider(&args);
+	if (IS_ERR(genpd))
+		return -EINVAL;
+
+	if (!to_cpu_pd(genpd)) {
+		pr_warn("%s: domain %s is not a CPU domain\n",
+				__func__, genpd->name);
+		return -EINVAL;
+	}
+
+	ret = of_parse_phandle_with_args(dn, "power-domains",
+			"#power-domain-cells", 0, &args);
+	if (ret < 0)
+		return ret;
+
+	parent = of_genpd_get_from_provider(&args);
+	if (IS_ERR(parent))
+		return -EINVAL;
+
+	pd = to_cpu_pd(parent);
+	if (!pd) {
+		pr_warn("%s: domain (%s) parent (%s) is non-CPU domain\n",
+				__func__, genpd->name, parent->name);
+		return -EINVAL;
+	}
+
+	ret = pm_genpd_add_subdomain(genpd, parent);
+	if (ret) {
+		pr_err("%s: Unable to add sub-domain (%s) to parent (%s)\n",
+				__func__, genpd->name, parent->name);
+		return ret;
+	}
+
+	get_cpus_in_domain(parent, pd->cpus);
+
+	return 0;
+}
+EXPORT_SYMBOL(of_attach_cpu_pm_domain);
diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
index a2a217d..489ee2f 100644
--- a/include/linux/cpu-pd.h
+++ b/include/linux/cpu-pd.h
@@ -11,6 +11,7 @@
 #ifndef __CPU_PD_H__
 #define __CPU_PD_H__
 
+#include <linux/cpumask.h>
 #include <linux/list.h>
 #include <linux/of.h>
 #include <linux/pm_domain.h>
@@ -25,8 +26,10 @@ struct cpu_pm_domain {
 	struct generic_pm_domain *genpd;
 	struct device_node *dn;
 	struct cpu_pd_ops plat_ops;
+	cpumask_var_t cpus;
 };
 
 struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 		const struct cpu_pd_ops *ops);
+int of_attach_cpu_pm_domain(struct device_node *dn);
 #endif /* __CPU_PD_H__ */
-- 
2.1.4

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

A PM domain comprising of CPUs may be powered off when all the CPUs in
the domain are powered down. Powering down a CPU domain is generally a
expensive operation and therefore the power performance trade offs
should be considered. The time between the last CPU powering down and
the first CPU powering up in a domain, is the time available for the
domain to sleep. Ideally, the sleep time of the domain should fulfill
the residency requirement of the domains' idle state.

To do this effectively, read the time before the wakeup of the cluster's
CPUs and ensure that the domain's idle state sleep time guarantees the
QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
state's residency.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index 617ce54..a00abc1 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -21,6 +21,7 @@
 #include <linux/pm_qos.h>
 #include <linux/rculist.h>
 #include <linux/slab.h>
+#include <linux/tick.h>
 
 #define CPU_PD_NAME_MAX 36
 
@@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
 	}
 }
 
+static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
+{
+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
+	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
+	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+	u64 sleep_ns = ~0;
+	ktime_t earliest;
+	int cpu;
+	int i;
+
+	/* Reset the last set genpd state, default to index 0 */
+	genpd->state_idx = 0;
+
+	/* We dont want to power down, if QoS is 0 */
+	if (!qos)
+		return false;
+
+	/*
+	 * Find the sleep time for the cluster.
+	 * The time between now and the first wake up of any CPU that
+	 * are in this domain hierarchy is the time available for the
+	 * domain to be idle.
+	 */
+	earliest.tv64 = KTIME_MAX;
+	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
+		struct device *cpu_dev = get_cpu_device(cpu);
+		struct gpd_timing_data *td;
+
+		td = &dev_gpd_data(cpu_dev)->td;
+
+		if (earliest.tv64 < td->next_wakeup.tv64)
+			earliest = td->next_wakeup;
+	}
+
+	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
+	if (sleep_ns <= 0)
+		return false;
+
+	/*
+	 * Find the deepest sleep state that satisfies the residency
+	 * requirement and the QoS constraint
+	 */
+	for (i = genpd->state_count - 1; i > 0; i--) {
+		u64 state_sleep_ns;
+
+		state_sleep_ns = genpd->states[i].power_off_latency_ns +
+			genpd->states[i].power_on_latency_ns +
+			genpd->states[i].residency_ns;
+
+		/*
+		 * If we cant sleep to save power in the state, move on
+		 * to the next lower idle state.
+		 */
+		if (state_sleep_ns > sleep_ns)
+		       continue;
+
+		/*
+		 * We also dont want to sleep more than we should to
+		 * gaurantee QoS.
+		 */
+		if (state_sleep_ns < (qos * NSEC_PER_USEC))
+			break;
+	}
+
+	if (i >= 0)
+		genpd->state_idx = i;
+
+	return  (i >= 0) ? true : false;
+}
+
+static bool cpu_stop_ok(struct device *dev)
+{
+	return true;
+}
+
+struct dev_power_governor cpu_pd_gov = {
+	.power_down_ok = cpu_pd_down_ok,
+	.stop_ok = cpu_stop_ok,
+};
+
 static int cpu_pd_power_off(struct generic_pm_domain *genpd)
 {
 	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
@@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
 
 	/* Register the CPU genpd */
 	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
-	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
+	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
 	if (ret) {
 		pr_err("Unable to initialize domain %s\n", dn->full_name);
 		return ret;
-- 
2.1.4

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

A PM domain comprising of CPUs may be powered off when all the CPUs in
the domain are powered down. Powering down a CPU domain is generally a
expensive operation and therefore the power performance trade offs
should be considered. The time between the last CPU powering down and
the first CPU powering up in a domain, is the time available for the
domain to sleep. Ideally, the sleep time of the domain should fulfill
the residency requirement of the domains' idle state.

To do this effectively, read the time before the wakeup of the cluster's
CPUs and ensure that the domain's idle state sleep time guarantees the
QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
state's residency.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index 617ce54..a00abc1 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -21,6 +21,7 @@
 #include <linux/pm_qos.h>
 #include <linux/rculist.h>
 #include <linux/slab.h>
+#include <linux/tick.h>
 
 #define CPU_PD_NAME_MAX 36
 
@@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
 	}
 }
 
+static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
+{
+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
+	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
+	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+	u64 sleep_ns = ~0;
+	ktime_t earliest;
+	int cpu;
+	int i;
+
+	/* Reset the last set genpd state, default to index 0 */
+	genpd->state_idx = 0;
+
+	/* We dont want to power down, if QoS is 0 */
+	if (!qos)
+		return false;
+
+	/*
+	 * Find the sleep time for the cluster.
+	 * The time between now and the first wake up of any CPU that
+	 * are in this domain hierarchy is the time available for the
+	 * domain to be idle.
+	 */
+	earliest.tv64 = KTIME_MAX;
+	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
+		struct device *cpu_dev = get_cpu_device(cpu);
+		struct gpd_timing_data *td;
+
+		td = &dev_gpd_data(cpu_dev)->td;
+
+		if (earliest.tv64 < td->next_wakeup.tv64)
+			earliest = td->next_wakeup;
+	}
+
+	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
+	if (sleep_ns <= 0)
+		return false;
+
+	/*
+	 * Find the deepest sleep state that satisfies the residency
+	 * requirement and the QoS constraint
+	 */
+	for (i = genpd->state_count - 1; i > 0; i--) {
+		u64 state_sleep_ns;
+
+		state_sleep_ns = genpd->states[i].power_off_latency_ns +
+			genpd->states[i].power_on_latency_ns +
+			genpd->states[i].residency_ns;
+
+		/*
+		 * If we cant sleep to save power in the state, move on
+		 * to the next lower idle state.
+		 */
+		if (state_sleep_ns > sleep_ns)
+		       continue;
+
+		/*
+		 * We also dont want to sleep more than we should to
+		 * gaurantee QoS.
+		 */
+		if (state_sleep_ns < (qos * NSEC_PER_USEC))
+			break;
+	}
+
+	if (i >= 0)
+		genpd->state_idx = i;
+
+	return  (i >= 0) ? true : false;
+}
+
+static bool cpu_stop_ok(struct device *dev)
+{
+	return true;
+}
+
+struct dev_power_governor cpu_pd_gov = {
+	.power_down_ok = cpu_pd_down_ok,
+	.stop_ok = cpu_stop_ok,
+};
+
 static int cpu_pd_power_off(struct generic_pm_domain *genpd)
 {
 	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
@@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
 
 	/* Register the CPU genpd */
 	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
-	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
+	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
 	if (ret) {
 		pr_err("Unable to initialize domain %s\n", dn->full_name);
 		return ret;
-- 
2.1.4

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

* [PATCH RFC 19/27] drivers: cpu-pd: Invoke CPU PM runtime on hotplug
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

When a CPU is hotplugged off invoke CPU runtime suspend to notify
runtime PM of the CPU being powered down and opportunistically power
down the domain as well. Do that independent of the architecture using
hotplug notifiers.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index a00abc1..e331ae6 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -237,6 +237,30 @@ static int of_pm_domain_attach_cpus(struct device_node *dn,
 	return 0;
 }
 
+static int cpu_hotplug(struct notifier_block *nb,
+			unsigned long action, void *data)
+{
+	struct device *dev = get_cpu_device(smp_processor_id());
+
+	/* Execute CPU runtime PM on that CPU */
+	switch (action) {
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		pm_runtime_put_sync_suspend(dev);
+		pm_runtime_disable(dev);
+		break;
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		pm_runtime_enable(dev);
+		pm_runtime_get_sync(dev);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
 int of_register_cpu_pm_domain(struct device_node *dn,
 		struct cpu_pm_domain *pd)
 {
@@ -277,10 +301,13 @@ int of_register_cpu_pm_domain(struct device_node *dn,
 
 	/* Attach the CPUs to the CPU PM domain */
 	ret = of_pm_domain_attach_cpus(dn, pd);
-	if (ret)
+	if (ret) {
 		of_genpd_del_provider(dn);
+		return ret;
+	}
 
-	return ret;
+	hotcpu_notifier(cpu_hotplug, 0)
+	return 0;
 }
 
 /**
-- 
2.1.4


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

* [PATCH RFC 19/27] drivers: cpu-pd: Invoke CPU PM runtime on hotplug
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

When a CPU is hotplugged off invoke CPU runtime suspend to notify
runtime PM of the CPU being powered down and opportunistically power
down the domain as well. Do that independent of the architecture using
hotplug notifiers.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index a00abc1..e331ae6 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -237,6 +237,30 @@ static int of_pm_domain_attach_cpus(struct device_node *dn,
 	return 0;
 }
 
+static int cpu_hotplug(struct notifier_block *nb,
+			unsigned long action, void *data)
+{
+	struct device *dev = get_cpu_device(smp_processor_id());
+
+	/* Execute CPU runtime PM on that CPU */
+	switch (action) {
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		pm_runtime_put_sync_suspend(dev);
+		pm_runtime_disable(dev);
+		break;
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		pm_runtime_enable(dev);
+		pm_runtime_get_sync(dev);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
 int of_register_cpu_pm_domain(struct device_node *dn,
 		struct cpu_pm_domain *pd)
 {
@@ -277,10 +301,13 @@ int of_register_cpu_pm_domain(struct device_node *dn,
 
 	/* Attach the CPUs to the CPU PM domain */
 	ret = of_pm_domain_attach_cpus(dn, pd);
-	if (ret)
+	if (ret) {
 		of_genpd_del_provider(dn);
+		return ret;
+	}
 
-	return ret;
+	hotcpu_notifier(cpu_hotplug, 0)
+	return 0;
 }
 
 /**
-- 
2.1.4

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

* [PATCH RFC 20/27] Documentation: ARM: topology: 'cluster' property for cluster nodes
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Rob Herring

Add a place holder phandle for a cluster to define cluster specific
properties like PM domain definitions etc.

Cc: Rob Herring <robherring2@gmail.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/arm/topology.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/topology.txt b/Documentation/devicetree/bindings/arm/topology.txt
index 1061faf..12b4082 100644
--- a/Documentation/devicetree/bindings/arm/topology.txt
+++ b/Documentation/devicetree/bindings/arm/topology.txt
@@ -109,6 +109,14 @@ Bindings for cluster/cpu/thread nodes are defined as follows:
 	The cluster node name must be "clusterN" as described in 2.1 above.
 	A cluster node can not be a leaf node.
 
+	Properties for a cluster node are -
+
+	-cluster
+		Usage: Optional
+		Value type: <phandle>
+		Definition: a phandle to a cluster node that corresponds to
+			    this cluster.
+
 	A cluster node's child nodes must be:
 
 	- one or more cluster nodes; or
-- 
2.1.4

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

* [PATCH RFC 20/27] Documentation: ARM: topology: 'cluster' property for cluster nodes
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Add a place holder phandle for a cluster to define cluster specific
properties like PM domain definitions etc.

Cc: Rob Herring <robherring2@gmail.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/arm/topology.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/topology.txt b/Documentation/devicetree/bindings/arm/topology.txt
index 1061faf..12b4082 100644
--- a/Documentation/devicetree/bindings/arm/topology.txt
+++ b/Documentation/devicetree/bindings/arm/topology.txt
@@ -109,6 +109,14 @@ Bindings for cluster/cpu/thread nodes are defined as follows:
 	The cluster node name must be "clusterN" as described in 2.1 above.
 	A cluster node can not be a leaf node.
 
+	Properties for a cluster node are -
+
+	-cluster
+		Usage: Optional
+		Value type: <phandle>
+		Definition: a phandle to a cluster node that corresponds to
+			    this cluster.
+
 	A cluster node's child nodes must be:
 
 	- one or more cluster nodes; or
-- 
2.1.4

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Rob Herring

Architectures that support CPU domain control in the firmware specify
the domain heirarchy as part of the topology nodes. Parse and initialize
domains from the topology node for such architectures.

Cc: Rob Herring <robherring2@gmail.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Kevin Hilman <khilman@linaro.org>
Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/cpu-pd.h      |  1 +
 2 files changed, 77 insertions(+)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index e331ae6..2872c18 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -429,3 +429,79 @@ int of_attach_cpu_pm_domain(struct device_node *dn)
 	return 0;
 }
 EXPORT_SYMBOL(of_attach_cpu_pm_domain);
+
+static int of_parse_cpu_pd(struct device_node *cluster,
+		const struct cpu_pd_ops *ops)
+{
+	struct device_node *domain_node;
+	struct generic_pm_domain *genpd;
+	char name[10];
+	struct device_node *c;
+	int i, ret;
+
+	for (i = 0; ; i++) {
+		snprintf(name, sizeof(name), "cluster%d", i);
+		c = of_get_child_by_name(cluster, name);
+		if (!c)
+			break;
+
+		domain_node = of_parse_phandle(c, "cluster", 0);
+		if (!domain_node)
+			return -1;
+
+		/* Initialize CPU PM domain domain at this level */
+		genpd = of_init_cpu_pm_domain(domain_node, ops);
+		if (IS_ERR(genpd))
+			return -1;
+
+		/* Initialize and attach child domains */
+		ret = of_parse_cpu_pd(c, ops);
+
+		/*
+		 * Attach the domain to its parent after reading
+		 * the children, so the mask of CPUs in this domain
+		 * are setup correctly.
+		 */
+		if (!ret)
+			of_attach_cpu_pm_domain(domain_node);
+
+		of_node_put(c);
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
+ * topology node in DT.
+ *
+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
+ */
+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
+{
+	struct device_node *cn, *map;
+	int ret = 0;
+
+	cn = of_find_node_by_path("/cpus");
+	if (!cn) {
+		pr_err("No CPU information found in DT\n");
+		return 0;
+	}
+
+	map = of_get_child_by_name(cn, "cpu-map");
+	if (!map)
+		goto out;
+
+	ret = of_parse_cpu_pd(map, ops);
+	if (ret != 0)
+		goto out_map;
+
+out_map:
+	of_node_put(map);
+out:
+	of_node_put(cn);
+	return ret;
+}
+EXPORT_SYMBOL(of_setup_cpu_domain_topology);
diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
index 489ee2f..e8290db 100644
--- a/include/linux/cpu-pd.h
+++ b/include/linux/cpu-pd.h
@@ -32,4 +32,5 @@ struct cpu_pm_domain {
 struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 		const struct cpu_pd_ops *ops);
 int of_attach_cpu_pm_domain(struct device_node *dn);
+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
 #endif /* __CPU_PD_H__ */
-- 
2.1.4

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Architectures that support CPU domain control in the firmware specify
the domain heirarchy as part of the topology nodes. Parse and initialize
domains from the topology node for such architectures.

Cc: Rob Herring <robherring2@gmail.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Kevin Hilman <khilman@linaro.org>
Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/base/power/cpu-pd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/cpu-pd.h      |  1 +
 2 files changed, 77 insertions(+)

diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
index e331ae6..2872c18 100644
--- a/drivers/base/power/cpu-pd.c
+++ b/drivers/base/power/cpu-pd.c
@@ -429,3 +429,79 @@ int of_attach_cpu_pm_domain(struct device_node *dn)
 	return 0;
 }
 EXPORT_SYMBOL(of_attach_cpu_pm_domain);
+
+static int of_parse_cpu_pd(struct device_node *cluster,
+		const struct cpu_pd_ops *ops)
+{
+	struct device_node *domain_node;
+	struct generic_pm_domain *genpd;
+	char name[10];
+	struct device_node *c;
+	int i, ret;
+
+	for (i = 0; ; i++) {
+		snprintf(name, sizeof(name), "cluster%d", i);
+		c = of_get_child_by_name(cluster, name);
+		if (!c)
+			break;
+
+		domain_node = of_parse_phandle(c, "cluster", 0);
+		if (!domain_node)
+			return -1;
+
+		/* Initialize CPU PM domain domain at this level */
+		genpd = of_init_cpu_pm_domain(domain_node, ops);
+		if (IS_ERR(genpd))
+			return -1;
+
+		/* Initialize and attach child domains */
+		ret = of_parse_cpu_pd(c, ops);
+
+		/*
+		 * Attach the domain to its parent after reading
+		 * the children, so the mask of CPUs in this domain
+		 * are setup correctly.
+		 */
+		if (!ret)
+			of_attach_cpu_pm_domain(domain_node);
+
+		of_node_put(c);
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
+ * topology node in DT.
+ *
+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
+ */
+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
+{
+	struct device_node *cn, *map;
+	int ret = 0;
+
+	cn = of_find_node_by_path("/cpus");
+	if (!cn) {
+		pr_err("No CPU information found in DT\n");
+		return 0;
+	}
+
+	map = of_get_child_by_name(cn, "cpu-map");
+	if (!map)
+		goto out;
+
+	ret = of_parse_cpu_pd(map, ops);
+	if (ret != 0)
+		goto out_map;
+
+out_map:
+	of_node_put(map);
+out:
+	of_node_put(cn);
+	return ret;
+}
+EXPORT_SYMBOL(of_setup_cpu_domain_topology);
diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
index 489ee2f..e8290db 100644
--- a/include/linux/cpu-pd.h
+++ b/include/linux/cpu-pd.h
@@ -32,4 +32,5 @@ struct cpu_pm_domain {
 struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
 		const struct cpu_pd_ops *ops);
 int of_attach_cpu_pm_domain(struct device_node *dn);
+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
 #endif /* __CPU_PD_H__ */
-- 
2.1.4

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

* [PATCH RFC 22/27] drivers: firmware: PSCI: Export psci_has_ext_power_state()
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Mark Rutland

Export psci_has_ext_power_state() to allow PSCI layers to determine and
pass the correct state id in the format supported.

Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/firmware/psci.c | 2 +-
 include/linux/psci.h    | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index d24f35d..3fd42e4 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -83,7 +83,7 @@ static u32 psci_function_id[PSCI_FN_MAX];
 
 static u32 psci_cpu_suspend_feature;
 
-static inline bool psci_has_ext_power_state(void)
+bool psci_has_ext_power_state(void)
 {
 	return psci_cpu_suspend_feature &
 				PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK;
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 12c4865..b9afbe2 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -23,6 +23,7 @@
 bool psci_tos_resident_on(int cpu);
 bool psci_power_state_loses_context(u32 state);
 bool psci_power_state_is_valid(u32 state);
+bool psci_has_ext_power_state(void);
 
 struct psci_operations {
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
-- 
2.1.4


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

* [PATCH RFC 22/27] drivers: firmware: PSCI: Export psci_has_ext_power_state()
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Export psci_has_ext_power_state() to allow PSCI layers to determine and
pass the correct state id in the format supported.

Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 drivers/firmware/psci.c | 2 +-
 include/linux/psci.h    | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index d24f35d..3fd42e4 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -83,7 +83,7 @@ static u32 psci_function_id[PSCI_FN_MAX];
 
 static u32 psci_cpu_suspend_feature;
 
-static inline bool psci_has_ext_power_state(void)
+bool psci_has_ext_power_state(void)
 {
 	return psci_cpu_suspend_feature &
 				PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK;
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 12c4865..b9afbe2 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -23,6 +23,7 @@
 bool psci_tos_resident_on(int cpu);
 bool psci_power_state_loses_context(u32 state);
 bool psci_power_state_is_valid(u32 state);
+bool psci_has_ext_power_state(void);
 
 struct psci_operations {
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
-- 
2.1.4

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

* [PATCH RFC 23/27] ARM64: psci: Support cluster idle states for OS-Initated
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer, Daniel Lezcano,
	Mark Rutland

ARMv8 PSCI firmware may allow Linux to determine the state of the CPU
cluster and the cluster at coherency level to enter idle states when
there are no active CPUs. Since Linux has a better idea of the QoS and
the wakeup pattern of the CPUs, the cluster idle states may be better
determined by the OS instead of the firmware.

The last CPU entering idle in a cluster, holds the responsibility of
selecting the state of the cluster. Only one CPU in a cluster may
provide the cluster idle state to the firmware. Similarly, the last CPU
in the cluster of clusters may provide the state of the coherency
domain.

The CPU PM domain framework facilitates registration of CPU PM domains
and reference counting for the last man down and the first man up. But
the organzation of CPUs into clusters must be provided. The cpu-map
topology node provides the information. Call into the CPU PM framework
to parse the CPU topology node and setup the PM domains. The state id
for the cluster ids is available with the domain idle state.

The last CPU PSCI state id of the entire system would therefore be -
Coherency State ID + Cluster State ID + CPU idle state ID, that is
passed into the PSCI firmware when the CPU makes the PSCI enable-method.

Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm64/kernel/psci.c | 54 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f67f35b..6618d33 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,10 +15,12 @@
 
 #define pr_fmt(fmt) "psci: " fmt
 
+#include <linux/cpu-pd.h>
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/smp.h>
 #include <linux/delay.h>
+#include <linux/pm_domain.h>
 #include <linux/psci.h>
 #include <linux/slab.h>
 
@@ -31,6 +33,44 @@
 #include <asm/suspend.h>
 
 static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+static DEFINE_PER_CPU(u32, cluster_state_id);
+
+static inline u32 psci_get_composite_state_id(u32 cpu_state)
+{
+	u32 val = cpu_state;
+
+	if (psci_has_ext_power_state())
+		val += this_cpu_read(cluster_state_id);
+
+	return val;
+}
+
+static inline void psci_reset_composite_state_id(void)
+{
+	this_cpu_write(cluster_state_id, 0);
+}
+
+static int psci_pd_power_on(struct generic_pm_domain *genpd)
+{
+	return 0;
+}
+
+static int psci_pd_power_off(struct generic_pm_domain *genpd)
+{
+	__this_cpu_add(cluster_state_id, genpd->states[genpd->state_idx].param);
+	return 0;
+}
+
+static const struct cpu_pd_ops psci_pd_ops = {
+	.power_on = psci_pd_power_on,
+	.power_off = psci_pd_power_off,
+};
+
+static int __init psci_setup_cpu_domains(void)
+{
+	return of_setup_cpu_domain_topology(&psci_pd_ops);
+}
+subsys_initcall(psci_setup_cpu_domains);
 
 static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
 {
@@ -117,6 +157,8 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
 	if (err)
 		pr_err("failed to boot CPU%d (%d)\n", cpu, err);
 
+	/* Reset CPU cluster states */
+	psci_reset_composite_state_id();
 	return err;
 }
 
@@ -181,15 +223,16 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
 static int psci_suspend_finisher(unsigned long index)
 {
 	u32 *state = __this_cpu_read(psci_power_state);
+	u32 ext_state = psci_get_composite_state_id(state[index - 1]);
 
-	return psci_ops.cpu_suspend(state[index - 1],
-				    virt_to_phys(cpu_resume));
+	return psci_ops.cpu_suspend(ext_state, virt_to_phys(cpu_resume));
 }
 
 static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
 {
 	int ret;
 	u32 *state = __this_cpu_read(psci_power_state);
+	u32 ext_state = psci_get_composite_state_id(state[index - 1]);
 	/*
 	 * idle state index 0 corresponds to wfi, should never be called
 	 * from the cpu_suspend operations
@@ -198,10 +241,15 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
 		return -EINVAL;
 
 	if (!psci_power_state_loses_context(state[index - 1]))
-		ret = psci_ops.cpu_suspend(state[index - 1], 0);
+		ret = psci_ops.cpu_suspend(ext_state, 0);
 	else
 		ret = cpu_suspend(index, psci_suspend_finisher);
 
+	/*
+	 * Clear the CPU's cluster states, we start afresh after coming
+	 * out of idle.
+	 */
+	psci_reset_composite_state_id();
 	return ret;
 }
 
-- 
2.1.4


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

* [PATCH RFC 23/27] ARM64: psci: Support cluster idle states for OS-Initated
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

ARMv8 PSCI firmware may allow Linux to determine the state of the CPU
cluster and the cluster at coherency level to enter idle states when
there are no active CPUs. Since Linux has a better idea of the QoS and
the wakeup pattern of the CPUs, the cluster idle states may be better
determined by the OS instead of the firmware.

The last CPU entering idle in a cluster, holds the responsibility of
selecting the state of the cluster. Only one CPU in a cluster may
provide the cluster idle state to the firmware. Similarly, the last CPU
in the cluster of clusters may provide the state of the coherency
domain.

The CPU PM domain framework facilitates registration of CPU PM domains
and reference counting for the last man down and the first man up. But
the organzation of CPUs into clusters must be provided. The cpu-map
topology node provides the information. Call into the CPU PM framework
to parse the CPU topology node and setup the PM domains. The state id
for the cluster ids is available with the domain idle state.

The last CPU PSCI state id of the entire system would therefore be -
Coherency State ID + Cluster State ID + CPU idle state ID, that is
passed into the PSCI firmware when the CPU makes the PSCI enable-method.

Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm64/kernel/psci.c | 54 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f67f35b..6618d33 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,10 +15,12 @@
 
 #define pr_fmt(fmt) "psci: " fmt
 
+#include <linux/cpu-pd.h>
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/smp.h>
 #include <linux/delay.h>
+#include <linux/pm_domain.h>
 #include <linux/psci.h>
 #include <linux/slab.h>
 
@@ -31,6 +33,44 @@
 #include <asm/suspend.h>
 
 static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+static DEFINE_PER_CPU(u32, cluster_state_id);
+
+static inline u32 psci_get_composite_state_id(u32 cpu_state)
+{
+	u32 val = cpu_state;
+
+	if (psci_has_ext_power_state())
+		val += this_cpu_read(cluster_state_id);
+
+	return val;
+}
+
+static inline void psci_reset_composite_state_id(void)
+{
+	this_cpu_write(cluster_state_id, 0);
+}
+
+static int psci_pd_power_on(struct generic_pm_domain *genpd)
+{
+	return 0;
+}
+
+static int psci_pd_power_off(struct generic_pm_domain *genpd)
+{
+	__this_cpu_add(cluster_state_id, genpd->states[genpd->state_idx].param);
+	return 0;
+}
+
+static const struct cpu_pd_ops psci_pd_ops = {
+	.power_on = psci_pd_power_on,
+	.power_off = psci_pd_power_off,
+};
+
+static int __init psci_setup_cpu_domains(void)
+{
+	return of_setup_cpu_domain_topology(&psci_pd_ops);
+}
+subsys_initcall(psci_setup_cpu_domains);
 
 static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
 {
@@ -117,6 +157,8 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
 	if (err)
 		pr_err("failed to boot CPU%d (%d)\n", cpu, err);
 
+	/* Reset CPU cluster states */
+	psci_reset_composite_state_id();
 	return err;
 }
 
@@ -181,15 +223,16 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
 static int psci_suspend_finisher(unsigned long index)
 {
 	u32 *state = __this_cpu_read(psci_power_state);
+	u32 ext_state = psci_get_composite_state_id(state[index - 1]);
 
-	return psci_ops.cpu_suspend(state[index - 1],
-				    virt_to_phys(cpu_resume));
+	return psci_ops.cpu_suspend(ext_state, virt_to_phys(cpu_resume));
 }
 
 static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
 {
 	int ret;
 	u32 *state = __this_cpu_read(psci_power_state);
+	u32 ext_state = psci_get_composite_state_id(state[index - 1]);
 	/*
 	 * idle state index 0 corresponds to wfi, should never be called
 	 * from the cpu_suspend operations
@@ -198,10 +241,15 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
 		return -EINVAL;
 
 	if (!psci_power_state_loses_context(state[index - 1]))
-		ret = psci_ops.cpu_suspend(state[index - 1], 0);
+		ret = psci_ops.cpu_suspend(ext_state, 0);
 	else
 		ret = cpu_suspend(index, psci_suspend_finisher);
 
+	/*
+	 * Clear the CPU's cluster states, we start afresh after coming
+	 * out of idle.
+	 */
+	psci_reset_composite_state_id();
 	return ret;
 }
 
-- 
2.1.4

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

* [PATCH RFC 24/27] arm64: dts: Add Qualcomm MSM8916, MTP8916, APQ8016, SBC8016 ids
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Kumar Gala

From: Kumar Gala <galak@codeaurora.org>

Add qcom,msm-id and qcom,board-id to allow bootloader to identify which
device tree to boot on the MTP8916 & SBC8016 boards.

Signed-off-by: Kumar Gala <galak@codeaurora.org>
---
 arch/arm64/boot/dts/qcom/apq8016-sbc.dts | 2 ++
 arch/arm64/boot/dts/qcom/msm8916-mtp.dts | 3 +++
 arch/arm64/boot/dts/qcom/msm8916.dtsi    | 6 ++++++
 3 files changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
index 825f489..6fea25d 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
@@ -13,9 +13,11 @@
 
 /dts-v1/;
 
+#include <dt-bindings/arm/qcom-ids.h>
 #include "apq8016-sbc.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. APQ 8016 SBC";
 	compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
+	qcom,board-id = <QCOM_BRD_ID(SBC, 1, 0) QCOM_BRD_SUBTYPE_DEFAULT>;
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
index fced77f..6c68b4e 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
@@ -13,10 +13,13 @@
 
 /dts-v1/;
 
+#include <dt-bindings/arm/qcom-ids.h>
 #include "msm8916-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM 8916 MTP";
 	compatible = "qcom,msm8916-mtp", "qcom,msm8916-mtp-smb1360",
 			"qcom,msm8916", "qcom,mtp";
+	qcom,board-id = <QCOM_BRD_ID(MTP, 1, 0) QCOM_BRD_SUBTYPE_DEFAULT>,
+			<QCOM_BRD_ID(MTP, 1, 0) QCOM_BRD_SUBTYPE_MTP8916_SMB1360>;
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 8d184ff..7be7c23 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -14,10 +14,16 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-msm8916.h>
 #include <dt-bindings/reset/qcom,gcc-msm8916.h>
+#include <dt-bindings/arm/qcom-ids.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8916";
 	compatible = "qcom,msm8916";
+	qcom,msm-id =	<QCOM_ID_MSM8916 0>,
+			<QCOM_ID_MSM8216 0>,
+			<QCOM_ID_MSM8116 0>,
+			<QCOM_ID_MSM8616 0>,
+			<QCOM_ID_APQ8016 0>;
 
 	interrupt-parent = <&intc>;
 
-- 
2.1.4


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

* [PATCH RFC 24/27] arm64: dts: Add Qualcomm MSM8916, MTP8916, APQ8016, SBC8016 ids
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kumar Gala <galak@codeaurora.org>

Add qcom,msm-id and qcom,board-id to allow bootloader to identify which
device tree to boot on the MTP8916 & SBC8016 boards.

Signed-off-by: Kumar Gala <galak@codeaurora.org>
---
 arch/arm64/boot/dts/qcom/apq8016-sbc.dts | 2 ++
 arch/arm64/boot/dts/qcom/msm8916-mtp.dts | 3 +++
 arch/arm64/boot/dts/qcom/msm8916.dtsi    | 6 ++++++
 3 files changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
index 825f489..6fea25d 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
@@ -13,9 +13,11 @@
 
 /dts-v1/;
 
+#include <dt-bindings/arm/qcom-ids.h>
 #include "apq8016-sbc.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. APQ 8016 SBC";
 	compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
+	qcom,board-id = <QCOM_BRD_ID(SBC, 1, 0) QCOM_BRD_SUBTYPE_DEFAULT>;
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
index fced77f..6c68b4e 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dts
@@ -13,10 +13,13 @@
 
 /dts-v1/;
 
+#include <dt-bindings/arm/qcom-ids.h>
 #include "msm8916-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM 8916 MTP";
 	compatible = "qcom,msm8916-mtp", "qcom,msm8916-mtp-smb1360",
 			"qcom,msm8916", "qcom,mtp";
+	qcom,board-id = <QCOM_BRD_ID(MTP, 1, 0) QCOM_BRD_SUBTYPE_DEFAULT>,
+			<QCOM_BRD_ID(MTP, 1, 0) QCOM_BRD_SUBTYPE_MTP8916_SMB1360>;
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 8d184ff..7be7c23 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -14,10 +14,16 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-msm8916.h>
 #include <dt-bindings/reset/qcom,gcc-msm8916.h>
+#include <dt-bindings/arm/qcom-ids.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8916";
 	compatible = "qcom,msm8916";
+	qcom,msm-id =	<QCOM_ID_MSM8916 0>,
+			<QCOM_ID_MSM8216 0>,
+			<QCOM_ID_MSM8116 0>,
+			<QCOM_ID_MSM8616 0>,
+			<QCOM_ID_APQ8016 0>;
 
 	interrupt-parent = <&intc>;
 
-- 
2.1.4

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

* [PATCH RFC 25/27] devicetree: bindings: Document qcom,msm-id and qcom,board-id
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Kumar Gala, devicetree

From: Kumar Gala <galak@codeaurora.org>

The top level qcom,msm-id and qcom,board-id are utilized by bootloaders
on Qualcomm MSM platforms to determine which device tree should be
utilized and passed to the kernel.

Cc: <devicetree@vger.kernel.org>
Signed-off-by: Kumar Gala <galak@codeaurora.org>
---
 Documentation/devicetree/bindings/arm/msm/ids.txt | 65 +++++++++++++++++++++++
 include/dt-bindings/arm/qcom-ids.h                | 33 ++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/ids.txt
 create mode 100644 include/dt-bindings/arm/qcom-ids.h

diff --git a/Documentation/devicetree/bindings/arm/msm/ids.txt b/Documentation/devicetree/bindings/arm/msm/ids.txt
new file mode 100644
index 0000000..9ee8428
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/ids.txt
@@ -0,0 +1,65 @@
+* MSM-ID
+
+The qcom,msm-id entry specifies the MSM chipset and hardware revision.  It can
+optionally be an array of these to indicate multiple hardware that use the same
+device tree.  It is expected that the bootloader will use this information at
+boot-up to decide which device tree to use when given multiple device trees,
+some of which may not be compatible with the actual hardware.  It is the
+bootloader's responsibility to pass the correct device tree to the kernel.
+
+PROPERTIES
+
+- qcom,msm-id:
+	Usage: required
+	Value type: <prop-encoded-array> (<chipset_id, rev_id> [, <c2, r2> ..])
+	Definition:
+		The "chipset_id" consists of three fields as below:
+
+		bits 0-15  = The unique MSM chipset id.
+		bits 16-31 = Reserved.  Should be 0
+
+		chipset_id is an exact match value
+
+		The "rev_id" is a chipset specific 32-bit id that represents
+		the version of the chipset.
+
+		The rev_id is a best match id.  The bootloader will look for
+		the closest possible patch.
+
+* BOARD-ID
+
+The qcom,board-id entry specifies the board type and revision information.  It
+can optionally be an array of these to indicate multiple boards that use the
+same device tree.  It is expected that the bootloader will use this information
+at boot-up to decide which device tree to use when given multiple device trees,
+some of which may not be compatible with the actual hardware.  It is the
+bootloader's responsibility to pass the correct device tree to the kernel.
+
+PROPERTIES
+
+- qcom,board-id:
+	Usage: required
+	Value type: <prop-encoded-array> (<board_id, subtype_id> [, <b2, s2> ..])
+	Definition:
+		The "board_id" consists of three fields as below:
+
+		bits 31-24 = Unusued.
+		bits 23-16 = Platform Version Major
+		bits 15-8  = Platfrom Version Minor
+		bits 7-0   = Platform Type
+
+		Platform Type field is an exact match value.  The Platform
+		Major/Minor field is a best match.  The bootloader will look
+		for the closest possible match.
+
+		The "subtype_id" is unique to a Platform Type/Chipset ID.  For
+		a given Platform Type, there will typically only be a single
+		board and the subtype_id will be 0.  However in some cases board
+		variants may need to be distinquished by different subtype_id
+		values.
+
+		subtype_id is an exact match value.
+
+EXAMPLE:
+	qcom,board-id = <15 2>;
+	qcom,msm-id = <0x1007e 0>;
diff --git a/include/dt-bindings/arm/qcom-ids.h b/include/dt-bindings/arm/qcom-ids.h
new file mode 100644
index 0000000..a18f34e
--- /dev/null
+++ b/include/dt-bindings/arm/qcom-ids.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DT_BINDINGS_QCOM_IDS_H
+#define __DT_BINDINGS_QCOM_IDS_H
+
+/* qcom,msm-id */
+#define QCOM_ID_MSM8916		206
+#define QCOM_ID_APQ8016		247
+#define QCOM_ID_MSM8216		248
+#define QCOM_ID_MSM8116		249
+#define QCOM_ID_MSM8616		250
+
+/* qcom,board-id */
+#define QCOM_BRD_ID(a, major, minor) \
+	(((major & 0xff) << 16) | ((minor & 0xff) << 8) | QCOM_BRD_ID_##a)
+
+#define QCOM_BRD_ID_MTP		8
+#define QCOM_BRD_ID_DRAGONBRD	10
+#define QCOM_BRD_ID_SBC		24
+
+#define QCOM_BRD_SUBTYPE_DEFAULT		0
+#define QCOM_BRD_SUBTYPE_MTP8916_SMB1360	1
+
+#endif
-- 
2.1.4

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

* [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom, board-id
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kumar Gala <galak@codeaurora.org>

The top level qcom,msm-id and qcom,board-id are utilized by bootloaders
on Qualcomm MSM platforms to determine which device tree should be
utilized and passed to the kernel.

Cc: <devicetree@vger.kernel.org>
Signed-off-by: Kumar Gala <galak@codeaurora.org>
---
 Documentation/devicetree/bindings/arm/msm/ids.txt | 65 +++++++++++++++++++++++
 include/dt-bindings/arm/qcom-ids.h                | 33 ++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/ids.txt
 create mode 100644 include/dt-bindings/arm/qcom-ids.h

diff --git a/Documentation/devicetree/bindings/arm/msm/ids.txt b/Documentation/devicetree/bindings/arm/msm/ids.txt
new file mode 100644
index 0000000..9ee8428
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/ids.txt
@@ -0,0 +1,65 @@
+* MSM-ID
+
+The qcom,msm-id entry specifies the MSM chipset and hardware revision.  It can
+optionally be an array of these to indicate multiple hardware that use the same
+device tree.  It is expected that the bootloader will use this information at
+boot-up to decide which device tree to use when given multiple device trees,
+some of which may not be compatible with the actual hardware.  It is the
+bootloader's responsibility to pass the correct device tree to the kernel.
+
+PROPERTIES
+
+- qcom,msm-id:
+	Usage: required
+	Value type: <prop-encoded-array> (<chipset_id, rev_id> [, <c2, r2> ..])
+	Definition:
+		The "chipset_id" consists of three fields as below:
+
+		bits 0-15  = The unique MSM chipset id.
+		bits 16-31 = Reserved.  Should be 0
+
+		chipset_id is an exact match value
+
+		The "rev_id" is a chipset specific 32-bit id that represents
+		the version of the chipset.
+
+		The rev_id is a best match id.  The bootloader will look for
+		the closest possible patch.
+
+* BOARD-ID
+
+The qcom,board-id entry specifies the board type and revision information.  It
+can optionally be an array of these to indicate multiple boards that use the
+same device tree.  It is expected that the bootloader will use this information
+at boot-up to decide which device tree to use when given multiple device trees,
+some of which may not be compatible with the actual hardware.  It is the
+bootloader's responsibility to pass the correct device tree to the kernel.
+
+PROPERTIES
+
+- qcom,board-id:
+	Usage: required
+	Value type: <prop-encoded-array> (<board_id, subtype_id> [, <b2, s2> ..])
+	Definition:
+		The "board_id" consists of three fields as below:
+
+		bits 31-24 = Unusued.
+		bits 23-16 = Platform Version Major
+		bits 15-8  = Platfrom Version Minor
+		bits 7-0   = Platform Type
+
+		Platform Type field is an exact match value.  The Platform
+		Major/Minor field is a best match.  The bootloader will look
+		for the closest possible match.
+
+		The "subtype_id" is unique to a Platform Type/Chipset ID.  For
+		a given Platform Type, there will typically only be a single
+		board and the subtype_id will be 0.  However in some cases board
+		variants may need to be distinquished by different subtype_id
+		values.
+
+		subtype_id is an exact match value.
+
+EXAMPLE:
+	qcom,board-id = <15 2>;
+	qcom,msm-id = <0x1007e 0>;
diff --git a/include/dt-bindings/arm/qcom-ids.h b/include/dt-bindings/arm/qcom-ids.h
new file mode 100644
index 0000000..a18f34e
--- /dev/null
+++ b/include/dt-bindings/arm/qcom-ids.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DT_BINDINGS_QCOM_IDS_H
+#define __DT_BINDINGS_QCOM_IDS_H
+
+/* qcom,msm-id */
+#define QCOM_ID_MSM8916		206
+#define QCOM_ID_APQ8016		247
+#define QCOM_ID_MSM8216		248
+#define QCOM_ID_MSM8116		249
+#define QCOM_ID_MSM8616		250
+
+/* qcom,board-id */
+#define QCOM_BRD_ID(a, major, minor) \
+	(((major & 0xff) << 16) | ((minor & 0xff) << 8) | QCOM_BRD_ID_##a)
+
+#define QCOM_BRD_ID_MTP		8
+#define QCOM_BRD_ID_DRAGONBRD	10
+#define QCOM_BRD_ID_SBC		24
+
+#define QCOM_BRD_SUBTYPE_DEFAULT		0
+#define QCOM_BRD_SUBTYPE_MTP8916_SMB1360	1
+
+#endif
-- 
2.1.4

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

* [PATCH RFC 26/27] ARM64: dts: Add PSCI cpuidle support for MSM8916
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Add device bindings for CPUs to suspend using PSCI as the enable-method.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 7be7c23..5806438 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -51,25 +51,49 @@
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
 
 		CPU1: cpu@1 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
 
 		CPU2: cpu@2 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
 
 		CPU3: cpu@3 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
+
+		idle-states {
+			CPU_SPC: spc {
+				compatible = "qcom,idle-state-spc",
+						"arm,idle-state";
+				arm,psci-suspend-param = <0x40000002>;
+				entry-latency-us = <130>;
+				exit-latency-us = <150>;
+				min-residency-us = <2000>;
+			};
+		};
+	};
+	
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
 	};
 
 	timer {
-- 
2.1.4


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

* [PATCH RFC 26/27] ARM64: dts: Add PSCI cpuidle support for MSM8916
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Add device bindings for CPUs to suspend using PSCI as the enable-method.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 7be7c23..5806438 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -51,25 +51,49 @@
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
 
 		CPU1: cpu at 1 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
 
 		CPU2: cpu at 2 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
 
 		CPU3: cpu at 3 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SPC>;
 		};
+
+		idle-states {
+			CPU_SPC: spc {
+				compatible = "qcom,idle-state-spc",
+						"arm,idle-state";
+				arm,psci-suspend-param = <0x40000002>;
+				entry-latency-us = <130>;
+				exit-latency-us = <150>;
+				min-residency-us = <2000>;
+			};
+		};
+	};
+	
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
 	};
 
 	timer {
-- 
2.1.4

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

* [PATCH RFC 27/27] ARM64: dts: Define CPU power domain for MSM8916
  2015-11-17 22:37 ` Lina Iyer
@ 2015-11-17 22:37   ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: ulf.hansson, khilman, linux-pm, linux-arm-kernel
  Cc: geert, k.kozlowski, msivasub, agross, sboyd, linux-arm-msm,
	lorenzo.pieralisi, ahaslam, mtitinger, Lina Iyer

Define power domain and the power states for the domain as defined by
the PSCI firmware.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 48 ++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 5806438..3ea8126 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -47,12 +47,32 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
+		cpu-map {
+			cluster0 {
+				cluster = <&CLUSTER0>;
+
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
 		CPU0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x0>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		CPU1: cpu@1 {
@@ -61,6 +81,7 @@
 			reg = <0x1>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		CPU2: cpu@2 {
@@ -69,6 +90,7 @@
 			reg = <0x2>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		CPU3: cpu@3 {
@@ -77,6 +99,7 @@
 			reg = <0x3>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		idle-states {
@@ -89,8 +112,31 @@
 				min-residency-us = <2000>;
 			};
 		};
+
+		CLUSTER0: cluster@0 {
+			#power-domain-cells = <0>;
+			power-states = <&CLUSTER_RET>, <&CLUSTER_PWR_DWN>;
+		};
+
+		cluster-power-states {
+			CLUSTER_RET: power-state@1 {
+				compatible = "linux,domain-state";
+				state-param = <0x1000010>;
+				entry-latency-us = <500>;
+				exit-latency-us = <500>;
+				residency-us = <2000>;
+			 };
+
+			CLUSTER_PWR_DWN: power-state@2 {
+				compatible = "linux,domain-state";
+				state-param = <0x1000030>;
+				entry-latency-us = <2000>;
+				exit-latency-us = <2000>;
+				residency-us = <6000>;
+			};
+		};
 	};
-	
+
 	psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
-- 
2.1.4

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

* [PATCH RFC 27/27] ARM64: dts: Define CPU power domain for MSM8916
@ 2015-11-17 22:37   ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-17 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

Define power domain and the power states for the domain as defined by
the PSCI firmware.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 48 ++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 5806438..3ea8126 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -47,12 +47,32 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
+		cpu-map {
+			cluster0 {
+				cluster = <&CLUSTER0>;
+
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
 		CPU0: cpu at 0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a53", "arm,armv8";
 			reg = <0x0>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		CPU1: cpu at 1 {
@@ -61,6 +81,7 @@
 			reg = <0x1>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		CPU2: cpu at 2 {
@@ -69,6 +90,7 @@
 			reg = <0x2>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		CPU3: cpu at 3 {
@@ -77,6 +99,7 @@
 			reg = <0x3>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SPC>;
+			power-domains = <&CLUSTER0>;
 		};
 
 		idle-states {
@@ -89,8 +112,31 @@
 				min-residency-us = <2000>;
 			};
 		};
+
+		CLUSTER0: cluster at 0 {
+			#power-domain-cells = <0>;
+			power-states = <&CLUSTER_RET>, <&CLUSTER_PWR_DWN>;
+		};
+
+		cluster-power-states {
+			CLUSTER_RET: power-state at 1 {
+				compatible = "linux,domain-state";
+				state-param = <0x1000010>;
+				entry-latency-us = <500>;
+				exit-latency-us = <500>;
+				residency-us = <2000>;
+			 };
+
+			CLUSTER_PWR_DWN: power-state at 2 {
+				compatible = "linux,domain-state";
+				state-param = <0x1000030>;
+				entry-latency-us = <2000>;
+				exit-latency-us = <2000>;
+				residency-us = <6000>;
+			};
+		};
 	};
-	
+
 	psci {
 		compatible = "arm,psci-1.0";
 		method = "smc";
-- 
2.1.4

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

* Re: [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-18  8:50     ` Zhaoyang Huang
  -1 siblings, 0 replies; 166+ messages in thread
From: Zhaoyang Huang @ 2015-11-18  8:50 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Ulf Hansson, Kevin Hilman, linux-pm, linux-arm-kernel, geert,
	Krzysztof Kozłowski, msivasub, Andy Gross, sboyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Daniel Lezcano

On 18 November 2015 at 06:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> Notify runtime PM when the CPU is going to be powered off in the idle
> state. This allows for runtime PM suspend/resume of the CPU as well as
> its PM domain.
>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
> index 545069d..8e72a23 100644
> --- a/drivers/cpuidle/cpuidle-arm.c
> +++ b/drivers/cpuidle/cpuidle-arm.c
> @@ -11,13 +11,16 @@
>
>  #define pr_fmt(fmt) "CPUidle arm: " fmt
>
> +#include <linux/cpu.h>
>  #include <linux/cpuidle.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/slab.h>
> +#include <linux/rcupdate.h>
>
>  #include <asm/cpuidle.h>
>
> @@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>
>         ret = cpu_pm_enter();
>         if (!ret) {
> +               struct device *cpu_dev = get_cpu_device(dev->cpu);
> +
> +               RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
By my test, it seems that the usage_count of cpu device will be
decrease to -1 and the code never runs here. If it need a runtime_put
somewhere?
> +
>                 /*
>                  * Pass idle state index to cpu_suspend which in turn will
>                  * call the CPU ops suspend protocol with idle index as a
> @@ -52,6 +59,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>                  */
>                 arm_cpuidle_suspend(idx);
>
> +               RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
>                 cpu_pm_exit();
>         }
>
> --
> 2.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
@ 2015-11-18  8:50     ` Zhaoyang Huang
  0 siblings, 0 replies; 166+ messages in thread
From: Zhaoyang Huang @ 2015-11-18  8:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 18 November 2015 at 06:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> Notify runtime PM when the CPU is going to be powered off in the idle
> state. This allows for runtime PM suspend/resume of the CPU as well as
> its PM domain.
>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
> index 545069d..8e72a23 100644
> --- a/drivers/cpuidle/cpuidle-arm.c
> +++ b/drivers/cpuidle/cpuidle-arm.c
> @@ -11,13 +11,16 @@
>
>  #define pr_fmt(fmt) "CPUidle arm: " fmt
>
> +#include <linux/cpu.h>
>  #include <linux/cpuidle.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/slab.h>
> +#include <linux/rcupdate.h>
>
>  #include <asm/cpuidle.h>
>
> @@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>
>         ret = cpu_pm_enter();
>         if (!ret) {
> +               struct device *cpu_dev = get_cpu_device(dev->cpu);
> +
> +               RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
By my test, it seems that the usage_count of cpu device will be
decrease to -1 and the code never runs here. If it need a runtime_put
somewhere?
> +
>                 /*
>                  * Pass idle state index to cpu_suspend which in turn will
>                  * call the CPU ops suspend protocol with idle index as a
> @@ -52,6 +59,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>                  */
>                 arm_cpuidle_suspend(idx);
>
> +               RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
>                 cpu_pm_exit();
>         }
>
> --
> 2.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
  2015-11-18  8:50     ` Zhaoyang Huang
@ 2015-11-18 14:17       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-18 14:17 UTC (permalink / raw)
  To: Zhaoyang Huang
  Cc: Ulf Hansson, Kevin Hilman, linux-pm, linux-arm-kernel, geert,
	Krzysztof Kozłowski, msivasub, Andy Gross, sboyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Daniel Lezcano

On Wed, Nov 18 2015 at 01:50 -0700, Zhaoyang Huang wrote:
>On 18 November 2015 at 06:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> Notify runtime PM when the CPU is going to be powered off in the idle
>> state. This allows for runtime PM suspend/resume of the CPU as well as
>> its PM domain.
>>
>> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
>> index 545069d..8e72a23 100644
>> --- a/drivers/cpuidle/cpuidle-arm.c
>> +++ b/drivers/cpuidle/cpuidle-arm.c
>> @@ -11,13 +11,16 @@
>>
>>  #define pr_fmt(fmt) "CPUidle arm: " fmt
>>
>> +#include <linux/cpu.h>
>>  #include <linux/cpuidle.h>
>>  #include <linux/cpumask.h>
>>  #include <linux/cpu_pm.h>
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #include <linux/slab.h>
>> +#include <linux/rcupdate.h>
>>
>>  #include <asm/cpuidle.h>
>>
>> @@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>
>>         ret = cpu_pm_enter();
>>         if (!ret) {
>> +               struct device *cpu_dev = get_cpu_device(dev->cpu);
>> +
>> +               RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
>By my test, it seems that the usage_count of cpu device will be
>decrease to -1 and the code never runs here. If it need a runtime_put
>somewhere?

You shouldn't have to. Pls make sure all the patches are pulled in and
compiles successfully.

Let me know if you still run into issues.

Thanks,
Lina

>> +
>>                 /*
>>                  * Pass idle state index to cpu_suspend which in turn will
>>                  * call the CPU ops suspend protocol with idle index as a
>> @@ -52,6 +59,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>                  */
>>                 arm_cpuidle_suspend(idx);
>>
>> +               RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
>>                 cpu_pm_exit();
>>         }
>>
>> --
>> 2.1.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
@ 2015-11-18 14:17       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-18 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 18 2015 at 01:50 -0700, Zhaoyang Huang wrote:
>On 18 November 2015 at 06:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> Notify runtime PM when the CPU is going to be powered off in the idle
>> state. This allows for runtime PM suspend/resume of the CPU as well as
>> its PM domain.
>>
>> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
>> index 545069d..8e72a23 100644
>> --- a/drivers/cpuidle/cpuidle-arm.c
>> +++ b/drivers/cpuidle/cpuidle-arm.c
>> @@ -11,13 +11,16 @@
>>
>>  #define pr_fmt(fmt) "CPUidle arm: " fmt
>>
>> +#include <linux/cpu.h>
>>  #include <linux/cpuidle.h>
>>  #include <linux/cpumask.h>
>>  #include <linux/cpu_pm.h>
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #include <linux/slab.h>
>> +#include <linux/rcupdate.h>
>>
>>  #include <asm/cpuidle.h>
>>
>> @@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>
>>         ret = cpu_pm_enter();
>>         if (!ret) {
>> +               struct device *cpu_dev = get_cpu_device(dev->cpu);
>> +
>> +               RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
>By my test, it seems that the usage_count of cpu device will be
>decrease to -1 and the code never runs here. If it need a runtime_put
>somewhere?

You shouldn't have to. Pls make sure all the patches are pulled in and
compiles successfully.

Let me know if you still run into issues.

Thanks,
Lina

>> +
>>                 /*
>>                  * Pass idle state index to cpu_suspend which in turn will
>>                  * call the CPU ops suspend protocol with idle index as a
>> @@ -52,6 +59,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>                  */
>>                 arm_cpuidle_suspend(idx);
>>
>> +               RCU_NONIDLE(pm_runtime_get_sync(cpu_dev));
>>                 cpu_pm_exit();
>>         }
>>
>> --
>> 2.1.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-18 14:57     ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel, linux-pm; +Cc: linux-arm-msm, Axel Haslam, Lina Iyer

From: Axel Haslam <ahaslam+renesas@baylibre.com>

The generic_pm_domain structure uses an array of latencies to be able to
declare multiple intermediate states.

Declare a single "OFF" state with the default latencies So that the
power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
structure can be eventualy removed.

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
[Lina: pm_genpd_init() argument change]
---
 arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 8e7976a..b070e06 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
 	.name = "ARM",
 };
 
+static struct genpd_power_state imx6q_arm_domain_states[] = {
+	{
+		.name = "OFF",
+		.power_off_latency_ns = 25000,
+		.power_on_latency_ns = 2000000,
+	},
+};
+
 static struct pu_domain imx6q_pu_domain = {
 	.base = {
 		.name = "PU",
 		.power_off = imx6q_pm_pu_power_off,
 		.power_on = imx6q_pm_pu_power_on,
-		.power_off_latency_ns = 25000,
-		.power_on_latency_ns = 2000000,
+		.gov = NULL,
+		.status = GPD_STATE_POWER_OFF,
+		.states = imx6q_arm_domain_states,
+		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
 	},
 };
 
-- 
2.1.4


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

* [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
@ 2015-11-18 14:57     ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-18 14:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Axel Haslam <ahaslam+renesas@baylibre.com>

The generic_pm_domain structure uses an array of latencies to be able to
declare multiple intermediate states.

Declare a single "OFF" state with the default latencies So that the
power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
structure can be eventualy removed.

Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
[Lina: pm_genpd_init() argument change]
---
 arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 8e7976a..b070e06 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
 	.name = "ARM",
 };
 
+static struct genpd_power_state imx6q_arm_domain_states[] = {
+	{
+		.name = "OFF",
+		.power_off_latency_ns = 25000,
+		.power_on_latency_ns = 2000000,
+	},
+};
+
 static struct pu_domain imx6q_pu_domain = {
 	.base = {
 		.name = "PU",
 		.power_off = imx6q_pm_pu_power_off,
 		.power_on = imx6q_pm_pu_power_on,
-		.power_off_latency_ns = 25000,
-		.power_on_latency_ns = 2000000,
+		.gov = NULL,
+		.status = GPD_STATE_POWER_OFF,
+		.states = imx6q_arm_domain_states,
+		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
 	},
 };
 
-- 
2.1.4

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-18 18:42     ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-11-18 18:42 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger

On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
> A PM domain comprising of CPUs may be powered off when all the CPUs in
> the domain are powered down. Powering down a CPU domain is generally a
> expensive operation and therefore the power performance trade offs
> should be considered. The time between the last CPU powering down and
> the first CPU powering up in a domain, is the time available for the
> domain to sleep. Ideally, the sleep time of the domain should fulfill
> the residency requirement of the domains' idle state.
> 
> To do this effectively, read the time before the wakeup of the cluster's
> CPUs and ensure that the domain's idle state sleep time guarantees the
> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
> state's residency.

To me this information should be part of the CPUidle governor (it is
already there), we should not split the decision into multiple layers.

The problem you are facing is that the CPUidle governor(s) do not take
cross cpus relationship into account, I do not think that adding another
decision layer in the power domain subsystem helps, you are doing that
just because adding it to the existing CPUidle governor(s) is invasive.

Why can't we use the power domain work you put together to eg disable
idle states that share multiple cpus and make them "visible" only
when the power domain that encompass them is actually going down ?

You could use the power domains information to detect states that
are shared between cpus.

It is just an idea, what I am saying is that having another governor in
the power domain subsytem does not make much sense, you split the
decision in two layers while there is actually one, the existing
CPUidle governor and that's where the decision should be taken.

Thoughts appreciated.

Lorenzo

> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 82 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> index 617ce54..a00abc1 100644
> --- a/drivers/base/power/cpu-pd.c
> +++ b/drivers/base/power/cpu-pd.c
> @@ -21,6 +21,7 @@
>  #include <linux/pm_qos.h>
>  #include <linux/rculist.h>
>  #include <linux/slab.h>
> +#include <linux/tick.h>
>  
>  #define CPU_PD_NAME_MAX 36
>  
> @@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
>  	}
>  }
>  
> +static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
> +{
> +	struct generic_pm_domain *genpd = pd_to_genpd(pd);
> +	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
> +	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
> +	u64 sleep_ns = ~0;
> +	ktime_t earliest;
> +	int cpu;
> +	int i;
> +
> +	/* Reset the last set genpd state, default to index 0 */
> +	genpd->state_idx = 0;
> +
> +	/* We dont want to power down, if QoS is 0 */
> +	if (!qos)
> +		return false;
> +
> +	/*
> +	 * Find the sleep time for the cluster.
> +	 * The time between now and the first wake up of any CPU that
> +	 * are in this domain hierarchy is the time available for the
> +	 * domain to be idle.
> +	 */
> +	earliest.tv64 = KTIME_MAX;
> +	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
> +		struct device *cpu_dev = get_cpu_device(cpu);
> +		struct gpd_timing_data *td;
> +
> +		td = &dev_gpd_data(cpu_dev)->td;
> +
> +		if (earliest.tv64 < td->next_wakeup.tv64)
> +			earliest = td->next_wakeup;
> +	}
> +
> +	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
> +	if (sleep_ns <= 0)
> +		return false;
> +
> +	/*
> +	 * Find the deepest sleep state that satisfies the residency
> +	 * requirement and the QoS constraint
> +	 */
> +	for (i = genpd->state_count - 1; i > 0; i--) {
> +		u64 state_sleep_ns;
> +
> +		state_sleep_ns = genpd->states[i].power_off_latency_ns +
> +			genpd->states[i].power_on_latency_ns +
> +			genpd->states[i].residency_ns;
> +
> +		/*
> +		 * If we cant sleep to save power in the state, move on
> +		 * to the next lower idle state.
> +		 */
> +		if (state_sleep_ns > sleep_ns)
> +		       continue;
> +
> +		/*
> +		 * We also dont want to sleep more than we should to
> +		 * gaurantee QoS.
> +		 */
> +		if (state_sleep_ns < (qos * NSEC_PER_USEC))
> +			break;
> +	}
> +
> +	if (i >= 0)
> +		genpd->state_idx = i;
> +
> +	return  (i >= 0) ? true : false;
> +}
> +
> +static bool cpu_stop_ok(struct device *dev)
> +{
> +	return true;
> +}
> +
> +struct dev_power_governor cpu_pd_gov = {
> +	.power_down_ok = cpu_pd_down_ok,
> +	.stop_ok = cpu_stop_ok,
> +};
> +
>  static int cpu_pd_power_off(struct generic_pm_domain *genpd)
>  {
>  	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
> @@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
>  
>  	/* Register the CPU genpd */
>  	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
> -	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
> +	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
>  	if (ret) {
>  		pr_err("Unable to initialize domain %s\n", dn->full_name);
>  		return ret;
> -- 
> 2.1.4
> 

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-18 18:42     ` Lorenzo Pieralisi
  0 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-11-18 18:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
> A PM domain comprising of CPUs may be powered off when all the CPUs in
> the domain are powered down. Powering down a CPU domain is generally a
> expensive operation and therefore the power performance trade offs
> should be considered. The time between the last CPU powering down and
> the first CPU powering up in a domain, is the time available for the
> domain to sleep. Ideally, the sleep time of the domain should fulfill
> the residency requirement of the domains' idle state.
> 
> To do this effectively, read the time before the wakeup of the cluster's
> CPUs and ensure that the domain's idle state sleep time guarantees the
> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
> state's residency.

To me this information should be part of the CPUidle governor (it is
already there), we should not split the decision into multiple layers.

The problem you are facing is that the CPUidle governor(s) do not take
cross cpus relationship into account, I do not think that adding another
decision layer in the power domain subsystem helps, you are doing that
just because adding it to the existing CPUidle governor(s) is invasive.

Why can't we use the power domain work you put together to eg disable
idle states that share multiple cpus and make them "visible" only
when the power domain that encompass them is actually going down ?

You could use the power domains information to detect states that
are shared between cpus.

It is just an idea, what I am saying is that having another governor in
the power domain subsytem does not make much sense, you split the
decision in two layers while there is actually one, the existing
CPUidle governor and that's where the decision should be taken.

Thoughts appreciated.

Lorenzo

> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 82 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> index 617ce54..a00abc1 100644
> --- a/drivers/base/power/cpu-pd.c
> +++ b/drivers/base/power/cpu-pd.c
> @@ -21,6 +21,7 @@
>  #include <linux/pm_qos.h>
>  #include <linux/rculist.h>
>  #include <linux/slab.h>
> +#include <linux/tick.h>
>  
>  #define CPU_PD_NAME_MAX 36
>  
> @@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
>  	}
>  }
>  
> +static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
> +{
> +	struct generic_pm_domain *genpd = pd_to_genpd(pd);
> +	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
> +	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
> +	u64 sleep_ns = ~0;
> +	ktime_t earliest;
> +	int cpu;
> +	int i;
> +
> +	/* Reset the last set genpd state, default to index 0 */
> +	genpd->state_idx = 0;
> +
> +	/* We dont want to power down, if QoS is 0 */
> +	if (!qos)
> +		return false;
> +
> +	/*
> +	 * Find the sleep time for the cluster.
> +	 * The time between now and the first wake up of any CPU that
> +	 * are in this domain hierarchy is the time available for the
> +	 * domain to be idle.
> +	 */
> +	earliest.tv64 = KTIME_MAX;
> +	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
> +		struct device *cpu_dev = get_cpu_device(cpu);
> +		struct gpd_timing_data *td;
> +
> +		td = &dev_gpd_data(cpu_dev)->td;
> +
> +		if (earliest.tv64 < td->next_wakeup.tv64)
> +			earliest = td->next_wakeup;
> +	}
> +
> +	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
> +	if (sleep_ns <= 0)
> +		return false;
> +
> +	/*
> +	 * Find the deepest sleep state that satisfies the residency
> +	 * requirement and the QoS constraint
> +	 */
> +	for (i = genpd->state_count - 1; i > 0; i--) {
> +		u64 state_sleep_ns;
> +
> +		state_sleep_ns = genpd->states[i].power_off_latency_ns +
> +			genpd->states[i].power_on_latency_ns +
> +			genpd->states[i].residency_ns;
> +
> +		/*
> +		 * If we cant sleep to save power in the state, move on
> +		 * to the next lower idle state.
> +		 */
> +		if (state_sleep_ns > sleep_ns)
> +		       continue;
> +
> +		/*
> +		 * We also dont want to sleep more than we should to
> +		 * gaurantee QoS.
> +		 */
> +		if (state_sleep_ns < (qos * NSEC_PER_USEC))
> +			break;
> +	}
> +
> +	if (i >= 0)
> +		genpd->state_idx = i;
> +
> +	return  (i >= 0) ? true : false;
> +}
> +
> +static bool cpu_stop_ok(struct device *dev)
> +{
> +	return true;
> +}
> +
> +struct dev_power_governor cpu_pd_gov = {
> +	.power_down_ok = cpu_pd_down_ok,
> +	.stop_ok = cpu_stop_ok,
> +};
> +
>  static int cpu_pd_power_off(struct generic_pm_domain *genpd)
>  {
>  	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
> @@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
>  
>  	/* Register the CPU genpd */
>  	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
> -	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
> +	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
>  	if (ret) {
>  		pr_err("Unable to initialize domain %s\n", dn->full_name);
>  		return ret;
> -- 
> 2.1.4
> 

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-18 18:42     ` Lorenzo Pieralisi
@ 2015-11-19  8:50       ` Marc Titinger
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-11-19  8:50 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam

On 18/11/2015 19:42, Lorenzo Pieralisi wrote:
> On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>> A PM domain comprising of CPUs may be powered off when all the CPUs in
>> the domain are powered down. Powering down a CPU domain is generally a
>> expensive operation and therefore the power performance trade offs
>> should be considered. The time between the last CPU powering down and
>> the first CPU powering up in a domain, is the time available for the
>> domain to sleep. Ideally, the sleep time of the domain should fulfill
>> the residency requirement of the domains' idle state.
>>
>> To do this effectively, read the time before the wakeup of the cluster's
>> CPUs and ensure that the domain's idle state sleep time guarantees the
>> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>> state's residency.
>
> To me this information should be part of the CPUidle governor (it is
> already there), we should not split the decision into multiple layers.
>
> The problem you are facing is that the CPUidle governor(s) do not take
> cross cpus relationship into account, I do not think that adding another
> decision layer in the power domain subsystem helps, you are doing that
> just because adding it to the existing CPUidle governor(s) is invasive.
>
> Why can't we use the power domain work you put together to eg disable
> idle states that share multiple cpus and make them "visible" only
> when the power domain that encompass them is actually going down ?
>
> You could use the power domains information to detect states that
> are shared between cpus.
>
> It is just an idea, what I am saying is that having another governor in
> the power domain subsytem does not make much sense, you split the
> decision in two layers while there is actually one, the existing
> CPUidle governor and that's where the decision should be taken.
>
> Thoughts appreciated.

Maybe this is silly and not thought-through, but I wonder if the 
responsibilities could be split or instance with an outer control loop 
that has the heuristic to compute the next tick time, and the required 
cpu-power needed during that time slot, and an inner control loop 
(genpd) that has a per-domain QoS and can optimize power consumption.

Marc.

>
> Lorenzo
>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>   drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 82 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>> index 617ce54..a00abc1 100644
>> --- a/drivers/base/power/cpu-pd.c
>> +++ b/drivers/base/power/cpu-pd.c
>> @@ -21,6 +21,7 @@
>>   #include <linux/pm_qos.h>
>>   #include <linux/rculist.h>
>>   #include <linux/slab.h>
>> +#include <linux/tick.h>
>>
>>   #define CPU_PD_NAME_MAX 36
>>
>> @@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
>>   	}
>>   }
>>
>> +static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
>> +{
>> +	struct generic_pm_domain *genpd = pd_to_genpd(pd);
>> +	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
>> +	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>> +	u64 sleep_ns = ~0;
>> +	ktime_t earliest;
>> +	int cpu;
>> +	int i;
>> +
>> +	/* Reset the last set genpd state, default to index 0 */
>> +	genpd->state_idx = 0;
>> +
>> +	/* We dont want to power down, if QoS is 0 */
>> +	if (!qos)
>> +		return false;
>> +
>> +	/*
>> +	 * Find the sleep time for the cluster.
>> +	 * The time between now and the first wake up of any CPU that
>> +	 * are in this domain hierarchy is the time available for the
>> +	 * domain to be idle.
>> +	 */
>> +	earliest.tv64 = KTIME_MAX;
>> +	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
>> +		struct device *cpu_dev = get_cpu_device(cpu);
>> +		struct gpd_timing_data *td;
>> +
>> +		td = &dev_gpd_data(cpu_dev)->td;
>> +
>> +		if (earliest.tv64 < td->next_wakeup.tv64)
>> +			earliest = td->next_wakeup;
>> +	}
>> +
>> +	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
>> +	if (sleep_ns <= 0)
>> +		return false;
>> +
>> +	/*
>> +	 * Find the deepest sleep state that satisfies the residency
>> +	 * requirement and the QoS constraint
>> +	 */
>> +	for (i = genpd->state_count - 1; i > 0; i--) {
>> +		u64 state_sleep_ns;
>> +
>> +		state_sleep_ns = genpd->states[i].power_off_latency_ns +
>> +			genpd->states[i].power_on_latency_ns +
>> +			genpd->states[i].residency_ns;
>> +
>> +		/*
>> +		 * If we cant sleep to save power in the state, move on
>> +		 * to the next lower idle state.
>> +		 */
>> +		if (state_sleep_ns > sleep_ns)
>> +		       continue;
>> +
>> +		/*
>> +		 * We also dont want to sleep more than we should to
>> +		 * gaurantee QoS.
>> +		 */
>> +		if (state_sleep_ns < (qos * NSEC_PER_USEC))
>> +			break;
>> +	}
>> +
>> +	if (i >= 0)
>> +		genpd->state_idx = i;
>> +
>> +	return  (i >= 0) ? true : false;
>> +}
>> +
>> +static bool cpu_stop_ok(struct device *dev)
>> +{
>> +	return true;
>> +}
>> +
>> +struct dev_power_governor cpu_pd_gov = {
>> +	.power_down_ok = cpu_pd_down_ok,
>> +	.stop_ok = cpu_stop_ok,
>> +};
>> +
>>   static int cpu_pd_power_off(struct generic_pm_domain *genpd)
>>   {
>>   	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
>> @@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
>>
>>   	/* Register the CPU genpd */
>>   	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
>> -	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
>> +	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
>>   	if (ret) {
>>   		pr_err("Unable to initialize domain %s\n", dn->full_name);
>>   		return ret;
>> --
>> 2.1.4
>>

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-19  8:50       ` Marc Titinger
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-11-19  8:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 18/11/2015 19:42, Lorenzo Pieralisi wrote:
> On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>> A PM domain comprising of CPUs may be powered off when all the CPUs in
>> the domain are powered down. Powering down a CPU domain is generally a
>> expensive operation and therefore the power performance trade offs
>> should be considered. The time between the last CPU powering down and
>> the first CPU powering up in a domain, is the time available for the
>> domain to sleep. Ideally, the sleep time of the domain should fulfill
>> the residency requirement of the domains' idle state.
>>
>> To do this effectively, read the time before the wakeup of the cluster's
>> CPUs and ensure that the domain's idle state sleep time guarantees the
>> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>> state's residency.
>
> To me this information should be part of the CPUidle governor (it is
> already there), we should not split the decision into multiple layers.
>
> The problem you are facing is that the CPUidle governor(s) do not take
> cross cpus relationship into account, I do not think that adding another
> decision layer in the power domain subsystem helps, you are doing that
> just because adding it to the existing CPUidle governor(s) is invasive.
>
> Why can't we use the power domain work you put together to eg disable
> idle states that share multiple cpus and make them "visible" only
> when the power domain that encompass them is actually going down ?
>
> You could use the power domains information to detect states that
> are shared between cpus.
>
> It is just an idea, what I am saying is that having another governor in
> the power domain subsytem does not make much sense, you split the
> decision in two layers while there is actually one, the existing
> CPUidle governor and that's where the decision should be taken.
>
> Thoughts appreciated.

Maybe this is silly and not thought-through, but I wonder if the 
responsibilities could be split or instance with an outer control loop 
that has the heuristic to compute the next tick time, and the required 
cpu-power needed during that time slot, and an inner control loop 
(genpd) that has a per-domain QoS and can optimize power consumption.

Marc.

>
> Lorenzo
>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>   drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 82 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>> index 617ce54..a00abc1 100644
>> --- a/drivers/base/power/cpu-pd.c
>> +++ b/drivers/base/power/cpu-pd.c
>> @@ -21,6 +21,7 @@
>>   #include <linux/pm_qos.h>
>>   #include <linux/rculist.h>
>>   #include <linux/slab.h>
>> +#include <linux/tick.h>
>>
>>   #define CPU_PD_NAME_MAX 36
>>
>> @@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
>>   	}
>>   }
>>
>> +static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
>> +{
>> +	struct generic_pm_domain *genpd = pd_to_genpd(pd);
>> +	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
>> +	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>> +	u64 sleep_ns = ~0;
>> +	ktime_t earliest;
>> +	int cpu;
>> +	int i;
>> +
>> +	/* Reset the last set genpd state, default to index 0 */
>> +	genpd->state_idx = 0;
>> +
>> +	/* We dont want to power down, if QoS is 0 */
>> +	if (!qos)
>> +		return false;
>> +
>> +	/*
>> +	 * Find the sleep time for the cluster.
>> +	 * The time between now and the first wake up of any CPU that
>> +	 * are in this domain hierarchy is the time available for the
>> +	 * domain to be idle.
>> +	 */
>> +	earliest.tv64 = KTIME_MAX;
>> +	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
>> +		struct device *cpu_dev = get_cpu_device(cpu);
>> +		struct gpd_timing_data *td;
>> +
>> +		td = &dev_gpd_data(cpu_dev)->td;
>> +
>> +		if (earliest.tv64 < td->next_wakeup.tv64)
>> +			earliest = td->next_wakeup;
>> +	}
>> +
>> +	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
>> +	if (sleep_ns <= 0)
>> +		return false;
>> +
>> +	/*
>> +	 * Find the deepest sleep state that satisfies the residency
>> +	 * requirement and the QoS constraint
>> +	 */
>> +	for (i = genpd->state_count - 1; i > 0; i--) {
>> +		u64 state_sleep_ns;
>> +
>> +		state_sleep_ns = genpd->states[i].power_off_latency_ns +
>> +			genpd->states[i].power_on_latency_ns +
>> +			genpd->states[i].residency_ns;
>> +
>> +		/*
>> +		 * If we cant sleep to save power in the state, move on
>> +		 * to the next lower idle state.
>> +		 */
>> +		if (state_sleep_ns > sleep_ns)
>> +		       continue;
>> +
>> +		/*
>> +		 * We also dont want to sleep more than we should to
>> +		 * gaurantee QoS.
>> +		 */
>> +		if (state_sleep_ns < (qos * NSEC_PER_USEC))
>> +			break;
>> +	}
>> +
>> +	if (i >= 0)
>> +		genpd->state_idx = i;
>> +
>> +	return  (i >= 0) ? true : false;
>> +}
>> +
>> +static bool cpu_stop_ok(struct device *dev)
>> +{
>> +	return true;
>> +}
>> +
>> +struct dev_power_governor cpu_pd_gov = {
>> +	.power_down_ok = cpu_pd_down_ok,
>> +	.stop_ok = cpu_stop_ok,
>> +};
>> +
>>   static int cpu_pd_power_off(struct generic_pm_domain *genpd)
>>   {
>>   	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
>> @@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
>>
>>   	/* Register the CPU genpd */
>>   	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
>> -	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
>> +	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
>>   	if (ret) {
>>   		pr_err("Unable to initialize domain %s\n", dn->full_name);
>>   		return ret;
>> --
>> 2.1.4
>>

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

* Re: [PATCH RFC 25/27] devicetree: bindings: Document qcom,msm-id and qcom,board-id
  2015-11-17 22:37   ` [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom, board-id Lina Iyer
@ 2015-11-19 14:36     ` Rob Herring
  -1 siblings, 0 replies; 166+ messages in thread
From: Rob Herring @ 2015-11-19 14:36 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Ulf Hansson, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	ahaslam, mtitinger, Kumar Gala, devicetree

On Tue, Nov 17, 2015 at 4:37 PM, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Kumar Gala <galak@codeaurora.org>
>
> The top level qcom,msm-id and qcom,board-id are utilized by bootloaders
> on Qualcomm MSM platforms to determine which device tree should be
> utilized and passed to the kernel.

See [1] and the link there to the prior version which is like this one.

Rob

[1] https://lkml.org/lkml/2015/10/26/651

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

* [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom, board-id
@ 2015-11-19 14:36     ` Rob Herring
  0 siblings, 0 replies; 166+ messages in thread
From: Rob Herring @ 2015-11-19 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 17, 2015 at 4:37 PM, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Kumar Gala <galak@codeaurora.org>
>
> The top level qcom,msm-id and qcom,board-id are utilized by bootloaders
> on Qualcomm MSM platforms to determine which device tree should be
> utilized and passed to the kernel.

See [1] and the link there to the prior version which is like this one.

Rob

[1] https://lkml.org/lkml/2015/10/26/651

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

* Re: [PATCH RFC 25/27] devicetree: bindings: Document qcom,msm-id and qcom,board-id
  2015-11-19 14:36     ` [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom, board-id Rob Herring
@ 2015-11-19 15:36       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-19 15:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: Ulf Hansson, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	ahaslam, mtitinger, Kumar Gala, devicetree

On Thu, Nov 19 2015 at 07:37 -0700, Rob Herring wrote:
>On Tue, Nov 17, 2015 at 4:37 PM, Lina Iyer <lina.iyer@linaro.org> wrote:
>> From: Kumar Gala <galak@codeaurora.org>
>>
>> The top level qcom,msm-id and qcom,board-id are utilized by bootloaders
>> on Qualcomm MSM platforms to determine which device tree should be
>> utilized and passed to the kernel.
>
>See [1] and the link there to the prior version which is like this one.
>
Thanks Rob. Andy Gross sent me that link and I am waiting on the changes
along with the dtb tool to make it. These patches will go away after
Stephen's changes. I just put it in here for completeness.

Thanks,
Lina

>[1] https://lkml.org/lkml/2015/10/26/651

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

* [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom,board-id
@ 2015-11-19 15:36       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-19 15:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 19 2015 at 07:37 -0700, Rob Herring wrote:
>On Tue, Nov 17, 2015 at 4:37 PM, Lina Iyer <lina.iyer@linaro.org> wrote:
>> From: Kumar Gala <galak@codeaurora.org>
>>
>> The top level qcom,msm-id and qcom,board-id are utilized by bootloaders
>> on Qualcomm MSM platforms to determine which device tree should be
>> utilized and passed to the kernel.
>
>See [1] and the link there to the prior version which is like this one.
>
Thanks Rob. Andy Gross sent me that link and I am waiting on the changes
along with the dtb tool to make it. These patches will go away after
Stephen's changes. I just put it in here for completeness.

Thanks,
Lina

>[1] https://lkml.org/lkml/2015/10/26/651

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

* Re: [PATCH RFC 03/27] PM / Domain: Add additional state specific param
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-19 21:33     ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 21:33 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

Lina Iyer <lina.iyer@linaro.org> writes:

> Allow domain states to hold additional state related data in a u32
> value. This may be used by the platform driver.

Should probably expand the changelog here to give some examples how how
this might be used by the platform driver.

Kevin

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

* [PATCH RFC 03/27] PM / Domain: Add additional state specific param
@ 2015-11-19 21:33     ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 21:33 UTC (permalink / raw)
  To: linux-arm-kernel

Lina Iyer <lina.iyer@linaro.org> writes:

> Allow domain states to hold additional state related data in a u32
> value. This may be used by the platform driver.

Should probably expand the changelog here to give some examples how how
this might be used by the platform driver.

Kevin

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

* Re: [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-19 22:10     ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 22:10 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger, Daniel Lezcano

Lina Iyer <lina.iyer@linaro.org> writes:

> Notify runtime PM when the CPU is going to be powered off in the idle
> state. This allows for runtime PM suspend/resume of the CPU as well as
> its PM domain.
>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
> index 545069d..8e72a23 100644
> --- a/drivers/cpuidle/cpuidle-arm.c
> +++ b/drivers/cpuidle/cpuidle-arm.c
> @@ -11,13 +11,16 @@
>  
>  #define pr_fmt(fmt) "CPUidle arm: " fmt
>  
> +#include <linux/cpu.h>
>  #include <linux/cpuidle.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/slab.h>
> +#include <linux/rcupdate.h>
>  
>  #include <asm/cpuidle.h>
>  
> @@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>  
>  	ret = cpu_pm_enter();
>  	if (!ret) {
> +		struct device *cpu_dev = get_cpu_device(dev->cpu);
> +
> +		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
> +

A comment in the changelog about the use of _put_sync_suspend() instead
of a normal _put_sync() would be helpful for this patch.

Kevin

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

* [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle
@ 2015-11-19 22:10     ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 22:10 UTC (permalink / raw)
  To: linux-arm-kernel

Lina Iyer <lina.iyer@linaro.org> writes:

> Notify runtime PM when the CPU is going to be powered off in the idle
> state. This allows for runtime PM suspend/resume of the CPU as well as
> its PM domain.
>
> Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/cpuidle/cpuidle-arm.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
> index 545069d..8e72a23 100644
> --- a/drivers/cpuidle/cpuidle-arm.c
> +++ b/drivers/cpuidle/cpuidle-arm.c
> @@ -11,13 +11,16 @@
>  
>  #define pr_fmt(fmt) "CPUidle arm: " fmt
>  
> +#include <linux/cpu.h>
>  #include <linux/cpuidle.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/slab.h>
> +#include <linux/rcupdate.h>
>  
>  #include <asm/cpuidle.h>
>  
> @@ -45,6 +48,10 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>  
>  	ret = cpu_pm_enter();
>  	if (!ret) {
> +		struct device *cpu_dev = get_cpu_device(dev->cpu);
> +
> +		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
> +

A comment in the changelog about the use of _put_sync_suspend() instead
of a normal _put_sync() would be helpful for this patch.

Kevin

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

* Re: [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-19 22:19     ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 22:19 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

Lina Iyer <lina.iyer@linaro.org> writes:

> Allow devices that know when their next wakeup event is, to record save
> it as part of timing data. A genpd governor may use this data to
> determine if suspending the domain is going to affect the QoS of its
> devices.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  include/linux/pm_domain.h | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index f1329ea..9ac089d 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -16,6 +16,7 @@
>  #include <linux/of.h>
>  #include <linux/notifier.h>
>  #include <linux/spinlock.h>
> +#include <linux/ktime.h>
>  
>  /* Defines used for the flags field in the struct generic_pm_domain */
>  #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
> @@ -104,6 +105,7 @@ struct gpd_timing_data {
>  	s64 effective_constraint_ns;
>  	bool constraint_changed;
>  	bool cached_stop_ok;
> +	ktime_t next_wakeup;
>  };

The addition of a new field should be combined with the patch that uses
it (e.g. PATCH 16/27)

Kevin

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

* [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data
@ 2015-11-19 22:19     ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 22:19 UTC (permalink / raw)
  To: linux-arm-kernel

Lina Iyer <lina.iyer@linaro.org> writes:

> Allow devices that know when their next wakeup event is, to record save
> it as part of timing data. A genpd governor may use this data to
> determine if suspending the domain is going to affect the QoS of its
> devices.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  include/linux/pm_domain.h | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index f1329ea..9ac089d 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -16,6 +16,7 @@
>  #include <linux/of.h>
>  #include <linux/notifier.h>
>  #include <linux/spinlock.h>
> +#include <linux/ktime.h>
>  
>  /* Defines used for the flags field in the struct generic_pm_domain */
>  #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
> @@ -104,6 +105,7 @@ struct gpd_timing_data {
>  	s64 effective_constraint_ns;
>  	bool constraint_changed;
>  	bool cached_stop_ok;
> +	ktime_t next_wakeup;
>  };

The addition of a new field should be combined with the patch that uses
it (e.g. PATCH 16/27)

Kevin

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

* Re: [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-19 23:35     ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 23:35 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

Lina Iyer <lina.iyer@linaro.org> writes:

> Reading the next wakeup of the CPU can only be realiably done only from
> that CPU. In the idle enter path record the next wake up of the CPU. The
> information is useful to determine the sleep time left for the CPU.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/cpuidle/cpuidle-arm.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
> index 8e72a23..b3133ef 100644
> --- a/drivers/cpuidle/cpuidle-arm.c
> +++ b/drivers/cpuidle/cpuidle-arm.c
> @@ -18,9 +18,11 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_domain.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/slab.h>
>  #include <linux/rcupdate.h>
> +#include <linux/tick.h>
>  
>  #include <asm/cpuidle.h>
>  
> @@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>  	ret = cpu_pm_enter();
>  	if (!ret) {
>  		struct device *cpu_dev = get_cpu_device(dev->cpu);
> +		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
>  
> +		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
>  		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));

Maybe set this back to zero atomicaly, after wakeup?

Checking for non-zero that might be another way for the domain goveror that there
haven't been any CPU wakeups since the CPUs have gone idle.

Kevin

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

* [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
@ 2015-11-19 23:35     ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 23:35 UTC (permalink / raw)
  To: linux-arm-kernel

Lina Iyer <lina.iyer@linaro.org> writes:

> Reading the next wakeup of the CPU can only be realiably done only from
> that CPU. In the idle enter path record the next wake up of the CPU. The
> information is useful to determine the sleep time left for the CPU.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/cpuidle/cpuidle-arm.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
> index 8e72a23..b3133ef 100644
> --- a/drivers/cpuidle/cpuidle-arm.c
> +++ b/drivers/cpuidle/cpuidle-arm.c
> @@ -18,9 +18,11 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_domain.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/slab.h>
>  #include <linux/rcupdate.h>
> +#include <linux/tick.h>
>  
>  #include <asm/cpuidle.h>
>  
> @@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>  	ret = cpu_pm_enter();
>  	if (!ret) {
>  		struct device *cpu_dev = get_cpu_device(dev->cpu);
> +		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
>  
> +		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
>  		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));

Maybe set this back to zero atomicaly, after wakeup?

Checking for non-zero that might be another way for the domain goveror that there
haven't been any CPU wakeups since the CPUs have gone idle.

Kevin

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-18 18:42     ` Lorenzo Pieralisi
@ 2015-11-19 23:52       ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 23:52 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: Lina Iyer, ulf.hansson, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger

Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:

> On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>> A PM domain comprising of CPUs may be powered off when all the CPUs in
>> the domain are powered down. Powering down a CPU domain is generally a
>> expensive operation and therefore the power performance trade offs
>> should be considered. The time between the last CPU powering down and
>> the first CPU powering up in a domain, is the time available for the
>> domain to sleep. Ideally, the sleep time of the domain should fulfill
>> the residency requirement of the domains' idle state.
>> 
>> To do this effectively, read the time before the wakeup of the cluster's
>> CPUs and ensure that the domain's idle state sleep time guarantees the
>> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>> state's residency.
>
> To me this information should be part of the CPUidle governor (it is
> already there), we should not split the decision into multiple layers.
>
> The problem you are facing is that the CPUidle governor(s) do not take
> cross cpus relationship into account, I do not think that adding another
> decision layer in the power domain subsystem helps, you are doing that
> just because adding it to the existing CPUidle governor(s) is invasive.
>
> Why can't we use the power domain work you put together to eg disable
> idle states that share multiple cpus and make them "visible" only
> when the power domain that encompass them is actually going down ?
>
> You could use the power domains information to detect states that
> are shared between cpus.
>
> It is just an idea, what I am saying is that having another governor in
> the power domain subsytem does not make much sense, you split the
> decision in two layers while there is actually one, the existing
> CPUidle governor and that's where the decision should be taken.

Hmm, considering "normal" devices in "normal" power domains, and
following the same logic, the equivalent would be to say that the
decision to gate the power domain belongs to the individual drivers
in the domain instead of in the power domain layer.  I disagree.

IMO, there are different decision layers because there are different
hardware layers.  Devices (including CPUs) are reponsible for handling
device-local idle states, based on device-local conditions (e.g. local
wakeups, timers, etc.)  and domains are responsible for handling
decisions based on conditions of the whole domain.

Kevin

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-19 23:52       ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-19 23:52 UTC (permalink / raw)
  To: linux-arm-kernel

Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:

> On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>> A PM domain comprising of CPUs may be powered off when all the CPUs in
>> the domain are powered down. Powering down a CPU domain is generally a
>> expensive operation and therefore the power performance trade offs
>> should be considered. The time between the last CPU powering down and
>> the first CPU powering up in a domain, is the time available for the
>> domain to sleep. Ideally, the sleep time of the domain should fulfill
>> the residency requirement of the domains' idle state.
>> 
>> To do this effectively, read the time before the wakeup of the cluster's
>> CPUs and ensure that the domain's idle state sleep time guarantees the
>> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>> state's residency.
>
> To me this information should be part of the CPUidle governor (it is
> already there), we should not split the decision into multiple layers.
>
> The problem you are facing is that the CPUidle governor(s) do not take
> cross cpus relationship into account, I do not think that adding another
> decision layer in the power domain subsystem helps, you are doing that
> just because adding it to the existing CPUidle governor(s) is invasive.
>
> Why can't we use the power domain work you put together to eg disable
> idle states that share multiple cpus and make them "visible" only
> when the power domain that encompass them is actually going down ?
>
> You could use the power domains information to detect states that
> are shared between cpus.
>
> It is just an idea, what I am saying is that having another governor in
> the power domain subsytem does not make much sense, you split the
> decision in two layers while there is actually one, the existing
> CPUidle governor and that's where the decision should be taken.

Hmm, considering "normal" devices in "normal" power domains, and
following the same logic, the equivalent would be to say that the
decision to gate the power domain belongs to the individual drivers
in the domain instead of in the power domain layer.  I disagree.

IMO, there are different decision layers because there are different
hardware layers.  Devices (including CPUs) are reponsible for handling
device-local idle states, based on device-local conditions (e.g. local
wakeups, timers, etc.)  and domains are responsible for handling
decisions based on conditions of the whole domain.

Kevin

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-20  0:03     ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-20  0:03 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

Lina Iyer <lina.iyer@linaro.org> writes:

> A PM domain comprising of CPUs may be powered off when all the CPUs in
> the domain are powered down. Powering down a CPU domain is generally a
> expensive operation and therefore the power performance trade offs
> should be considered. The time between the last CPU powering down and
> the first CPU powering up in a domain, is the time available for the
> domain to sleep. Ideally, the sleep time of the domain should fulfill
> the residency requirement of the domains' idle state.
>
> To do this effectively, read the time before the wakeup of the cluster's
> CPUs and ensure that the domain's idle state sleep time guarantees the
> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
> state's residency.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>

[...]

> +static bool cpu_stop_ok(struct device *dev)
> +{
> +	return true;
> +}
> +
> +struct dev_power_governor cpu_pd_gov = {
> +	.power_down_ok = cpu_pd_down_ok,
> +	.stop_ok = cpu_stop_ok,
> +};

If stop_ok is unconditionally true, it should probably just be removed
(IOW cpu_pd_gov->stop_ok == NULL), and that will avoid an unnecessary
function call.

Kevin

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-20  0:03     ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-20  0:03 UTC (permalink / raw)
  To: linux-arm-kernel

Lina Iyer <lina.iyer@linaro.org> writes:

> A PM domain comprising of CPUs may be powered off when all the CPUs in
> the domain are powered down. Powering down a CPU domain is generally a
> expensive operation and therefore the power performance trade offs
> should be considered. The time between the last CPU powering down and
> the first CPU powering up in a domain, is the time available for the
> domain to sleep. Ideally, the sleep time of the domain should fulfill
> the residency requirement of the domains' idle state.
>
> To do this effectively, read the time before the wakeup of the cluster's
> CPUs and ensure that the domain's idle state sleep time guarantees the
> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
> state's residency.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>

[...]

> +static bool cpu_stop_ok(struct device *dev)
> +{
> +	return true;
> +}
> +
> +struct dev_power_governor cpu_pd_gov = {
> +	.power_down_ok = cpu_pd_down_ok,
> +	.stop_ok = cpu_stop_ok,
> +};

If stop_ok is unconditionally true, it should probably just be removed
(IOW cpu_pd_gov->stop_ok == NULL), and that will avoid an unnecessary
function call.

Kevin

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

* Re: [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data
  2015-11-19 22:19     ` Kevin Hilman
@ 2015-11-20 15:58       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 15:58 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On Thu, Nov 19 2015 at 15:19 -0700, Kevin Hilman wrote:
>Lina Iyer <lina.iyer@linaro.org> writes:
>
>> Allow devices that know when their next wakeup event is, to record save
>> it as part of timing data. A genpd governor may use this data to
>> determine if suspending the domain is going to affect the QoS of its
>> devices.
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  include/linux/pm_domain.h | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index f1329ea..9ac089d 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -16,6 +16,7 @@
>>  #include <linux/of.h>
>>  #include <linux/notifier.h>
>>  #include <linux/spinlock.h>
>> +#include <linux/ktime.h>
>>
>>  /* Defines used for the flags field in the struct generic_pm_domain */
>>  #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
>> @@ -104,6 +105,7 @@ struct gpd_timing_data {
>>  	s64 effective_constraint_ns;
>>  	bool constraint_changed;
>>  	bool cached_stop_ok;
>> +	ktime_t next_wakeup;
>>  };
>
>The addition of a new field should be combined with the patch that uses
>it (e.g. PATCH 16/27)
>
Okay. Will do.

>Kevin

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

* [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data
@ 2015-11-20 15:58       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 19 2015 at 15:19 -0700, Kevin Hilman wrote:
>Lina Iyer <lina.iyer@linaro.org> writes:
>
>> Allow devices that know when their next wakeup event is, to record save
>> it as part of timing data. A genpd governor may use this data to
>> determine if suspending the domain is going to affect the QoS of its
>> devices.
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  include/linux/pm_domain.h | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index f1329ea..9ac089d 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -16,6 +16,7 @@
>>  #include <linux/of.h>
>>  #include <linux/notifier.h>
>>  #include <linux/spinlock.h>
>> +#include <linux/ktime.h>
>>
>>  /* Defines used for the flags field in the struct generic_pm_domain */
>>  #define GENPD_FLAG_PM_CLK	(1U << 0) /* PM domain uses PM clk */
>> @@ -104,6 +105,7 @@ struct gpd_timing_data {
>>  	s64 effective_constraint_ns;
>>  	bool constraint_changed;
>>  	bool cached_stop_ok;
>> +	ktime_t next_wakeup;
>>  };
>
>The addition of a new field should be combined with the patch that uses
>it (e.g. PATCH 16/27)
>
Okay. Will do.

>Kevin

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-19 23:52       ` Kevin Hilman
@ 2015-11-20 16:21         ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-11-20 16:21 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Lina Iyer, ulf.hansson, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger

On Thu, Nov 19, 2015 at 03:52:13PM -0800, Kevin Hilman wrote:
> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
> 
> > On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
> >> A PM domain comprising of CPUs may be powered off when all the CPUs in
> >> the domain are powered down. Powering down a CPU domain is generally a
> >> expensive operation and therefore the power performance trade offs
> >> should be considered. The time between the last CPU powering down and
> >> the first CPU powering up in a domain, is the time available for the
> >> domain to sleep. Ideally, the sleep time of the domain should fulfill
> >> the residency requirement of the domains' idle state.
> >> 
> >> To do this effectively, read the time before the wakeup of the cluster's
> >> CPUs and ensure that the domain's idle state sleep time guarantees the
> >> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
> >> state's residency.
> >
> > To me this information should be part of the CPUidle governor (it is
> > already there), we should not split the decision into multiple layers.
> >
> > The problem you are facing is that the CPUidle governor(s) do not take
> > cross cpus relationship into account, I do not think that adding another
> > decision layer in the power domain subsystem helps, you are doing that
> > just because adding it to the existing CPUidle governor(s) is invasive.
> >
> > Why can't we use the power domain work you put together to eg disable
> > idle states that share multiple cpus and make them "visible" only
> > when the power domain that encompass them is actually going down ?
> >
> > You could use the power domains information to detect states that
> > are shared between cpus.
> >
> > It is just an idea, what I am saying is that having another governor in
> > the power domain subsytem does not make much sense, you split the
> > decision in two layers while there is actually one, the existing
> > CPUidle governor and that's where the decision should be taken.
> 
> Hmm, considering "normal" devices in "normal" power domains, and
> following the same logic, the equivalent would be to say that the
> decision to gate the power domain belongs to the individual drivers
> in the domain instead of in the power domain layer.  I disagree.
> 
> IMO, there are different decision layers because there are different
> hardware layers.  Devices (including CPUs) are reponsible for handling
> device-local idle states, based on device-local conditions (e.g. local
> wakeups, timers, etc.)  and domains are responsible for handling
> decisions based on conditions of the whole domain.

After going through the series for the second time (it is quite complex and
should probably be split) I understood your point of view and I agree with
it, I will review it more in-depth to understand the details.

One thing that is not clear to me is how we would end up handling
cluster states in platform coordinated mode with this series (and
I am actually referring to the data we would add in the idle-states,
such as min-residency). I admit that data for cluster states at present
is not extremely well defined, because we have to add latencies for
the cluster state even if the state itself may be just a cpu one (by
definition a cluster state is entered only if all cpus in the cluster
enter it, otherwise FW or power controller demote them automatically).

I would like to take this series as an opportunity to improve the
current situation in a clean way (and without changing the bindings,
only augmenting them).

On a side note, I think we should give up the concept of cluster
entirely, to me they are just a group of cpus, I do not see any reason
why we should group cpus this way and I do not like the dependencies
of this series on the cpu-map either, I do not see the reason but I
will go through code again to make sure I am not missing anything.

To be clear, to me the cpumask should be created with all cpus belonging
in a given power domain, no cluster dependency (and yes the CPU PM
notifiers are not appropriate at present - eg on
cpu_cluster_pm_{enter/exit} we save and restore the GIC distributor state
even on multi-cluster systems, that's useless and has no connection with
the real power domain topology at all, so the concept of cluster as it
stands is shaky to say the least).

Thanks,
Lorenzo

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-20 16:21         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-11-20 16:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 19, 2015 at 03:52:13PM -0800, Kevin Hilman wrote:
> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
> 
> > On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
> >> A PM domain comprising of CPUs may be powered off when all the CPUs in
> >> the domain are powered down. Powering down a CPU domain is generally a
> >> expensive operation and therefore the power performance trade offs
> >> should be considered. The time between the last CPU powering down and
> >> the first CPU powering up in a domain, is the time available for the
> >> domain to sleep. Ideally, the sleep time of the domain should fulfill
> >> the residency requirement of the domains' idle state.
> >> 
> >> To do this effectively, read the time before the wakeup of the cluster's
> >> CPUs and ensure that the domain's idle state sleep time guarantees the
> >> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
> >> state's residency.
> >
> > To me this information should be part of the CPUidle governor (it is
> > already there), we should not split the decision into multiple layers.
> >
> > The problem you are facing is that the CPUidle governor(s) do not take
> > cross cpus relationship into account, I do not think that adding another
> > decision layer in the power domain subsystem helps, you are doing that
> > just because adding it to the existing CPUidle governor(s) is invasive.
> >
> > Why can't we use the power domain work you put together to eg disable
> > idle states that share multiple cpus and make them "visible" only
> > when the power domain that encompass them is actually going down ?
> >
> > You could use the power domains information to detect states that
> > are shared between cpus.
> >
> > It is just an idea, what I am saying is that having another governor in
> > the power domain subsytem does not make much sense, you split the
> > decision in two layers while there is actually one, the existing
> > CPUidle governor and that's where the decision should be taken.
> 
> Hmm, considering "normal" devices in "normal" power domains, and
> following the same logic, the equivalent would be to say that the
> decision to gate the power domain belongs to the individual drivers
> in the domain instead of in the power domain layer.  I disagree.
> 
> IMO, there are different decision layers because there are different
> hardware layers.  Devices (including CPUs) are reponsible for handling
> device-local idle states, based on device-local conditions (e.g. local
> wakeups, timers, etc.)  and domains are responsible for handling
> decisions based on conditions of the whole domain.

After going through the series for the second time (it is quite complex and
should probably be split) I understood your point of view and I agree with
it, I will review it more in-depth to understand the details.

One thing that is not clear to me is how we would end up handling
cluster states in platform coordinated mode with this series (and
I am actually referring to the data we would add in the idle-states,
such as min-residency). I admit that data for cluster states at present
is not extremely well defined, because we have to add latencies for
the cluster state even if the state itself may be just a cpu one (by
definition a cluster state is entered only if all cpus in the cluster
enter it, otherwise FW or power controller demote them automatically).

I would like to take this series as an opportunity to improve the
current situation in a clean way (and without changing the bindings,
only augmenting them).

On a side note, I think we should give up the concept of cluster
entirely, to me they are just a group of cpus, I do not see any reason
why we should group cpus this way and I do not like the dependencies
of this series on the cpu-map either, I do not see the reason but I
will go through code again to make sure I am not missing anything.

To be clear, to me the cpumask should be created with all cpus belonging
in a given power domain, no cluster dependency (and yes the CPU PM
notifiers are not appropriate at present - eg on
cpu_cluster_pm_{enter/exit} we save and restore the GIC distributor state
even on multi-cluster systems, that's useless and has no connection with
the real power domain topology at all, so the concept of cluster as it
stands is shaky to say the least).

Thanks,
Lorenzo

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

* Re: [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
  2015-11-19 23:35     ` Kevin Hilman
@ 2015-11-20 16:28       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 16:28 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On Thu, Nov 19 2015 at 16:35 -0700, Kevin Hilman wrote:
>Lina Iyer <lina.iyer@linaro.org> writes:
>
>> Reading the next wakeup of the CPU can only be realiably done only from
>> that CPU. In the idle enter path record the next wake up of the CPU. The
>> information is useful to determine the sleep time left for the CPU.
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/cpuidle/cpuidle-arm.c | 5 +++++
>>  1 file changed, 5 insertions(+)
>>
>> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
>> index 8e72a23..b3133ef 100644
>> --- a/drivers/cpuidle/cpuidle-arm.c
>> +++ b/drivers/cpuidle/cpuidle-arm.c
>> @@ -18,9 +18,11 @@
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_domain.h>
>>  #include <linux/pm_runtime.h>
>>  #include <linux/slab.h>
>>  #include <linux/rcupdate.h>
>> +#include <linux/tick.h>
>>
>>  #include <asm/cpuidle.h>
>>
>> @@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>  	ret = cpu_pm_enter();
>>  	if (!ret) {
>>  		struct device *cpu_dev = get_cpu_device(dev->cpu);
>> +		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
>>
>> +		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
>>  		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
>
>Maybe set this back to zero atomicaly, after wakeup?
>
>Checking for non-zero that might be another way for the domain goveror that there
>haven't been any CPU wakeups since the CPUs have gone idle.
>
I set it to 0 below.

The reference counting by the GET_PUT tells the domain if a device is
suspended. I see that as a redudant information. May be I am not getting
your point.

-- Lina
>Kevin

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

* [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
@ 2015-11-20 16:28       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 16:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 19 2015 at 16:35 -0700, Kevin Hilman wrote:
>Lina Iyer <lina.iyer@linaro.org> writes:
>
>> Reading the next wakeup of the CPU can only be realiably done only from
>> that CPU. In the idle enter path record the next wake up of the CPU. The
>> information is useful to determine the sleep time left for the CPU.
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/cpuidle/cpuidle-arm.c | 5 +++++
>>  1 file changed, 5 insertions(+)
>>
>> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
>> index 8e72a23..b3133ef 100644
>> --- a/drivers/cpuidle/cpuidle-arm.c
>> +++ b/drivers/cpuidle/cpuidle-arm.c
>> @@ -18,9 +18,11 @@
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_domain.h>
>>  #include <linux/pm_runtime.h>
>>  #include <linux/slab.h>
>>  #include <linux/rcupdate.h>
>> +#include <linux/tick.h>
>>
>>  #include <asm/cpuidle.h>
>>
>> @@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>  	ret = cpu_pm_enter();
>>  	if (!ret) {
>>  		struct device *cpu_dev = get_cpu_device(dev->cpu);
>> +		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
>>
>> +		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
>>  		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
>
>Maybe set this back to zero atomicaly, after wakeup?
>
>Checking for non-zero that might be another way for the domain goveror that there
>haven't been any CPU wakeups since the CPUs have gone idle.
>
I set it to 0 below.

The reference counting by the GET_PUT tells the domain if a device is
suspended. I see that as a redudant information. May be I am not getting
your point.

-- Lina
>Kevin

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-20 16:21         ` Lorenzo Pieralisi
@ 2015-11-20 16:42           ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 16:42 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: Kevin Hilman, ulf.hansson, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger

On Fri, Nov 20 2015 at 09:20 -0700, Lorenzo Pieralisi wrote:
>On Thu, Nov 19, 2015 at 03:52:13PM -0800, Kevin Hilman wrote:
>> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
>>
>> > On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>> >> A PM domain comprising of CPUs may be powered off when all the CPUs in
>> >> the domain are powered down. Powering down a CPU domain is generally a
>> >> expensive operation and therefore the power performance trade offs
>> >> should be considered. The time between the last CPU powering down and
>> >> the first CPU powering up in a domain, is the time available for the
>> >> domain to sleep. Ideally, the sleep time of the domain should fulfill
>> >> the residency requirement of the domains' idle state.
>> >>
>> >> To do this effectively, read the time before the wakeup of the cluster's
>> >> CPUs and ensure that the domain's idle state sleep time guarantees the
>> >> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>> >> state's residency.
>> >
>> > To me this information should be part of the CPUidle governor (it is
>> > already there), we should not split the decision into multiple layers.
>> >
>> > The problem you are facing is that the CPUidle governor(s) do not take
>> > cross cpus relationship into account, I do not think that adding another
>> > decision layer in the power domain subsystem helps, you are doing that
>> > just because adding it to the existing CPUidle governor(s) is invasive.
>> >
>> > Why can't we use the power domain work you put together to eg disable
>> > idle states that share multiple cpus and make them "visible" only
>> > when the power domain that encompass them is actually going down ?
>> >
>> > You could use the power domains information to detect states that
>> > are shared between cpus.
>> >
>> > It is just an idea, what I am saying is that having another governor in
>> > the power domain subsytem does not make much sense, you split the
>> > decision in two layers while there is actually one, the existing
>> > CPUidle governor and that's where the decision should be taken.
>>
>> Hmm, considering "normal" devices in "normal" power domains, and
>> following the same logic, the equivalent would be to say that the
>> decision to gate the power domain belongs to the individual drivers
>> in the domain instead of in the power domain layer.  I disagree.
>>
>> IMO, there are different decision layers because there are different
>> hardware layers.  Devices (including CPUs) are reponsible for handling
>> device-local idle states, based on device-local conditions (e.g. local
>> wakeups, timers, etc.)  and domains are responsible for handling
>> decisions based on conditions of the whole domain.
>
>After going through the series for the second time (it is quite complex and
>should probably be split) I understood your point of view and I agree with
>it, I will review it more in-depth to understand the details.
>
I have included patches from Axel and Marc, so as to get a complete
picture. My core changes are in genpd, cpu-pd and psci.c

>One thing that is not clear to me is how we would end up handling
>cluster states in platform coordinated mode with this series (and
>I am actually referring to the data we would add in the idle-states,
>such as min-residency).
>
>From what I see, the platform coordinated mode, doesnt need any of this.
We are fine as it is today. CPUs vote for the cluster state they can
enter and the f/w determines based on these votes. It makes sense and
probably easier to flatten out the cluster states and attach them to
cpuidle for that.

I couldnt find a symmetry with OS initated. May be it deserves more
discussion and brain storming.

>I admit that data for cluster states at present
>is not extremely well defined, because we have to add latencies for
>the cluster state even if the state itself may be just a cpu one (by
>definition a cluster state is entered only if all cpus in the cluster
>enter it, otherwise FW or power controller demote them automatically).
>

>I would like to take this series as an opportunity to improve the
>current situation in a clean way (and without changing the bindings,
>only augmenting them).
>
>On a side note, I think we should give up the concept of cluster
>entirely, to me they are just a group of cpus, I do not see any reason
>why we should group cpus this way and I do not like the dependencies
>of this series on the cpu-map either, I do not see the reason but I
>will go through code again to make sure I am not missing anything.
>
SoC's could have different organization of CPUs (clubbed as clusters)
and power domains the power thesee clusters. This information has to
come from the DT. Since there are no actual devices in linux for domain
management (with PSCI), I have added them to cpu-map, which already
builds up the cluster hierarchy. The only addition I had to make wa
allow these cluster nodes to be tell the kernel that they are domain
providers.

>To be clear, to me the cpumask should be created with all cpus belonging
>in a given power domain, no cluster dependency (and yes the CPU PM
>notifiers are not appropriate at present - eg on
>cpu_cluster_pm_{enter/exit} we save and restore the GIC distributor state
>even on multi-cluster systems, that's useless and has no connection with
>the real power domain topology at all, so the concept of cluster as it
>stands is shaky to say the least).
>

Lets discuss this more. I am interested in what you are thinking, will
let you go through the code.

Thanks for you time Lorenzo.

-- Lina

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-20 16:42           ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 16:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Nov 20 2015 at 09:20 -0700, Lorenzo Pieralisi wrote:
>On Thu, Nov 19, 2015 at 03:52:13PM -0800, Kevin Hilman wrote:
>> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
>>
>> > On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>> >> A PM domain comprising of CPUs may be powered off when all the CPUs in
>> >> the domain are powered down. Powering down a CPU domain is generally a
>> >> expensive operation and therefore the power performance trade offs
>> >> should be considered. The time between the last CPU powering down and
>> >> the first CPU powering up in a domain, is the time available for the
>> >> domain to sleep. Ideally, the sleep time of the domain should fulfill
>> >> the residency requirement of the domains' idle state.
>> >>
>> >> To do this effectively, read the time before the wakeup of the cluster's
>> >> CPUs and ensure that the domain's idle state sleep time guarantees the
>> >> QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>> >> state's residency.
>> >
>> > To me this information should be part of the CPUidle governor (it is
>> > already there), we should not split the decision into multiple layers.
>> >
>> > The problem you are facing is that the CPUidle governor(s) do not take
>> > cross cpus relationship into account, I do not think that adding another
>> > decision layer in the power domain subsystem helps, you are doing that
>> > just because adding it to the existing CPUidle governor(s) is invasive.
>> >
>> > Why can't we use the power domain work you put together to eg disable
>> > idle states that share multiple cpus and make them "visible" only
>> > when the power domain that encompass them is actually going down ?
>> >
>> > You could use the power domains information to detect states that
>> > are shared between cpus.
>> >
>> > It is just an idea, what I am saying is that having another governor in
>> > the power domain subsytem does not make much sense, you split the
>> > decision in two layers while there is actually one, the existing
>> > CPUidle governor and that's where the decision should be taken.
>>
>> Hmm, considering "normal" devices in "normal" power domains, and
>> following the same logic, the equivalent would be to say that the
>> decision to gate the power domain belongs to the individual drivers
>> in the domain instead of in the power domain layer.  I disagree.
>>
>> IMO, there are different decision layers because there are different
>> hardware layers.  Devices (including CPUs) are reponsible for handling
>> device-local idle states, based on device-local conditions (e.g. local
>> wakeups, timers, etc.)  and domains are responsible for handling
>> decisions based on conditions of the whole domain.
>
>After going through the series for the second time (it is quite complex and
>should probably be split) I understood your point of view and I agree with
>it, I will review it more in-depth to understand the details.
>
I have included patches from Axel and Marc, so as to get a complete
picture. My core changes are in genpd, cpu-pd and psci.c

>One thing that is not clear to me is how we would end up handling
>cluster states in platform coordinated mode with this series (and
>I am actually referring to the data we would add in the idle-states,
>such as min-residency).
>
>From what I see, the platform coordinated mode, doesnt need any of this.
We are fine as it is today. CPUs vote for the cluster state they can
enter and the f/w determines based on these votes. It makes sense and
probably easier to flatten out the cluster states and attach them to
cpuidle for that.

I couldnt find a symmetry with OS initated. May be it deserves more
discussion and brain storming.

>I admit that data for cluster states at present
>is not extremely well defined, because we have to add latencies for
>the cluster state even if the state itself may be just a cpu one (by
>definition a cluster state is entered only if all cpus in the cluster
>enter it, otherwise FW or power controller demote them automatically).
>

>I would like to take this series as an opportunity to improve the
>current situation in a clean way (and without changing the bindings,
>only augmenting them).
>
>On a side note, I think we should give up the concept of cluster
>entirely, to me they are just a group of cpus, I do not see any reason
>why we should group cpus this way and I do not like the dependencies
>of this series on the cpu-map either, I do not see the reason but I
>will go through code again to make sure I am not missing anything.
>
SoC's could have different organization of CPUs (clubbed as clusters)
and power domains the power thesee clusters. This information has to
come from the DT. Since there are no actual devices in linux for domain
management (with PSCI), I have added them to cpu-map, which already
builds up the cluster hierarchy. The only addition I had to make wa
allow these cluster nodes to be tell the kernel that they are domain
providers.

>To be clear, to me the cpumask should be created with all cpus belonging
>in a given power domain, no cluster dependency (and yes the CPU PM
>notifiers are not appropriate at present - eg on
>cpu_cluster_pm_{enter/exit} we save and restore the GIC distributor state
>even on multi-cluster systems, that's useless and has no connection with
>the real power domain topology at all, so the concept of cluster as it
>stands is shaky to say the least).
>

Lets discuss this more. I am interested in what you are thinking, will
let you go through the code.

Thanks for you time Lorenzo.

-- Lina

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

* Re: [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
  2015-11-19  8:50       ` Marc Titinger
@ 2015-11-20 17:39         ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 17:39 UTC (permalink / raw)
  To: Marc Titinger
  Cc: Lorenzo Pieralisi, ulf.hansson, khilman, linux-pm,
	linux-arm-kernel, geert, k.kozlowski, msivasub, agross, sboyd,
	linux-arm-msm, ahaslam

On Thu, Nov 19 2015 at 01:50 -0700, Marc Titinger wrote:
>On 18/11/2015 19:42, Lorenzo Pieralisi wrote:
>>On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>>>A PM domain comprising of CPUs may be powered off when all the CPUs in
>>>the domain are powered down. Powering down a CPU domain is generally a
>>>expensive operation and therefore the power performance trade offs
>>>should be considered. The time between the last CPU powering down and
>>>the first CPU powering up in a domain, is the time available for the
>>>domain to sleep. Ideally, the sleep time of the domain should fulfill
>>>the residency requirement of the domains' idle state.
>>>
>>>To do this effectively, read the time before the wakeup of the cluster's
>>>CPUs and ensure that the domain's idle state sleep time guarantees the
>>>QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>>>state's residency.
>>
>>To me this information should be part of the CPUidle governor (it is
>>already there), we should not split the decision into multiple layers.
>>
>>The problem you are facing is that the CPUidle governor(s) do not take
>>cross cpus relationship into account, I do not think that adding another
>>decision layer in the power domain subsystem helps, you are doing that
>>just because adding it to the existing CPUidle governor(s) is invasive.
>>
>>Why can't we use the power domain work you put together to eg disable
>>idle states that share multiple cpus and make them "visible" only
>>when the power domain that encompass them is actually going down ?
>>
>>You could use the power domains information to detect states that
>>are shared between cpus.
>>
>>It is just an idea, what I am saying is that having another governor in
>>the power domain subsytem does not make much sense, you split the
>>decision in two layers while there is actually one, the existing
>>CPUidle governor and that's where the decision should be taken.
>>
>>Thoughts appreciated.
>
>Maybe this is silly and not thought-through, but I wonder if the 
>responsibilities could be split or instance with an outer control loop 
>that has the heuristic to compute the next tick time, and the required 
>cpu-power needed during that time slot, and an inner control loop 
>(genpd) that has a per-domain QoS and can optimize power consumption.
>
Not sure I understand everything you said, but the heuristics across a
bunch of CPUs can be very erratic. Its hard enough for menu governor to
determine heuristics on a per-cpu basis.

I governor in this patch already takes care of PM QoS, but does not do a
per-cpu QoS.

We should discuss this more.

-- Lina

>Marc.
>
>>
>>Lorenzo
>>
>>>Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>>>---
>>>  drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
>>>  1 file changed, 82 insertions(+), 1 deletion(-)
>>>
>>>diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>>>index 617ce54..a00abc1 100644
>>>--- a/drivers/base/power/cpu-pd.c
>>>+++ b/drivers/base/power/cpu-pd.c
>>>@@ -21,6 +21,7 @@
>>>  #include <linux/pm_qos.h>
>>>  #include <linux/rculist.h>
>>>  #include <linux/slab.h>
>>>+#include <linux/tick.h>
>>>
>>>  #define CPU_PD_NAME_MAX 36
>>>
>>>@@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
>>>  	}
>>>  }
>>>
>>>+static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
>>>+{
>>>+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
>>>+	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
>>>+	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>>>+	u64 sleep_ns = ~0;
>>>+	ktime_t earliest;
>>>+	int cpu;
>>>+	int i;
>>>+
>>>+	/* Reset the last set genpd state, default to index 0 */
>>>+	genpd->state_idx = 0;
>>>+
>>>+	/* We dont want to power down, if QoS is 0 */
>>>+	if (!qos)
>>>+		return false;
>>>+
>>>+	/*
>>>+	 * Find the sleep time for the cluster.
>>>+	 * The time between now and the first wake up of any CPU that
>>>+	 * are in this domain hierarchy is the time available for the
>>>+	 * domain to be idle.
>>>+	 */
>>>+	earliest.tv64 = KTIME_MAX;
>>>+	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
>>>+		struct device *cpu_dev = get_cpu_device(cpu);
>>>+		struct gpd_timing_data *td;
>>>+
>>>+		td = &dev_gpd_data(cpu_dev)->td;
>>>+
>>>+		if (earliest.tv64 < td->next_wakeup.tv64)
>>>+			earliest = td->next_wakeup;
>>>+	}
>>>+
>>>+	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
>>>+	if (sleep_ns <= 0)
>>>+		return false;
>>>+
>>>+	/*
>>>+	 * Find the deepest sleep state that satisfies the residency
>>>+	 * requirement and the QoS constraint
>>>+	 */
>>>+	for (i = genpd->state_count - 1; i > 0; i--) {
>>>+		u64 state_sleep_ns;
>>>+
>>>+		state_sleep_ns = genpd->states[i].power_off_latency_ns +
>>>+			genpd->states[i].power_on_latency_ns +
>>>+			genpd->states[i].residency_ns;
>>>+
>>>+		/*
>>>+		 * If we cant sleep to save power in the state, move on
>>>+		 * to the next lower idle state.
>>>+		 */
>>>+		if (state_sleep_ns > sleep_ns)
>>>+		       continue;
>>>+
>>>+		/*
>>>+		 * We also dont want to sleep more than we should to
>>>+		 * gaurantee QoS.
>>>+		 */
>>>+		if (state_sleep_ns < (qos * NSEC_PER_USEC))
>>>+			break;
>>>+	}
>>>+
>>>+	if (i >= 0)
>>>+		genpd->state_idx = i;
>>>+
>>>+	return  (i >= 0) ? true : false;
>>>+}
>>>+
>>>+static bool cpu_stop_ok(struct device *dev)
>>>+{
>>>+	return true;
>>>+}
>>>+
>>>+struct dev_power_governor cpu_pd_gov = {
>>>+	.power_down_ok = cpu_pd_down_ok,
>>>+	.stop_ok = cpu_stop_ok,
>>>+};
>>>+
>>>  static int cpu_pd_power_off(struct generic_pm_domain *genpd)
>>>  {
>>>  	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
>>>@@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
>>>
>>>  	/* Register the CPU genpd */
>>>  	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
>>>-	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
>>>+	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
>>>  	if (ret) {
>>>  		pr_err("Unable to initialize domain %s\n", dn->full_name);
>>>  		return ret;
>>>--
>>>2.1.4
>>>
>

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

* [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs
@ 2015-11-20 17:39         ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-20 17:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 19 2015 at 01:50 -0700, Marc Titinger wrote:
>On 18/11/2015 19:42, Lorenzo Pieralisi wrote:
>>On Tue, Nov 17, 2015 at 03:37:42PM -0700, Lina Iyer wrote:
>>>A PM domain comprising of CPUs may be powered off when all the CPUs in
>>>the domain are powered down. Powering down a CPU domain is generally a
>>>expensive operation and therefore the power performance trade offs
>>>should be considered. The time between the last CPU powering down and
>>>the first CPU powering up in a domain, is the time available for the
>>>domain to sleep. Ideally, the sleep time of the domain should fulfill
>>>the residency requirement of the domains' idle state.
>>>
>>>To do this effectively, read the time before the wakeup of the cluster's
>>>CPUs and ensure that the domain's idle state sleep time guarantees the
>>>QoS requirements of each of the CPU, the PM QoS CPU_DMA_LATENCY and the
>>>state's residency.
>>
>>To me this information should be part of the CPUidle governor (it is
>>already there), we should not split the decision into multiple layers.
>>
>>The problem you are facing is that the CPUidle governor(s) do not take
>>cross cpus relationship into account, I do not think that adding another
>>decision layer in the power domain subsystem helps, you are doing that
>>just because adding it to the existing CPUidle governor(s) is invasive.
>>
>>Why can't we use the power domain work you put together to eg disable
>>idle states that share multiple cpus and make them "visible" only
>>when the power domain that encompass them is actually going down ?
>>
>>You could use the power domains information to detect states that
>>are shared between cpus.
>>
>>It is just an idea, what I am saying is that having another governor in
>>the power domain subsytem does not make much sense, you split the
>>decision in two layers while there is actually one, the existing
>>CPUidle governor and that's where the decision should be taken.
>>
>>Thoughts appreciated.
>
>Maybe this is silly and not thought-through, but I wonder if the 
>responsibilities could be split or instance with an outer control loop 
>that has the heuristic to compute the next tick time, and the required 
>cpu-power needed during that time slot, and an inner control loop 
>(genpd) that has a per-domain QoS and can optimize power consumption.
>
Not sure I understand everything you said, but the heuristics across a
bunch of CPUs can be very erratic. Its hard enough for menu governor to
determine heuristics on a per-cpu basis.

I governor in this patch already takes care of PM QoS, but does not do a
per-cpu QoS.

We should discuss this more.

-- Lina

>Marc.
>
>>
>>Lorenzo
>>
>>>Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>>>---
>>>  drivers/base/power/cpu-pd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
>>>  1 file changed, 82 insertions(+), 1 deletion(-)
>>>
>>>diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>>>index 617ce54..a00abc1 100644
>>>--- a/drivers/base/power/cpu-pd.c
>>>+++ b/drivers/base/power/cpu-pd.c
>>>@@ -21,6 +21,7 @@
>>>  #include <linux/pm_qos.h>
>>>  #include <linux/rculist.h>
>>>  #include <linux/slab.h>
>>>+#include <linux/tick.h>
>>>
>>>  #define CPU_PD_NAME_MAX 36
>>>
>>>@@ -66,6 +67,86 @@ static void get_cpus_in_domain(struct generic_pm_domain *genpd,
>>>  	}
>>>  }
>>>
>>>+static bool cpu_pd_down_ok(struct dev_pm_domain *pd)
>>>+{
>>>+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
>>>+	struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd);
>>>+	int qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>>>+	u64 sleep_ns = ~0;
>>>+	ktime_t earliest;
>>>+	int cpu;
>>>+	int i;
>>>+
>>>+	/* Reset the last set genpd state, default to index 0 */
>>>+	genpd->state_idx = 0;
>>>+
>>>+	/* We dont want to power down, if QoS is 0 */
>>>+	if (!qos)
>>>+		return false;
>>>+
>>>+	/*
>>>+	 * Find the sleep time for the cluster.
>>>+	 * The time between now and the first wake up of any CPU that
>>>+	 * are in this domain hierarchy is the time available for the
>>>+	 * domain to be idle.
>>>+	 */
>>>+	earliest.tv64 = KTIME_MAX;
>>>+	for_each_cpu_and(cpu, cpu_pd->cpus, cpu_online_mask) {
>>>+		struct device *cpu_dev = get_cpu_device(cpu);
>>>+		struct gpd_timing_data *td;
>>>+
>>>+		td = &dev_gpd_data(cpu_dev)->td;
>>>+
>>>+		if (earliest.tv64 < td->next_wakeup.tv64)
>>>+			earliest = td->next_wakeup;
>>>+	}
>>>+
>>>+	sleep_ns = ktime_to_ns(ktime_sub(earliest, ktime_get()));
>>>+	if (sleep_ns <= 0)
>>>+		return false;
>>>+
>>>+	/*
>>>+	 * Find the deepest sleep state that satisfies the residency
>>>+	 * requirement and the QoS constraint
>>>+	 */
>>>+	for (i = genpd->state_count - 1; i > 0; i--) {
>>>+		u64 state_sleep_ns;
>>>+
>>>+		state_sleep_ns = genpd->states[i].power_off_latency_ns +
>>>+			genpd->states[i].power_on_latency_ns +
>>>+			genpd->states[i].residency_ns;
>>>+
>>>+		/*
>>>+		 * If we cant sleep to save power in the state, move on
>>>+		 * to the next lower idle state.
>>>+		 */
>>>+		if (state_sleep_ns > sleep_ns)
>>>+		       continue;
>>>+
>>>+		/*
>>>+		 * We also dont want to sleep more than we should to
>>>+		 * gaurantee QoS.
>>>+		 */
>>>+		if (state_sleep_ns < (qos * NSEC_PER_USEC))
>>>+			break;
>>>+	}
>>>+
>>>+	if (i >= 0)
>>>+		genpd->state_idx = i;
>>>+
>>>+	return  (i >= 0) ? true : false;
>>>+}
>>>+
>>>+static bool cpu_stop_ok(struct device *dev)
>>>+{
>>>+	return true;
>>>+}
>>>+
>>>+struct dev_power_governor cpu_pd_gov = {
>>>+	.power_down_ok = cpu_pd_down_ok,
>>>+	.stop_ok = cpu_stop_ok,
>>>+};
>>>+
>>>  static int cpu_pd_power_off(struct generic_pm_domain *genpd)
>>>  {
>>>  	struct cpu_pm_domain *pd = to_cpu_pd(genpd);
>>>@@ -183,7 +264,7 @@ int of_register_cpu_pm_domain(struct device_node *dn,
>>>
>>>  	/* Register the CPU genpd */
>>>  	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
>>>-	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
>>>+	ret = of_pm_genpd_init(dn, pd->genpd, &cpu_pd_gov, false);
>>>  	if (ret) {
>>>  		pr_err("Unable to initialize domain %s\n", dn->full_name);
>>>  		return ret;
>>>--
>>>2.1.4
>>>
>

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

* Re: [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
  2015-11-18 14:57     ` Lina Iyer
@ 2015-11-23 13:31       ` Lucas Stach
  -1 siblings, 0 replies; 166+ messages in thread
From: Lucas Stach @ 2015-11-23 13:31 UTC (permalink / raw)
  To: Lina Iyer; +Cc: linux-arm-kernel, linux-pm, linux-arm-msm, Axel Haslam

Am Mittwoch, den 18.11.2015, 07:57 -0700 schrieb Lina Iyer:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
> 
> The generic_pm_domain structure uses an array of latencies to be able to
> declare multiple intermediate states.
> 
> Declare a single "OFF" state with the default latencies So that the
> power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
> structure can be eventualy removed.
> 
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> [Lina: pm_genpd_init() argument change]
> ---
>  arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> index 8e7976a..b070e06 100644
> --- a/arch/arm/mach-imx/gpc.c
> +++ b/arch/arm/mach-imx/gpc.c
> @@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
>  	.name = "ARM",
>  };
>  
> +static struct genpd_power_state imx6q_arm_domain_states[] = {

Those states are for the PU, not the ARM domain.

> +	{
> +		.name = "OFF",
> +		.power_off_latency_ns = 25000,
> +		.power_on_latency_ns = 2000000,
> +	},
> +};
> +
>  static struct pu_domain imx6q_pu_domain = {
>  	.base = {
>  		.name = "PU",
>  		.power_off = imx6q_pm_pu_power_off,
>  		.power_on = imx6q_pm_pu_power_on,
> -		.power_off_latency_ns = 25000,
> -		.power_on_latency_ns = 2000000,
> +		.gov = NULL,
> +		.status = GPD_STATE_POWER_OFF,

The above 2 lines should not be needed. This is a static struct, so .gov
will already be NULL. status is set by pm_genpd_init() and the above
value is actively wrong.

> +		.states = imx6q_arm_domain_states,
> +		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
>  	},
>  };
>  

How urgent is this patch? I have a series to rework the GPC driver
almost ready and I could fold this change in directly if it's okay for
this to sit through a review of the rework.

Regards,
Lucas
-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

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

* [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
@ 2015-11-23 13:31       ` Lucas Stach
  0 siblings, 0 replies; 166+ messages in thread
From: Lucas Stach @ 2015-11-23 13:31 UTC (permalink / raw)
  To: linux-arm-kernel

Am Mittwoch, den 18.11.2015, 07:57 -0700 schrieb Lina Iyer:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
> 
> The generic_pm_domain structure uses an array of latencies to be able to
> declare multiple intermediate states.
> 
> Declare a single "OFF" state with the default latencies So that the
> power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
> structure can be eventualy removed.
> 
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> [Lina: pm_genpd_init() argument change]
> ---
>  arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> index 8e7976a..b070e06 100644
> --- a/arch/arm/mach-imx/gpc.c
> +++ b/arch/arm/mach-imx/gpc.c
> @@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
>  	.name = "ARM",
>  };
>  
> +static struct genpd_power_state imx6q_arm_domain_states[] = {

Those states are for the PU, not the ARM domain.

> +	{
> +		.name = "OFF",
> +		.power_off_latency_ns = 25000,
> +		.power_on_latency_ns = 2000000,
> +	},
> +};
> +
>  static struct pu_domain imx6q_pu_domain = {
>  	.base = {
>  		.name = "PU",
>  		.power_off = imx6q_pm_pu_power_off,
>  		.power_on = imx6q_pm_pu_power_on,
> -		.power_off_latency_ns = 25000,
> -		.power_on_latency_ns = 2000000,
> +		.gov = NULL,
> +		.status = GPD_STATE_POWER_OFF,

The above 2 lines should not be needed. This is a static struct, so .gov
will already be NULL. status is set by pm_genpd_init() and the above
value is actively wrong.

> +		.states = imx6q_arm_domain_states,
> +		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
>  	},
>  };
>  

How urgent is this patch? I have a series to rework the GPC driver
almost ready and I could fold this change in directly if it's okay for
this to sit through a review of the rework.

Regards,
Lucas
-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

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

* Re: [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
  2015-11-23 13:31       ` Lucas Stach
@ 2015-11-23 13:42         ` Lucas Stach
  -1 siblings, 0 replies; 166+ messages in thread
From: Lucas Stach @ 2015-11-23 13:42 UTC (permalink / raw)
  To: Lina Iyer; +Cc: linux-arm-kernel, linux-pm, linux-arm-msm, Axel Haslam

Am Montag, den 23.11.2015, 14:31 +0100 schrieb Lucas Stach:
> Am Mittwoch, den 18.11.2015, 07:57 -0700 schrieb Lina Iyer:
> > From: Axel Haslam <ahaslam+renesas@baylibre.com>
> > 
> > The generic_pm_domain structure uses an array of latencies to be able to
> > declare multiple intermediate states.
> > 
> > Declare a single "OFF" state with the default latencies So that the
> > power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
> > structure can be eventualy removed.
> > 
> > Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> > Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> > [Lina: pm_genpd_init() argument change]
> > ---
> >  arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
> >  1 file changed, 12 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> > index 8e7976a..b070e06 100644
> > --- a/arch/arm/mach-imx/gpc.c
> > +++ b/arch/arm/mach-imx/gpc.c
> > @@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
> >  	.name = "ARM",
> >  };
> >  
> > +static struct genpd_power_state imx6q_arm_domain_states[] = {
> 
> Those states are for the PU, not the ARM domain.
> 
> > +	{
> > +		.name = "OFF",
> > +		.power_off_latency_ns = 25000,
> > +		.power_on_latency_ns = 2000000,
> > +	},
> > +};
> > +
> >  static struct pu_domain imx6q_pu_domain = {
> >  	.base = {
> >  		.name = "PU",
> >  		.power_off = imx6q_pm_pu_power_off,
> >  		.power_on = imx6q_pm_pu_power_on,
> > -		.power_off_latency_ns = 25000,
> > -		.power_on_latency_ns = 2000000,
> > +		.gov = NULL,
> > +		.status = GPD_STATE_POWER_OFF,
> 
> The above 2 lines should not be needed. This is a static struct, so .gov
> will already be NULL. status is set by pm_genpd_init() and the above
> value is actively wrong.
> 
> > +		.states = imx6q_arm_domain_states,
> > +		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
> >  	},
> >  };
> >  
> 
> How urgent is this patch? I have a series to rework the GPC driver
> almost ready and I could fold this change in directly if it's okay for
> this to sit through a review of the rework.

And I just noticed this depends on changes that are not already in
v4.4-rc. Why is this sent as a single patch and not as part of the
series adding multiple state support to genpd?

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |


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

* [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
@ 2015-11-23 13:42         ` Lucas Stach
  0 siblings, 0 replies; 166+ messages in thread
From: Lucas Stach @ 2015-11-23 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 23.11.2015, 14:31 +0100 schrieb Lucas Stach:
> Am Mittwoch, den 18.11.2015, 07:57 -0700 schrieb Lina Iyer:
> > From: Axel Haslam <ahaslam+renesas@baylibre.com>
> > 
> > The generic_pm_domain structure uses an array of latencies to be able to
> > declare multiple intermediate states.
> > 
> > Declare a single "OFF" state with the default latencies So that the
> > power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
> > structure can be eventualy removed.
> > 
> > Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> > Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> > [Lina: pm_genpd_init() argument change]
> > ---
> >  arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
> >  1 file changed, 12 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> > index 8e7976a..b070e06 100644
> > --- a/arch/arm/mach-imx/gpc.c
> > +++ b/arch/arm/mach-imx/gpc.c
> > @@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
> >  	.name = "ARM",
> >  };
> >  
> > +static struct genpd_power_state imx6q_arm_domain_states[] = {
> 
> Those states are for the PU, not the ARM domain.
> 
> > +	{
> > +		.name = "OFF",
> > +		.power_off_latency_ns = 25000,
> > +		.power_on_latency_ns = 2000000,
> > +	},
> > +};
> > +
> >  static struct pu_domain imx6q_pu_domain = {
> >  	.base = {
> >  		.name = "PU",
> >  		.power_off = imx6q_pm_pu_power_off,
> >  		.power_on = imx6q_pm_pu_power_on,
> > -		.power_off_latency_ns = 25000,
> > -		.power_on_latency_ns = 2000000,
> > +		.gov = NULL,
> > +		.status = GPD_STATE_POWER_OFF,
> 
> The above 2 lines should not be needed. This is a static struct, so .gov
> will already be NULL. status is set by pm_genpd_init() and the above
> value is actively wrong.
> 
> > +		.states = imx6q_arm_domain_states,
> > +		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
> >  	},
> >  };
> >  
> 
> How urgent is this patch? I have a series to rework the GPC driver
> almost ready and I could fold this change in directly if it's okay for
> this to sit through a review of the rework.

And I just noticed this depends on changes that are not already in
v4.4-rc. Why is this sent as a single patch and not as part of the
series adding multiple state support to genpd?

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |

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

* Re: [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
  2015-11-20 16:28       ` Lina Iyer
@ 2015-11-24 18:29         ` Kevin Hilman
  -1 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-24 18:29 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, linux-pm, linux-arm-kernel, geert, k.kozlowski,
	msivasub, agross, sboyd, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

Lina Iyer <lina.iyer@linaro.org> writes:

> On Thu, Nov 19 2015 at 16:35 -0700, Kevin Hilman wrote:
>>Lina Iyer <lina.iyer@linaro.org> writes:
>>
>>> Reading the next wakeup of the CPU can only be realiably done only from
>>> that CPU. In the idle enter path record the next wake up of the CPU. The
>>> information is useful to determine the sleep time left for the CPU.
>>>
>>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>>> ---
>>>  drivers/cpuidle/cpuidle-arm.c | 5 +++++
>>>  1 file changed, 5 insertions(+)
>>>
>>> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
>>> index 8e72a23..b3133ef 100644
>>> --- a/drivers/cpuidle/cpuidle-arm.c
>>> +++ b/drivers/cpuidle/cpuidle-arm.c
>>> @@ -18,9 +18,11 @@
>>>  #include <linux/kernel.h>
>>>  #include <linux/module.h>
>>>  #include <linux/of.h>
>>> +#include <linux/pm_domain.h>
>>>  #include <linux/pm_runtime.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/rcupdate.h>
>>> +#include <linux/tick.h>
>>>
>>>  #include <asm/cpuidle.h>
>>>
>>> @@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>>  	ret = cpu_pm_enter();
>>>  	if (!ret) {
>>>  		struct device *cpu_dev = get_cpu_device(dev->cpu);
>>> +		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
>>>
>>> +		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
>>>  		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
>>
>>Maybe set this back to zero atomicaly, after wakeup?
>>
>>Checking for non-zero that might be another way for the domain goveror that there
>>haven't been any CPU wakeups since the CPUs have gone idle.
>>
> I set it to 0 below.

Oops, you're right.  Not sure how I missed that.

> The reference counting by the GET_PUT tells the domain if a device is
> suspended. I see that as a redudant information. May be I am not getting
> your point.

It's redundant, but may be helpful in detecting races.  e.g. domain is
being powered off and CPU wakes up and sets this zero, but runtime PM
layers haven't been called yet so dev->power->usage_count is still zero.

Kevin

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

* [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU
@ 2015-11-24 18:29         ` Kevin Hilman
  0 siblings, 0 replies; 166+ messages in thread
From: Kevin Hilman @ 2015-11-24 18:29 UTC (permalink / raw)
  To: linux-arm-kernel

Lina Iyer <lina.iyer@linaro.org> writes:

> On Thu, Nov 19 2015 at 16:35 -0700, Kevin Hilman wrote:
>>Lina Iyer <lina.iyer@linaro.org> writes:
>>
>>> Reading the next wakeup of the CPU can only be realiably done only from
>>> that CPU. In the idle enter path record the next wake up of the CPU. The
>>> information is useful to determine the sleep time left for the CPU.
>>>
>>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>>> ---
>>>  drivers/cpuidle/cpuidle-arm.c | 5 +++++
>>>  1 file changed, 5 insertions(+)
>>>
>>> diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
>>> index 8e72a23..b3133ef 100644
>>> --- a/drivers/cpuidle/cpuidle-arm.c
>>> +++ b/drivers/cpuidle/cpuidle-arm.c
>>> @@ -18,9 +18,11 @@
>>>  #include <linux/kernel.h>
>>>  #include <linux/module.h>
>>>  #include <linux/of.h>
>>> +#include <linux/pm_domain.h>
>>>  #include <linux/pm_runtime.h>
>>>  #include <linux/slab.h>
>>>  #include <linux/rcupdate.h>
>>> +#include <linux/tick.h>
>>>
>>>  #include <asm/cpuidle.h>
>>>
>>> @@ -49,7 +51,9 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
>>>  	ret = cpu_pm_enter();
>>>  	if (!ret) {
>>>  		struct device *cpu_dev = get_cpu_device(dev->cpu);
>>> +		struct generic_pm_domain_data *gpd = dev_gpd_data(cpu_dev);
>>>
>>> +		gpd->td.next_wakeup = tick_nohz_get_next_wakeup();
>>>  		RCU_NONIDLE(pm_runtime_put_sync_suspend(cpu_dev));
>>
>>Maybe set this back to zero atomicaly, after wakeup?
>>
>>Checking for non-zero that might be another way for the domain goveror that there
>>haven't been any CPU wakeups since the CPUs have gone idle.
>>
> I set it to 0 below.

Oops, you're right.  Not sure how I missed that.

> The reference counting by the GET_PUT tells the domain if a device is
> suspended. I see that as a redudant information. May be I am not getting
> your point.

It's redundant, but may be helpful in detecting races.  e.g. domain is
being powered off and CPU wakes up and sets this zero, but runtime PM
layers haven't been called yet so dev->power->usage_count is still zero.

Kevin

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

* Re: [PATCH RFC 07/27] PM / Domains: Read domain residency from DT
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-24 20:41     ` Stephen Boyd
  -1 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-24 20:41 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On 11/17, Lina Iyer wrote:
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index ecfaf44..d71da29 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -67,6 +67,13 @@ have the following properties -
>  		If omitted, this is assumed to be equal to:
>  			entry-latency-us + exit-latency-us
>  
> +	- residency-us:
> +		Usage: Optional
> +		Value type: <prop-encoded-array>

Is it an array or just a single u32? Some example would be good
to add.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 07/27] PM / Domains: Read domain residency from DT
@ 2015-11-24 20:41     ` Stephen Boyd
  0 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-24 20:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/17, Lina Iyer wrote:
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index ecfaf44..d71da29 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -67,6 +67,13 @@ have the following properties -
>  		If omitted, this is assumed to be equal to:
>  			entry-latency-us + exit-latency-us
>  
> +	- residency-us:
> +		Usage: Optional
> +		Value type: <prop-encoded-array>

Is it an array or just a single u32? Some example would be good
to add.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 10/27] drivers: power: Introduce PM domains for CPUs/clusters
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-24 20:52     ` Stephen Boyd
  -1 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-24 20:52 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger, Daniel Lezcano

On 11/17, Lina Iyer wrote:
> diff --git a/Documentation/arm/cpu-domains.txt b/Documentation/arm/cpu-domains.txt
> new file mode 100644
> index 0000000..ef5f215
> --- /dev/null
> +++ b/Documentation/arm/cpu-domains.txt
> @@ -0,0 +1,52 @@
> +CPU Clusters and PM domain
> +
> +Newer CPUs are grouped in a SoC as clusters. A cluster in addition to the
> +CPUs may have caches, GIC, VFP and architecture specific power controller to
> +power the cluster. A cluster may also be nested in another cluster, the
> +hierarchy of which is depicted in the device tree. CPUIdle frameworks enables

s/frameworks/framework/?

s/depicted/described/? Hopefully we aren't putting pictures or
art in DT for this sort of stuff.


> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> new file mode 100644
> index 0000000..9758b8d
> --- /dev/null
> +++ b/drivers/base/power/cpu-pd.c
> @@ -0,0 +1,231 @@
> +/*
> + * CPU Generic PM Domain.
> + *
> + * Copyright (C) 2015 Linaro Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define DEBUG
> +
> +#include <linux/kernel.h>
> +#include <linux/export.h>
> +#include <linux/cpu.h>
> +#include <linux/cpu_pm.h>
> +#include <linux/cpu-pd.h>
> +#include <linux/device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/platform_device.h>

Is this used?

> +#include <linux/rculist.h>
> +#include <linux/slab.h>
> +
> +#define CPU_PD_NAME_MAX 36
> +
[...]
> +static int of_pm_domain_attach_cpus(struct device_node *dn)
> +{
> +	int cpuid, ret;
> +
> +	/* Find any CPU nodes with a phandle to this power domain */
> +	for_each_possible_cpu(cpuid) {
> +		struct device *cpu_dev;
> +		struct device_node *cpu_pd;
> +
> +		cpu_dev = get_cpu_device(cpuid);
> +		if (!cpu_dev) {
> +			pr_warn("%s: Unable to get device for CPU%d\n",
> +					__func__, cpuid);
> +			return -ENODEV;
> +		}
> +
> +		/* Only attach CPUs that are part of this domain */
> +		cpu_pd = of_parse_phandle(cpu_dev->of_node, "power-domains", 0);
> +		if (cpu_pd != dn)
> +			continue;
> +
> +		if (cpu_online(cpuid)) {

I guess we don't care if hotplug is running in parallel to this
code?

> +			pm_runtime_set_active(cpu_dev);
> +			/*
> +			 * Execute the below on that 'cpu' to ensure that the
> +			 * reference counting is correct. It's possible that
> +			 * while this code is executing, the 'cpu' may be
> +			 * powered down, but we may incorrectly increment the
> +			 * usage. By executing the get_cpu on the 'cpu',
> +			 * we can ensure that the 'cpu' and its usage count are
> +			 * matched.
> +			 */
> +			smp_call_function_single(cpuid, run_cpu, NULL, true);
> +		} else {
> +			pm_runtime_set_suspended(cpu_dev);
> +		}
> +
> +		ret = genpd_dev_pm_attach(cpu_dev);
> +		if (ret) {
> +			dev_warn(cpu_dev,
> +				"%s: Unable to attach to power-domain: %d\n",
> +				__func__, ret);
> +		} else {
> +			pm_runtime_enable(cpu_dev);
> +			dev_dbg(cpu_dev, "Attached CPU%d to domain\n", cpuid);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int of_register_cpu_pm_domain(struct device_node *dn,

static?

> +		struct cpu_pm_domain *pd)
> +{
> +	int ret;
> +
> +	if (!pd || !pd->genpd)
> +		return -EINVAL;
> +
> +	/*
> +	 * The platform should not set up the genpd callbacks.
> +	 * They should setup the pd->plat_ops instead.
> +	 */
> +	WARN_ON(pd->genpd->power_off);
> +	WARN_ON(pd->genpd->power_on);
> +
> +	pd->genpd->power_off = cpu_pd_power_off;
> +	pd->genpd->power_on = cpu_pd_power_on;
> +	pd->genpd->flags |= GENPD_FLAG_IRQ_SAFE;
> +
> +	INIT_LIST_HEAD_RCU(&pd->link);
> +	spin_lock(&cpu_pd_list_lock);
> +	list_add_rcu(&pd->link, &of_cpu_pd_list);
> +	spin_unlock(&cpu_pd_list_lock);
> +	pd->dn = dn;
> +
> +	/* Register the CPU genpd */
> +	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
> +	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
> +	if (ret) {
> +		pr_err("Unable to initialize domain %s\n", dn->full_name);
> +		return ret;
> +	}
> +
> +	ret = of_genpd_add_provider_simple(dn, pd->genpd);
> +	if (ret)
> +		pr_warn("Unable to add genpd %s as provider\n",
> +				pd->genpd->name);
> +
> +	/* Attach the CPUs to the CPU PM domain */
> +	ret = of_pm_domain_attach_cpus(dn);
> +	if (ret)
> +		of_genpd_del_provider(dn);
> +
> +	return ret;
> +}
> +
> +/**
> + * of_init_cpu_pm_domain() - Initialize a CPU PM domain using the CPU pd
> + * provided
> + * @dn: PM domain provider device node
> + * @ops: CPU PM domain platform specific ops for callback
> + *
> + * This is a single step initialize the CPU PM domain with defaults,
> + * also register the genpd and attach CPUs to the genpd.

Returns?

> + */
> +struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
> +				const struct cpu_pd_ops *ops)
> +{
> +	struct cpu_pm_domain *pd;
> +	int ret;
> +
> +	if (!of_device_is_available(dn))
> +		return ERR_PTR(-ENODEV);
> +
> +	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return ERR_PTR(-ENOMEM);
> +
> +	pd->genpd = kzalloc(sizeof(*(pd->genpd)), GFP_KERNEL);
> +	if (!pd->genpd) {
> +		kfree(pd);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	pd->genpd->name = kstrndup(dn->full_name, CPU_PD_NAME_MAX, GFP_KERNEL);
> +	if (!pd->genpd->name) {
> +		kfree(pd->genpd);
> +		kfree(pd);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	if (ops) {
> +		pd->plat_ops.power_off = ops->power_off;
> +		pd->plat_ops.power_on = ops->power_on;
> +	}
> +
> +	ret = of_register_cpu_pm_domain(dn, pd);
> +	if (ret) {
> +		kfree(pd->genpd->name);
> +		kfree(pd->genpd);
> +		kfree(pd);
> +		return ERR_PTR(ret);

Maybe we can have a goto error path so that we don't duplicate
these kfree calls a bunch of times.

> +	}
> +
> +	return pd->genpd;
> +}
> +EXPORT_SYMBOL(of_init_cpu_pm_domain);

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 10/27] drivers: power: Introduce PM domains for CPUs/clusters
@ 2015-11-24 20:52     ` Stephen Boyd
  0 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-24 20:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/17, Lina Iyer wrote:
> diff --git a/Documentation/arm/cpu-domains.txt b/Documentation/arm/cpu-domains.txt
> new file mode 100644
> index 0000000..ef5f215
> --- /dev/null
> +++ b/Documentation/arm/cpu-domains.txt
> @@ -0,0 +1,52 @@
> +CPU Clusters and PM domain
> +
> +Newer CPUs are grouped in a SoC as clusters. A cluster in addition to the
> +CPUs may have caches, GIC, VFP and architecture specific power controller to
> +power the cluster. A cluster may also be nested in another cluster, the
> +hierarchy of which is depicted in the device tree. CPUIdle frameworks enables

s/frameworks/framework/?

s/depicted/described/? Hopefully we aren't putting pictures or
art in DT for this sort of stuff.


> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> new file mode 100644
> index 0000000..9758b8d
> --- /dev/null
> +++ b/drivers/base/power/cpu-pd.c
> @@ -0,0 +1,231 @@
> +/*
> + * CPU Generic PM Domain.
> + *
> + * Copyright (C) 2015 Linaro Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define DEBUG
> +
> +#include <linux/kernel.h>
> +#include <linux/export.h>
> +#include <linux/cpu.h>
> +#include <linux/cpu_pm.h>
> +#include <linux/cpu-pd.h>
> +#include <linux/device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/platform_device.h>

Is this used?

> +#include <linux/rculist.h>
> +#include <linux/slab.h>
> +
> +#define CPU_PD_NAME_MAX 36
> +
[...]
> +static int of_pm_domain_attach_cpus(struct device_node *dn)
> +{
> +	int cpuid, ret;
> +
> +	/* Find any CPU nodes with a phandle to this power domain */
> +	for_each_possible_cpu(cpuid) {
> +		struct device *cpu_dev;
> +		struct device_node *cpu_pd;
> +
> +		cpu_dev = get_cpu_device(cpuid);
> +		if (!cpu_dev) {
> +			pr_warn("%s: Unable to get device for CPU%d\n",
> +					__func__, cpuid);
> +			return -ENODEV;
> +		}
> +
> +		/* Only attach CPUs that are part of this domain */
> +		cpu_pd = of_parse_phandle(cpu_dev->of_node, "power-domains", 0);
> +		if (cpu_pd != dn)
> +			continue;
> +
> +		if (cpu_online(cpuid)) {

I guess we don't care if hotplug is running in parallel to this
code?

> +			pm_runtime_set_active(cpu_dev);
> +			/*
> +			 * Execute the below on that 'cpu' to ensure that the
> +			 * reference counting is correct. It's possible that
> +			 * while this code is executing, the 'cpu' may be
> +			 * powered down, but we may incorrectly increment the
> +			 * usage. By executing the get_cpu on the 'cpu',
> +			 * we can ensure that the 'cpu' and its usage count are
> +			 * matched.
> +			 */
> +			smp_call_function_single(cpuid, run_cpu, NULL, true);
> +		} else {
> +			pm_runtime_set_suspended(cpu_dev);
> +		}
> +
> +		ret = genpd_dev_pm_attach(cpu_dev);
> +		if (ret) {
> +			dev_warn(cpu_dev,
> +				"%s: Unable to attach to power-domain: %d\n",
> +				__func__, ret);
> +		} else {
> +			pm_runtime_enable(cpu_dev);
> +			dev_dbg(cpu_dev, "Attached CPU%d to domain\n", cpuid);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int of_register_cpu_pm_domain(struct device_node *dn,

static?

> +		struct cpu_pm_domain *pd)
> +{
> +	int ret;
> +
> +	if (!pd || !pd->genpd)
> +		return -EINVAL;
> +
> +	/*
> +	 * The platform should not set up the genpd callbacks.
> +	 * They should setup the pd->plat_ops instead.
> +	 */
> +	WARN_ON(pd->genpd->power_off);
> +	WARN_ON(pd->genpd->power_on);
> +
> +	pd->genpd->power_off = cpu_pd_power_off;
> +	pd->genpd->power_on = cpu_pd_power_on;
> +	pd->genpd->flags |= GENPD_FLAG_IRQ_SAFE;
> +
> +	INIT_LIST_HEAD_RCU(&pd->link);
> +	spin_lock(&cpu_pd_list_lock);
> +	list_add_rcu(&pd->link, &of_cpu_pd_list);
> +	spin_unlock(&cpu_pd_list_lock);
> +	pd->dn = dn;
> +
> +	/* Register the CPU genpd */
> +	pr_debug("adding %s as CPU PM domain.\n", pd->genpd->name);
> +	ret = of_pm_genpd_init(dn, pd->genpd, &simple_qos_governor, false);
> +	if (ret) {
> +		pr_err("Unable to initialize domain %s\n", dn->full_name);
> +		return ret;
> +	}
> +
> +	ret = of_genpd_add_provider_simple(dn, pd->genpd);
> +	if (ret)
> +		pr_warn("Unable to add genpd %s as provider\n",
> +				pd->genpd->name);
> +
> +	/* Attach the CPUs to the CPU PM domain */
> +	ret = of_pm_domain_attach_cpus(dn);
> +	if (ret)
> +		of_genpd_del_provider(dn);
> +
> +	return ret;
> +}
> +
> +/**
> + * of_init_cpu_pm_domain() - Initialize a CPU PM domain using the CPU pd
> + * provided
> + * @dn: PM domain provider device node
> + * @ops: CPU PM domain platform specific ops for callback
> + *
> + * This is a single step initialize the CPU PM domain with defaults,
> + * also register the genpd and attach CPUs to the genpd.

Returns?

> + */
> +struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
> +				const struct cpu_pd_ops *ops)
> +{
> +	struct cpu_pm_domain *pd;
> +	int ret;
> +
> +	if (!of_device_is_available(dn))
> +		return ERR_PTR(-ENODEV);
> +
> +	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return ERR_PTR(-ENOMEM);
> +
> +	pd->genpd = kzalloc(sizeof(*(pd->genpd)), GFP_KERNEL);
> +	if (!pd->genpd) {
> +		kfree(pd);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	pd->genpd->name = kstrndup(dn->full_name, CPU_PD_NAME_MAX, GFP_KERNEL);
> +	if (!pd->genpd->name) {
> +		kfree(pd->genpd);
> +		kfree(pd);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	if (ops) {
> +		pd->plat_ops.power_off = ops->power_off;
> +		pd->plat_ops.power_on = ops->power_on;
> +	}
> +
> +	ret = of_register_cpu_pm_domain(dn, pd);
> +	if (ret) {
> +		kfree(pd->genpd->name);
> +		kfree(pd->genpd);
> +		kfree(pd);
> +		return ERR_PTR(ret);

Maybe we can have a goto error path so that we don't duplicate
these kfree calls a bunch of times.

> +	}
> +
> +	return pd->genpd;
> +}
> +EXPORT_SYMBOL(of_init_cpu_pm_domain);

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
  2015-11-17 22:37   ` Lina Iyer
@ 2015-11-24 21:00     ` Stephen Boyd
  -1 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-24 21:00 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On 11/17, Lina Iyer wrote:
> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> index 9758b8d..617ce54 100644
> --- a/drivers/base/power/cpu-pd.c
> +++ b/drivers/base/power/cpu-pd.c
> @@ -18,6 +18,7 @@
>  #include <linux/device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_qos.h>

What's this added for?

>  #include <linux/rculist.h>
>  #include <linux/slab.h>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
@ 2015-11-24 21:00     ` Stephen Boyd
  0 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-24 21:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/17, Lina Iyer wrote:
> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> index 9758b8d..617ce54 100644
> --- a/drivers/base/power/cpu-pd.c
> +++ b/drivers/base/power/cpu-pd.c
> @@ -18,6 +18,7 @@
>  #include <linux/device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_qos.h>

What's this added for?

>  #include <linux/rculist.h>
>  #include <linux/slab.h>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
  2015-11-24 21:00     ` Stephen Boyd
@ 2015-11-25 14:13       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-25 14:13 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On Tue, Nov 24 2015 at 14:00 -0700, Stephen Boyd wrote:
>On 11/17, Lina Iyer wrote:
>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>> index 9758b8d..617ce54 100644
>> --- a/drivers/base/power/cpu-pd.c
>> +++ b/drivers/base/power/cpu-pd.c
>> @@ -18,6 +18,7 @@
>>  #include <linux/device.h>
>>  #include <linux/pm_runtime.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/pm_qos.h>
>
>What's this added for?
>
pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
Getting the PM QoS for the CPUs.

-- Lina

>>  #include <linux/rculist.h>
>>  #include <linux/slab.h>
>
>-- 
>Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>a Linux Foundation Collaborative Project

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

* [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
@ 2015-11-25 14:13       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-25 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 24 2015 at 14:00 -0700, Stephen Boyd wrote:
>On 11/17, Lina Iyer wrote:
>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>> index 9758b8d..617ce54 100644
>> --- a/drivers/base/power/cpu-pd.c
>> +++ b/drivers/base/power/cpu-pd.c
>> @@ -18,6 +18,7 @@
>>  #include <linux/device.h>
>>  #include <linux/pm_runtime.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/pm_qos.h>
>
>What's this added for?
>
pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
Getting the PM QoS for the CPUs.

-- Lina

>>  #include <linux/rculist.h>
>>  #include <linux/slab.h>
>
>-- 
>Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
  2015-11-25 14:13       ` Lina Iyer
@ 2015-11-25 19:12         ` Stephen Boyd
  -1 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-25 19:12 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On 11/25/15 06:13, Lina Iyer wrote:
> On Tue, Nov 24 2015 at 14:00 -0700, Stephen Boyd wrote:
>> On 11/17, Lina Iyer wrote:
>>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>>> index 9758b8d..617ce54 100644
>>> --- a/drivers/base/power/cpu-pd.c
>>> +++ b/drivers/base/power/cpu-pd.c
>>> @@ -18,6 +18,7 @@
>>>  #include <linux/device.h>
>>>  #include <linux/pm_runtime.h>
>>>  #include <linux/platform_device.h>
>>> +#include <linux/pm_qos.h>
>>
>> What's this added for?
>>
> pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
> Getting the PM QoS for the CPUs.
>

Ok. That function call is not added in this patch though.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
@ 2015-11-25 19:12         ` Stephen Boyd
  0 siblings, 0 replies; 166+ messages in thread
From: Stephen Boyd @ 2015-11-25 19:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/25/15 06:13, Lina Iyer wrote:
> On Tue, Nov 24 2015 at 14:00 -0700, Stephen Boyd wrote:
>> On 11/17, Lina Iyer wrote:
>>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>>> index 9758b8d..617ce54 100644
>>> --- a/drivers/base/power/cpu-pd.c
>>> +++ b/drivers/base/power/cpu-pd.c
>>> @@ -18,6 +18,7 @@
>>>  #include <linux/device.h>
>>>  #include <linux/pm_runtime.h>
>>>  #include <linux/platform_device.h>
>>> +#include <linux/pm_qos.h>
>>
>> What's this added for?
>>
> pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
> Getting the PM QoS for the CPUs.
>

Ok. That function call is not added in this patch though.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
  2015-11-25 19:12         ` Stephen Boyd
@ 2015-11-25 20:20           ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-25 20:20 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, linux-arm-msm, lorenzo.pieralisi,
	ahaslam, mtitinger

On Wed, Nov 25 2015 at 12:12 -0700, Stephen Boyd wrote:
>On 11/25/15 06:13, Lina Iyer wrote:
>> On Tue, Nov 24 2015 at 14:00 -0700, Stephen Boyd wrote:
>>> On 11/17, Lina Iyer wrote:
>>>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>>>> index 9758b8d..617ce54 100644
>>>> --- a/drivers/base/power/cpu-pd.c
>>>> +++ b/drivers/base/power/cpu-pd.c
>>>> @@ -18,6 +18,7 @@
>>>>  #include <linux/device.h>
>>>>  #include <linux/pm_runtime.h>
>>>>  #include <linux/platform_device.h>
>>>> +#include <linux/pm_qos.h>
>>>
>>> What's this added for?
>>>
>> pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>> Getting the PM QoS for the CPUs.
>>
>
>Ok. That function call is not added in this patch though.
>
Ah, right. Will fix.

>-- 
>Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>a Linux Foundation Collaborative Project
>

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

* [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain
@ 2015-11-25 20:20           ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-11-25 20:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 25 2015 at 12:12 -0700, Stephen Boyd wrote:
>On 11/25/15 06:13, Lina Iyer wrote:
>> On Tue, Nov 24 2015 at 14:00 -0700, Stephen Boyd wrote:
>>> On 11/17, Lina Iyer wrote:
>>>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>>>> index 9758b8d..617ce54 100644
>>>> --- a/drivers/base/power/cpu-pd.c
>>>> +++ b/drivers/base/power/cpu-pd.c
>>>> @@ -18,6 +18,7 @@
>>>>  #include <linux/device.h>
>>>>  #include <linux/pm_runtime.h>
>>>>  #include <linux/platform_device.h>
>>>> +#include <linux/pm_qos.h>
>>>
>>> What's this added for?
>>>
>> pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>> Getting the PM QoS for the CPUs.
>>
>
>Ok. That function call is not added in this patch though.
>
Ah, right. Will fix.

>-- 
>Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>a Linux Foundation Collaborative Project
>

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

* Re: [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
  2015-11-23 13:42         ` Lucas Stach
@ 2015-12-04 23:19           ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-04 23:19 UTC (permalink / raw)
  To: Lucas Stach; +Cc: linux-arm-kernel, linux-pm, linux-arm-msm, Axel Haslam

On Mon, Nov 23 2015 at 06:42 -0700, Lucas Stach wrote:
>Am Montag, den 23.11.2015, 14:31 +0100 schrieb Lucas Stach:
>> Am Mittwoch, den 18.11.2015, 07:57 -0700 schrieb Lina Iyer:
>> > From: Axel Haslam <ahaslam+renesas@baylibre.com>
>> >
>> > The generic_pm_domain structure uses an array of latencies to be able to
>> > declare multiple intermediate states.
>> >
>> > Declare a single "OFF" state with the default latencies So that the
>> > power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
>> > structure can be eventualy removed.
>> >
>> > Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
>> > Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> > [Lina: pm_genpd_init() argument change]
>> > ---
>> >  arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
>> >  1 file changed, 12 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
>> > index 8e7976a..b070e06 100644
>> > --- a/arch/arm/mach-imx/gpc.c
>> > +++ b/arch/arm/mach-imx/gpc.c
>> > @@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
>> >  	.name = "ARM",
>> >  };
>> >
>> > +static struct genpd_power_state imx6q_arm_domain_states[] = {
>>
>> Those states are for the PU, not the ARM domain.
>>
>> > +	{
>> > +		.name = "OFF",
>> > +		.power_off_latency_ns = 25000,
>> > +		.power_on_latency_ns = 2000000,
>> > +	},
>> > +};
>> > +
>> >  static struct pu_domain imx6q_pu_domain = {
>> >  	.base = {
>> >  		.name = "PU",
>> >  		.power_off = imx6q_pm_pu_power_off,
>> >  		.power_on = imx6q_pm_pu_power_on,
>> > -		.power_off_latency_ns = 25000,
>> > -		.power_on_latency_ns = 2000000,
>> > +		.gov = NULL,
>> > +		.status = GPD_STATE_POWER_OFF,
>>
>> The above 2 lines should not be needed. This is a static struct, so .gov
>> will already be NULL. status is set by pm_genpd_init() and the above
>> value is actively wrong.
>>
True.

>> > +		.states = imx6q_arm_domain_states,
>> > +		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
>> >  	},
>> >  };
>> >
>>
>> How urgent is this patch? I have a series to rework the GPC driver
>> almost ready and I could fold this change in directly if it's okay for
>> this to sit through a review of the rework.
>
>And I just noticed this depends on changes that are not already in
>v4.4-rc. Why is this sent as a single patch and not as part of the
>series adding multiple state support to genpd?
>
Sorry, since this is ARM 32, I had not comple tested it when I sent out
the series. I sent this out after I realized it.

Thanks,
Lina

>Regards,
>Lucas
>
>-- 
>Pengutronix e.K.             | Lucas Stach                 |
>Industrial Linux Solutions   | http://www.pengutronix.de/  |
>

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

* [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct.
@ 2015-12-04 23:19           ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-04 23:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 23 2015 at 06:42 -0700, Lucas Stach wrote:
>Am Montag, den 23.11.2015, 14:31 +0100 schrieb Lucas Stach:
>> Am Mittwoch, den 18.11.2015, 07:57 -0700 schrieb Lina Iyer:
>> > From: Axel Haslam <ahaslam+renesas@baylibre.com>
>> >
>> > The generic_pm_domain structure uses an array of latencies to be able to
>> > declare multiple intermediate states.
>> >
>> > Declare a single "OFF" state with the default latencies So that the
>> > power_off_latency_ns and power_on_latency_ns fields of generic_pm_domain
>> > structure can be eventualy removed.
>> >
>> > Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
>> > Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> > [Lina: pm_genpd_init() argument change]
>> > ---
>> >  arch/arm/mach-imx/gpc.c | 14 ++++++++++++--
>> >  1 file changed, 12 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
>> > index 8e7976a..b070e06 100644
>> > --- a/arch/arm/mach-imx/gpc.c
>> > +++ b/arch/arm/mach-imx/gpc.c
>> > @@ -368,13 +368,23 @@ static struct generic_pm_domain imx6q_arm_domain = {
>> >  	.name = "ARM",
>> >  };
>> >
>> > +static struct genpd_power_state imx6q_arm_domain_states[] = {
>>
>> Those states are for the PU, not the ARM domain.
>>
>> > +	{
>> > +		.name = "OFF",
>> > +		.power_off_latency_ns = 25000,
>> > +		.power_on_latency_ns = 2000000,
>> > +	},
>> > +};
>> > +
>> >  static struct pu_domain imx6q_pu_domain = {
>> >  	.base = {
>> >  		.name = "PU",
>> >  		.power_off = imx6q_pm_pu_power_off,
>> >  		.power_on = imx6q_pm_pu_power_on,
>> > -		.power_off_latency_ns = 25000,
>> > -		.power_on_latency_ns = 2000000,
>> > +		.gov = NULL,
>> > +		.status = GPD_STATE_POWER_OFF,
>>
>> The above 2 lines should not be needed. This is a static struct, so .gov
>> will already be NULL. status is set by pm_genpd_init() and the above
>> value is actively wrong.
>>
True.

>> > +		.states = imx6q_arm_domain_states,
>> > +		.state_count = ARRAY_SIZE(imx6q_arm_domain_states),
>> >  	},
>> >  };
>> >
>>
>> How urgent is this patch? I have a series to rework the GPC driver
>> almost ready and I could fold this change in directly if it's okay for
>> this to sit through a review of the rework.
>
>And I just noticed this depends on changes that are not already in
>v4.4-rc. Why is this sent as a single patch and not as part of the
>series adding multiple state support to genpd?
>
Sorry, since this is ARM 32, I had not comple tested it when I sent out
the series. I sent this out after I realized it.

Thanks,
Lina

>Regards,
>Lucas
>
>-- 
>Pengutronix e.K.             | Lucas Stach                 |
>Industrial Linux Solutions   | http://www.pengutronix.de/  |
>

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

* Re: [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-07 14:54     ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-12-07 14:54 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger, Rob Herring

Hi Lina,

On Tue, Nov 17, 2015 at 03:37:45PM -0700, Lina Iyer wrote:
> Architectures that support CPU domain control in the firmware specify
> the domain heirarchy as part of the topology nodes. Parse and initialize
> domains from the topology node for such architectures.
> 
> Cc: Rob Herring <robherring2@gmail.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Kevin Hilman <khilman@linaro.org>
> Cc: Ulf Hansson <ulf.hansson@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/base/power/cpu-pd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/cpu-pd.h      |  1 +
>  2 files changed, 77 insertions(+)
> 
> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> index e331ae6..2872c18 100644
> --- a/drivers/base/power/cpu-pd.c
> +++ b/drivers/base/power/cpu-pd.c
> @@ -429,3 +429,79 @@ int of_attach_cpu_pm_domain(struct device_node *dn)
>  	return 0;
>  }
>  EXPORT_SYMBOL(of_attach_cpu_pm_domain);
> +
> +static int of_parse_cpu_pd(struct device_node *cluster,
> +		const struct cpu_pd_ops *ops)
> +{
> +	struct device_node *domain_node;
> +	struct generic_pm_domain *genpd;
> +	char name[10];
> +	struct device_node *c;
> +	int i, ret;
> +
> +	for (i = 0; ; i++) {
> +		snprintf(name, sizeof(name), "cluster%d", i);
> +		c = of_get_child_by_name(cluster, name);
> +		if (!c)
> +			break;
> +
> +		domain_node = of_parse_phandle(c, "cluster", 0);
> +		if (!domain_node)
> +			return -1;
> +
> +		/* Initialize CPU PM domain domain at this level */
> +		genpd = of_init_cpu_pm_domain(domain_node, ops);
> +		if (IS_ERR(genpd))
> +			return -1;
> +
> +		/* Initialize and attach child domains */
> +		ret = of_parse_cpu_pd(c, ops);
> +
> +		/*
> +		 * Attach the domain to its parent after reading
> +		 * the children, so the mask of CPUs in this domain
> +		 * are setup correctly.
> +		 */
> +		if (!ret)
> +			of_attach_cpu_pm_domain(domain_node);
> +
> +		of_node_put(c);
> +		if (ret != 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
> + * topology node in DT.
> + *
> + * @ops: The PM domain suspend/resume ops for all the domains in the topology
> + */
> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
> +{
> +	struct device_node *cn, *map;
> +	int ret = 0;
> +
> +	cn = of_find_node_by_path("/cpus");
> +	if (!cn) {
> +		pr_err("No CPU information found in DT\n");
> +		return 0;
> +	}
> +
> +	map = of_get_child_by_name(cn, "cpu-map");
> +	if (!map)
> +		goto out;

I commented on this before, is this reliance on cpu-map necessary ?
Could not you just rely on the "power-domains" phandle in the cpu
nodes to build the cpumask for a specific power domain ? I think
you should try to decouple the concept of power domain from the cpu-map
cluster and I think this would also simplify your code in the process.

So to sum it up, I'd suggest you build the power domain cpumask by
enumerating the cpus pointing at a specific power-domain node.

Lorenzo

> +
> +	ret = of_parse_cpu_pd(map, ops);
> +	if (ret != 0)
> +		goto out_map;
> +
> +out_map:
> +	of_node_put(map);
> +out:
> +	of_node_put(cn);
> +	return ret;
> +}
> +EXPORT_SYMBOL(of_setup_cpu_domain_topology);
> diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
> index 489ee2f..e8290db 100644
> --- a/include/linux/cpu-pd.h
> +++ b/include/linux/cpu-pd.h
> @@ -32,4 +32,5 @@ struct cpu_pm_domain {
>  struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
>  		const struct cpu_pd_ops *ops);
>  int of_attach_cpu_pm_domain(struct device_node *dn);
> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
>  #endif /* __CPU_PD_H__ */
> -- 
> 2.1.4
> 

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
@ 2015-12-07 14:54     ` Lorenzo Pieralisi
  0 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-12-07 14:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lina,

On Tue, Nov 17, 2015 at 03:37:45PM -0700, Lina Iyer wrote:
> Architectures that support CPU domain control in the firmware specify
> the domain heirarchy as part of the topology nodes. Parse and initialize
> domains from the topology node for such architectures.
> 
> Cc: Rob Herring <robherring2@gmail.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Kevin Hilman <khilman@linaro.org>
> Cc: Ulf Hansson <ulf.hansson@linaro.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/base/power/cpu-pd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/cpu-pd.h      |  1 +
>  2 files changed, 77 insertions(+)
> 
> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
> index e331ae6..2872c18 100644
> --- a/drivers/base/power/cpu-pd.c
> +++ b/drivers/base/power/cpu-pd.c
> @@ -429,3 +429,79 @@ int of_attach_cpu_pm_domain(struct device_node *dn)
>  	return 0;
>  }
>  EXPORT_SYMBOL(of_attach_cpu_pm_domain);
> +
> +static int of_parse_cpu_pd(struct device_node *cluster,
> +		const struct cpu_pd_ops *ops)
> +{
> +	struct device_node *domain_node;
> +	struct generic_pm_domain *genpd;
> +	char name[10];
> +	struct device_node *c;
> +	int i, ret;
> +
> +	for (i = 0; ; i++) {
> +		snprintf(name, sizeof(name), "cluster%d", i);
> +		c = of_get_child_by_name(cluster, name);
> +		if (!c)
> +			break;
> +
> +		domain_node = of_parse_phandle(c, "cluster", 0);
> +		if (!domain_node)
> +			return -1;
> +
> +		/* Initialize CPU PM domain domain at this level */
> +		genpd = of_init_cpu_pm_domain(domain_node, ops);
> +		if (IS_ERR(genpd))
> +			return -1;
> +
> +		/* Initialize and attach child domains */
> +		ret = of_parse_cpu_pd(c, ops);
> +
> +		/*
> +		 * Attach the domain to its parent after reading
> +		 * the children, so the mask of CPUs in this domain
> +		 * are setup correctly.
> +		 */
> +		if (!ret)
> +			of_attach_cpu_pm_domain(domain_node);
> +
> +		of_node_put(c);
> +		if (ret != 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
> + * topology node in DT.
> + *
> + * @ops: The PM domain suspend/resume ops for all the domains in the topology
> + */
> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
> +{
> +	struct device_node *cn, *map;
> +	int ret = 0;
> +
> +	cn = of_find_node_by_path("/cpus");
> +	if (!cn) {
> +		pr_err("No CPU information found in DT\n");
> +		return 0;
> +	}
> +
> +	map = of_get_child_by_name(cn, "cpu-map");
> +	if (!map)
> +		goto out;

I commented on this before, is this reliance on cpu-map necessary ?
Could not you just rely on the "power-domains" phandle in the cpu
nodes to build the cpumask for a specific power domain ? I think
you should try to decouple the concept of power domain from the cpu-map
cluster and I think this would also simplify your code in the process.

So to sum it up, I'd suggest you build the power domain cpumask by
enumerating the cpus pointing at a specific power-domain node.

Lorenzo

> +
> +	ret = of_parse_cpu_pd(map, ops);
> +	if (ret != 0)
> +		goto out_map;
> +
> +out_map:
> +	of_node_put(map);
> +out:
> +	of_node_put(cn);
> +	return ret;
> +}
> +EXPORT_SYMBOL(of_setup_cpu_domain_topology);
> diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
> index 489ee2f..e8290db 100644
> --- a/include/linux/cpu-pd.h
> +++ b/include/linux/cpu-pd.h
> @@ -32,4 +32,5 @@ struct cpu_pm_domain {
>  struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
>  		const struct cpu_pd_ops *ops);
>  int of_attach_cpu_pm_domain(struct device_node *dn);
> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
>  #endif /* __CPU_PD_H__ */
> -- 
> 2.1.4
> 

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

* Re: [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
  2015-12-07 14:54     ` Lorenzo Pieralisi
@ 2015-12-08 18:05       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-08 18:05 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger, Rob Herring

On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
>Hi Lina,
>
>On Tue, Nov 17, 2015 at 03:37:45PM -0700, Lina Iyer wrote:
>> Architectures that support CPU domain control in the firmware specify
>> the domain heirarchy as part of the topology nodes. Parse and initialize
>> domains from the topology node for such architectures.
>>
>> Cc: Rob Herring <robherring2@gmail.com>
>> Cc: Stephen Boyd <sboyd@codeaurora.org>
>> Cc: Kevin Hilman <khilman@linaro.org>
>> Cc: Ulf Hansson <ulf.hansson@linaro.org>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/base/power/cpu-pd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/cpu-pd.h      |  1 +
>>  2 files changed, 77 insertions(+)
>>
>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>> index e331ae6..2872c18 100644
>> --- a/drivers/base/power/cpu-pd.c
>> +++ b/drivers/base/power/cpu-pd.c
>> @@ -429,3 +429,79 @@ int of_attach_cpu_pm_domain(struct device_node *dn)
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL(of_attach_cpu_pm_domain);
>> +
>> +static int of_parse_cpu_pd(struct device_node *cluster,
>> +		const struct cpu_pd_ops *ops)
>> +{
>> +	struct device_node *domain_node;
>> +	struct generic_pm_domain *genpd;
>> +	char name[10];
>> +	struct device_node *c;
>> +	int i, ret;
>> +
>> +	for (i = 0; ; i++) {
>> +		snprintf(name, sizeof(name), "cluster%d", i);
>> +		c = of_get_child_by_name(cluster, name);
>> +		if (!c)
>> +			break;
>> +
>> +		domain_node = of_parse_phandle(c, "cluster", 0);
>> +		if (!domain_node)
>> +			return -1;
>> +
>> +		/* Initialize CPU PM domain domain at this level */
>> +		genpd = of_init_cpu_pm_domain(domain_node, ops);
>> +		if (IS_ERR(genpd))
>> +			return -1;
>> +
>> +		/* Initialize and attach child domains */
>> +		ret = of_parse_cpu_pd(c, ops);
>> +
>> +		/*
>> +		 * Attach the domain to its parent after reading
>> +		 * the children, so the mask of CPUs in this domain
>> +		 * are setup correctly.
>> +		 */
>> +		if (!ret)
>> +			of_attach_cpu_pm_domain(domain_node);
>> +
>> +		of_node_put(c);
>> +		if (ret != 0)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
>> + * topology node in DT.
>> + *
>> + * @ops: The PM domain suspend/resume ops for all the domains in the topology
>> + */
>> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
>> +{
>> +	struct device_node *cn, *map;
>> +	int ret = 0;
>> +
>> +	cn = of_find_node_by_path("/cpus");
>> +	if (!cn) {
>> +		pr_err("No CPU information found in DT\n");
>> +		return 0;
>> +	}
>> +
>> +	map = of_get_child_by_name(cn, "cpu-map");
>> +	if (!map)
>> +		goto out;
>
>I commented on this before, is this reliance on cpu-map necessary ?
>Could not you just rely on the "power-domains" phandle in the cpu
>nodes to build the cpumask for a specific power domain ? I think
>you should try to decouple the concept of power domain from the cpu-map
>cluster and I think this would also simplify your code in the process.
>
Sorry, I missed seeing your comment on this earlier.

Hmm, it can be done, but I felt out of place to define just power
domains that have no devices in Linux, since they are handled in PSCI,
but also have no relation to PSCI. Hence, I felt cpu-map to be a good
place for the cluster domain. But I am not strongly inclined. I can
remove them from the cpu-map and keep them as separate nodes. However,
it would be nice to have a way to say these nodes are PSCI controlled.

Thanks,
Lina

>So to sum it up, I'd suggest you build the power domain cpumask by
>enumerating the cpus pointing at a specific power-domain node.
>

>> +
>> +	ret = of_parse_cpu_pd(map, ops);
>> +	if (ret != 0)
>> +		goto out_map;
>> +
>> +out_map:
>> +	of_node_put(map);
>> +out:
>> +	of_node_put(cn);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL(of_setup_cpu_domain_topology);
>> diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
>> index 489ee2f..e8290db 100644
>> --- a/include/linux/cpu-pd.h
>> +++ b/include/linux/cpu-pd.h
>> @@ -32,4 +32,5 @@ struct cpu_pm_domain {
>>  struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
>>  		const struct cpu_pd_ops *ops);
>>  int of_attach_cpu_pm_domain(struct device_node *dn);
>> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
>>  #endif /* __CPU_PD_H__ */
>> --
>> 2.1.4
>>

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
@ 2015-12-08 18:05       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-08 18:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
>Hi Lina,
>
>On Tue, Nov 17, 2015 at 03:37:45PM -0700, Lina Iyer wrote:
>> Architectures that support CPU domain control in the firmware specify
>> the domain heirarchy as part of the topology nodes. Parse and initialize
>> domains from the topology node for such architectures.
>>
>> Cc: Rob Herring <robherring2@gmail.com>
>> Cc: Stephen Boyd <sboyd@codeaurora.org>
>> Cc: Kevin Hilman <khilman@linaro.org>
>> Cc: Ulf Hansson <ulf.hansson@linaro.org>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/base/power/cpu-pd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/cpu-pd.h      |  1 +
>>  2 files changed, 77 insertions(+)
>>
>> diff --git a/drivers/base/power/cpu-pd.c b/drivers/base/power/cpu-pd.c
>> index e331ae6..2872c18 100644
>> --- a/drivers/base/power/cpu-pd.c
>> +++ b/drivers/base/power/cpu-pd.c
>> @@ -429,3 +429,79 @@ int of_attach_cpu_pm_domain(struct device_node *dn)
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL(of_attach_cpu_pm_domain);
>> +
>> +static int of_parse_cpu_pd(struct device_node *cluster,
>> +		const struct cpu_pd_ops *ops)
>> +{
>> +	struct device_node *domain_node;
>> +	struct generic_pm_domain *genpd;
>> +	char name[10];
>> +	struct device_node *c;
>> +	int i, ret;
>> +
>> +	for (i = 0; ; i++) {
>> +		snprintf(name, sizeof(name), "cluster%d", i);
>> +		c = of_get_child_by_name(cluster, name);
>> +		if (!c)
>> +			break;
>> +
>> +		domain_node = of_parse_phandle(c, "cluster", 0);
>> +		if (!domain_node)
>> +			return -1;
>> +
>> +		/* Initialize CPU PM domain domain at this level */
>> +		genpd = of_init_cpu_pm_domain(domain_node, ops);
>> +		if (IS_ERR(genpd))
>> +			return -1;
>> +
>> +		/* Initialize and attach child domains */
>> +		ret = of_parse_cpu_pd(c, ops);
>> +
>> +		/*
>> +		 * Attach the domain to its parent after reading
>> +		 * the children, so the mask of CPUs in this domain
>> +		 * are setup correctly.
>> +		 */
>> +		if (!ret)
>> +			of_attach_cpu_pm_domain(domain_node);
>> +
>> +		of_node_put(c);
>> +		if (ret != 0)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
>> + * topology node in DT.
>> + *
>> + * @ops: The PM domain suspend/resume ops for all the domains in the topology
>> + */
>> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
>> +{
>> +	struct device_node *cn, *map;
>> +	int ret = 0;
>> +
>> +	cn = of_find_node_by_path("/cpus");
>> +	if (!cn) {
>> +		pr_err("No CPU information found in DT\n");
>> +		return 0;
>> +	}
>> +
>> +	map = of_get_child_by_name(cn, "cpu-map");
>> +	if (!map)
>> +		goto out;
>
>I commented on this before, is this reliance on cpu-map necessary ?
>Could not you just rely on the "power-domains" phandle in the cpu
>nodes to build the cpumask for a specific power domain ? I think
>you should try to decouple the concept of power domain from the cpu-map
>cluster and I think this would also simplify your code in the process.
>
Sorry, I missed seeing your comment on this earlier.

Hmm, it can be done, but I felt out of place to define just power
domains that have no devices in Linux, since they are handled in PSCI,
but also have no relation to PSCI. Hence, I felt cpu-map to be a good
place for the cluster domain. But I am not strongly inclined. I can
remove them from the cpu-map and keep them as separate nodes. However,
it would be nice to have a way to say these nodes are PSCI controlled.

Thanks,
Lina

>So to sum it up, I'd suggest you build the power domain cpumask by
>enumerating the cpus pointing at a specific power-domain node.
>

>> +
>> +	ret = of_parse_cpu_pd(map, ops);
>> +	if (ret != 0)
>> +		goto out_map;
>> +
>> +out_map:
>> +	of_node_put(map);
>> +out:
>> +	of_node_put(cn);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL(of_setup_cpu_domain_topology);
>> diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
>> index 489ee2f..e8290db 100644
>> --- a/include/linux/cpu-pd.h
>> +++ b/include/linux/cpu-pd.h
>> @@ -32,4 +32,5 @@ struct cpu_pm_domain {
>>  struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
>>  		const struct cpu_pd_ops *ops);
>>  int of_attach_cpu_pm_domain(struct device_node *dn);
>> +int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
>>  #endif /* __CPU_PD_H__ */
>> --
>> 2.1.4
>>

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

* Re: [PATCH RFC 01/27] PM / Domains: core changes for multiple states
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-09 13:58     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-09 13:58 UTC (permalink / raw)
  To: Lina Iyer, Axel Haslam
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Marc Titinger, Axel Haslam

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>
> From: Axel Haslam <ahaslam@baylibre.com>
>
> Add the core changes to be able to declare multiple states.
> When trying to set a power domain to off, genpd will be able to choose
> from an array of states declared by the platform. The power on and off
> latencies are now tied to a state.

I would like to get an answer to *why* we need this.

For example, we should mention that some HWs supports these multiple
states - at least.

>
> States should be declared in ascending order from shallowest to deepest,

I guess *should* isn't good enough. Perhaps *shall* is better?

> deepest meaning the state which takes longer to enter and exit.
>
> the power_off and power_on function can use the 'state_idx' field of the
> generic_pm_domain structure, to distinguish between the different states
> and act accordingly.

This needs some more explanation.

First, please use the wording of "callbacks", like ->power_on() to
better describe what function you are talking about.
Second, what is "state_idx"? What's does it really tell the SOC PM
domain driver here?

>
> Example:
>
> static int pd1_power_on(struct generic_pm_domain *domain)
> {
>         /* domain->state_idx = state the domain is coming from */
> }
>
> static int pd1_power_off(struct generic_pm_domain *domain)
> {
>         /* domain->state_idx = desired powered off state */
> }
>
> const struct genpd_power_state pd_states[] = {
>         {
>                 .name = "RET",
>                 .power_on_latency_ns = ON_LATENCY_FAST,
>                 .power_off_latency_ns = OFF_LATENCY_FAST,
>         },
>         {
>                 .name = "DEEP_RET",
>                 .power_on_latency_ns = ON_LATENCY_MED,
>                 .power_off_latency_ns = OFF_LATENCY_MED,
>         },
>         {
>                 .name = "OFF",
>                 .power_on_latency_ns = ON_LATENCY_SLOW,
>                 .power_off_latency_ns = OFF_LATENCY_SLOW,
>         }
> };
>
> struct generic_pm_domain pd1 = {
>         .name = "PD1",
>         .power_on = pd1_power_on,
>         .power_off = pd1_power_off,
>         [...]
> };
>
> int xxx_init_pm_domain(){
>
>         pd1->state = copy_of(pd_states);
>         pd1->state_count = ARRAY_SIZE(pd_states);
>         pm_genpd_init(pd1, true);
>
> }

Well, even if the above describes this quite good, I think it better
belongs in the Documentation rather than in the change log.

Can we try to the improve the text in the change-log instead?

>
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> [Lina: Modified genpd state initialization and remove use of
> save_state_latency_ns in genpd timing data]
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/base/power/domain.c          | 136 +++++++++++++++++++++++++++++++++--
>  drivers/base/power/domain_governor.c |  13 +++-
>  include/linux/pm_domain.h            |  10 +++
>  3 files changed, 151 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index e03b1ad..3242854 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -34,6 +34,12 @@
>         __ret;                                                  \
>  })
>
> +#define GENPD_MAX_NAME_SIZE 20
> +
> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,

Please avoid forward declarations.

Also, we have just got rid of all *name* based genpd API/functions. I
don't want us to start adding another.

Or perhaps it's just the name of the function that I don't like!? :-)

> +                                      const struct genpd_power_state *st,
> +                                      unsigned int st_count);
> +
>  static LIST_HEAD(gpd_list);
>  static DEFINE_MUTEX(gpd_list_lock);
>
> @@ -102,6 +108,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
>
>  static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>  {
> +       unsigned int state_idx = genpd->state_idx;
>         ktime_t time_start;
>         s64 elapsed_ns;
>         int ret;
> @@ -118,10 +125,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>                 return ret;
>
>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
> -       if (elapsed_ns <= genpd->power_on_latency_ns)
> +       if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
>                 return ret;
>
> -       genpd->power_on_latency_ns = elapsed_ns;
> +       genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
>         genpd->max_off_time_changed = true;
>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>                  genpd->name, "on", elapsed_ns);
> @@ -131,6 +138,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>
>  static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>  {
> +       unsigned int state_idx = genpd->state_idx;
>         ktime_t time_start;
>         s64 elapsed_ns;
>         int ret;
> @@ -147,10 +155,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>                 return ret;
>
>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
> -       if (elapsed_ns <= genpd->power_off_latency_ns)
> +       if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
>                 return ret;
>
> -       genpd->power_off_latency_ns = elapsed_ns;
> +       genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
>         genpd->max_off_time_changed = true;
>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>                  genpd->name, "off", elapsed_ns);
> @@ -582,6 +590,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
>             || atomic_read(&genpd->sd_count) > 0)
>                 return;
>
> +       /* Choose the deepest state when suspending */
> +       genpd->state_idx = genpd->state_count - 1;
>         genpd_power_off(genpd, timed);
>
>         genpd->status = GPD_STATE_POWER_OFF;
> @@ -1205,6 +1215,61 @@ static void genpd_free_dev_data(struct device *dev,
>         dev_pm_put_subsys_data(dev);
>  }
>
> +static int genpd_alloc_states_data(struct generic_pm_domain *genpd,

In this patch I would rather just add *one* new "alloc" function and
name it like below.

static int genpd_alloc_default_state(struct generic_pm_domain *genpd)

I assume the name I suggest for it, indicates what it needs to do and
*not* needs to do.

> +                                  const struct genpd_power_state *st,
> +                                  unsigned int st_count)
> +{
> +       int ret = 0;
> +       unsigned int i;
> +
> +       if (IS_ERR_OR_NULL(genpd)) {
> +               ret = -EINVAL;
> +               goto err;
> +       }
> +
> +       if (!st || (st_count < 1)) {
> +               ret = -EINVAL;
> +               goto err;
> +       }
> +
> +       /* Allocate the local memory to keep the states for this genpd */
> +       genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
> +       if (!genpd->states) {
> +               ret = -ENOMEM;
> +               goto err;
> +       }
> +
> +       for (i = 0; i < st_count; i++) {
> +               genpd->states[i].power_on_latency_ns =
> +                       st[i].power_on_latency_ns;
> +               genpd->states[i].power_off_latency_ns =
> +                       st[i].power_off_latency_ns;
> +       }
> +
> +       /*
> +        * Copy the latency values To keep compatibility with
> +        * platforms that are not converted to use the multiple states.
> +        * This will be removed once all platforms are converted to use
> +        * multiple states. note that non converted platforms will use the
> +        * default single off state.
> +        */
> +       if (genpd->power_on_latency_ns != 0)
> +               genpd->states[0].power_on_latency_ns =
> +                               genpd->power_on_latency_ns;
> +
> +       if (genpd->power_off_latency_ns != 0)
> +               genpd->states[0].power_off_latency_ns =
> +                               genpd->power_off_latency_ns;
> +
> +       genpd->state_count = st_count;
> +
> +       /* to save memory, Name allocation will happen if debug is enabled */

Urgh. :-)

I instead suggest we skip the entire "name" attribute" and just use
the state_idx to provide the same information.

For sure at this point, this information won't be interpreted by
"anybody". Reading an integer value instead of string, shouldn't be
that difficult to understand.

Future wise, if we see that it could be beneficial to add the "name"
attribute, we can do that then.

Removing the name attribute will also simplify this patch, quite much.
Can you please do that.

> +       pm_genpd_alloc_states_names(genpd, st, st_count);
> +
> +err:
> +       return ret;
> +}
> +
>  /**
>   * __pm_genpd_add_device - Add a device to an I/O PM domain.
>   * @genpd: PM domain to add the device to.
> @@ -1459,6 +1524,15 @@ static int pm_genpd_default_restore_state(struct device *dev)
>  void pm_genpd_init(struct generic_pm_domain *genpd,
>                    struct dev_power_governor *gov, bool is_off)
>  {
> +       int ret;
> +       static const struct genpd_power_state genpd_default_off[] = {
> +               {
> +                       .name = "OFF",
> +                       .power_off_latency_ns = 0,
> +                       .power_on_latency_ns = 0,
> +               },
> +       };

I suggest you remove this and instead handle that within
genpd_alloc_default_state().

> +
>         if (IS_ERR_OR_NULL(genpd))
>                 return;
>
> @@ -1503,6 +1577,19 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>                 genpd->dev_ops.start = pm_clk_resume;
>         }
>
> +       /*
> +        * Allocate the default state if genpd states
> +        * are not already defined.
> +        */
> +       if (!genpd->state_count) {
> +               ret = genpd_alloc_states_data(genpd, genpd_default_off, 1);

Call the new "genpd_alloc_default_state()" instead.

> +               if (ret)
> +                       return;
> +       }
> +
> +       /* Assume the deepest state on init*/
> +       genpd->state_idx = genpd->state_count - 1;

When the PM domain is powered on, in other words the genpd->status ==
GPD_STATE_ACTIVE, I guess this value doesn't matter much.

Although, what if the PM domain is powered off, don't you need to
respect the value that might have been assigned by the SoC PM domain
driver? Else you may at the next power on, indicate that you are
coming from a state that's not the correct one.

Perhaps, you should only set genpd->state_idx = 0, from
genpd_alloc_default_state() and in the other case leave the value as
is?

> +
>         mutex_lock(&gpd_list_lock);
>         list_add(&genpd->gpd_list_node, &gpd_list);
>         mutex_unlock(&gpd_list_lock);
> @@ -1822,6 +1909,33 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>  #include <linux/kobject.h>
>  static struct dentry *pm_genpd_debugfs_dir;
>
> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
> +                                      const struct genpd_power_state *st,
> +                                      unsigned int st_count)
> +{
> +       unsigned int i;
> +
> +       if (IS_ERR_OR_NULL(genpd))
> +               return -EINVAL;
> +
> +       if (genpd->state_count != st_count) {
> +               pr_err("Invalid allocated state count\n");
> +               return -EINVAL;
> +       }
> +
> +       for (i = 0; i < st_count; i++) {
> +               genpd->states[i].name = kstrndup(st[i].name,
> +                               GENPD_MAX_NAME_SIZE, GFP_KERNEL);
> +               if (!genpd->states[i].name) {
> +                       pr_err("%s Failed to allocate state %d name.\n",
> +                               genpd->name, i);
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
>  /*
>   * TODO: This function is a slightly modified version of rtpm_status_show
>   * from sysfs.c, so generalize it.
> @@ -1855,6 +1969,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
>                 [GPD_STATE_ACTIVE] = "on",
>                 [GPD_STATE_POWER_OFF] = "off"
>         };
> +       unsigned int state_idx = genpd->state_idx;
>         struct pm_domain_data *pm_data;
>         const char *kobj_path;
>         struct gpd_link *link;
> @@ -1866,7 +1981,11 @@ static int pm_genpd_summary_one(struct seq_file *s,
>
>         if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
>                 goto exit;
> -       seq_printf(s, "%-30s  %-15s ", genpd->name, status_lookup[genpd->status]);
> +
> +       seq_printf(s, "%-30s  %-15s  ", genpd->name,
> +                  (genpd->status == GPD_STATE_POWER_OFF) ?
> +                  genpd->states[state_idx].name :
> +                  status_lookup[genpd->status]);
>
>         /*
>          * Modifications on the list require holding locks on both
> @@ -1954,4 +2073,11 @@ static void __exit pm_genpd_debug_exit(void)
>         debugfs_remove_recursive(pm_genpd_debugfs_dir);
>  }
>  __exitcall(pm_genpd_debug_exit);
> +#else
> +static inline int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
> +                                       const struct genpd_power_state *st,
> +                                       unsigned int st_count)
> +{
> +       return 0;
> +}
>  #endif /* CONFIG_PM_ADVANCED_DEBUG */
> diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
> index e60dd12..b4984f5 100644
> --- a/drivers/base/power/domain_governor.c
> +++ b/drivers/base/power/domain_governor.c
> @@ -125,8 +125,12 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>                 return genpd->cached_power_down_ok;
>         }
>
> -       off_on_time_ns = genpd->power_off_latency_ns +
> -                               genpd->power_on_latency_ns;
> +       /*
> +        * Use the only available state, until multiple state support is added
> +        * to the governor.
> +        */

So you want to delay this step into a later patch. I am fine with
that, but you need to state that in the change-log.

Perhaps it's better to say that we will always try with the
shallowest/deepest off state, and just ignore the other states in this
phase?

> +       off_on_time_ns = genpd->states[0].power_off_latency_ns +
> +                               genpd->states[0].power_on_latency_ns;

If you think my above idea seems reasonable, that should change the above to:

off_on_time_ns = genpd->states[genpd->state_count - 1].power_off_latency_ns +
     genpd->states[genpd->state_count - 1].power_on_latency_ns;

>
>         min_off_time_ns = -1;
>         /*
> @@ -203,8 +207,11 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>          * The difference between the computed minimum subdomain or device off
>          * time and the time needed to turn the domain on is the maximum
>          * theoretical time this domain can spend in the "off" state.
> +        * Use the only available state, until multiple state support is added
> +        * to the governor.
>          */
> -       genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
> +       genpd->max_off_time_ns = min_off_time_ns -
> +               genpd->states[0].power_on_latency_ns;

Ditto.

>         return true;
>  }
>
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index ba4ced3..11763cf 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -37,6 +37,12 @@ struct gpd_dev_ops {
>         bool (*active_wakeup)(struct device *dev);
>  };
>
> +struct genpd_power_state {
> +       char *name;

As stated, suggest to remove "name".

> +       s64 power_off_latency_ns;
> +       s64 power_on_latency_ns;
> +};
> +
>  struct generic_pm_domain {
>         struct dev_pm_domain domain;    /* PM domain operations */
>         struct list_head gpd_list_node; /* Node in the global PM domains list */
> @@ -66,6 +72,10 @@ struct generic_pm_domain {
>         void (*detach_dev)(struct generic_pm_domain *domain,
>                            struct device *dev);
>         unsigned int flags;             /* Bit field of configs for genpd */
> +       struct genpd_power_state *states;
> +       unsigned int state_count; /* number of states */
> +       unsigned int state_idx; /* state that genpd will go to when off */
> +
>  };
>
>  static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
> --
> 2.1.4
>

Kind regards
Uffe

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

* [PATCH RFC 01/27] PM / Domains: core changes for multiple states
@ 2015-12-09 13:58     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-09 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>
> From: Axel Haslam <ahaslam@baylibre.com>
>
> Add the core changes to be able to declare multiple states.
> When trying to set a power domain to off, genpd will be able to choose
> from an array of states declared by the platform. The power on and off
> latencies are now tied to a state.

I would like to get an answer to *why* we need this.

For example, we should mention that some HWs supports these multiple
states - at least.

>
> States should be declared in ascending order from shallowest to deepest,

I guess *should* isn't good enough. Perhaps *shall* is better?

> deepest meaning the state which takes longer to enter and exit.
>
> the power_off and power_on function can use the 'state_idx' field of the
> generic_pm_domain structure, to distinguish between the different states
> and act accordingly.

This needs some more explanation.

First, please use the wording of "callbacks", like ->power_on() to
better describe what function you are talking about.
Second, what is "state_idx"? What's does it really tell the SOC PM
domain driver here?

>
> Example:
>
> static int pd1_power_on(struct generic_pm_domain *domain)
> {
>         /* domain->state_idx = state the domain is coming from */
> }
>
> static int pd1_power_off(struct generic_pm_domain *domain)
> {
>         /* domain->state_idx = desired powered off state */
> }
>
> const struct genpd_power_state pd_states[] = {
>         {
>                 .name = "RET",
>                 .power_on_latency_ns = ON_LATENCY_FAST,
>                 .power_off_latency_ns = OFF_LATENCY_FAST,
>         },
>         {
>                 .name = "DEEP_RET",
>                 .power_on_latency_ns = ON_LATENCY_MED,
>                 .power_off_latency_ns = OFF_LATENCY_MED,
>         },
>         {
>                 .name = "OFF",
>                 .power_on_latency_ns = ON_LATENCY_SLOW,
>                 .power_off_latency_ns = OFF_LATENCY_SLOW,
>         }
> };
>
> struct generic_pm_domain pd1 = {
>         .name = "PD1",
>         .power_on = pd1_power_on,
>         .power_off = pd1_power_off,
>         [...]
> };
>
> int xxx_init_pm_domain(){
>
>         pd1->state = copy_of(pd_states);
>         pd1->state_count = ARRAY_SIZE(pd_states);
>         pm_genpd_init(pd1, true);
>
> }

Well, even if the above describes this quite good, I think it better
belongs in the Documentation rather than in the change log.

Can we try to the improve the text in the change-log instead?

>
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> [Lina: Modified genpd state initialization and remove use of
> save_state_latency_ns in genpd timing data]
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  drivers/base/power/domain.c          | 136 +++++++++++++++++++++++++++++++++--
>  drivers/base/power/domain_governor.c |  13 +++-
>  include/linux/pm_domain.h            |  10 +++
>  3 files changed, 151 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index e03b1ad..3242854 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -34,6 +34,12 @@
>         __ret;                                                  \
>  })
>
> +#define GENPD_MAX_NAME_SIZE 20
> +
> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,

Please avoid forward declarations.

Also, we have just got rid of all *name* based genpd API/functions. I
don't want us to start adding another.

Or perhaps it's just the name of the function that I don't like!? :-)

> +                                      const struct genpd_power_state *st,
> +                                      unsigned int st_count);
> +
>  static LIST_HEAD(gpd_list);
>  static DEFINE_MUTEX(gpd_list_lock);
>
> @@ -102,6 +108,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
>
>  static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>  {
> +       unsigned int state_idx = genpd->state_idx;
>         ktime_t time_start;
>         s64 elapsed_ns;
>         int ret;
> @@ -118,10 +125,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>                 return ret;
>
>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
> -       if (elapsed_ns <= genpd->power_on_latency_ns)
> +       if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
>                 return ret;
>
> -       genpd->power_on_latency_ns = elapsed_ns;
> +       genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
>         genpd->max_off_time_changed = true;
>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>                  genpd->name, "on", elapsed_ns);
> @@ -131,6 +138,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>
>  static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>  {
> +       unsigned int state_idx = genpd->state_idx;
>         ktime_t time_start;
>         s64 elapsed_ns;
>         int ret;
> @@ -147,10 +155,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>                 return ret;
>
>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
> -       if (elapsed_ns <= genpd->power_off_latency_ns)
> +       if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
>                 return ret;
>
> -       genpd->power_off_latency_ns = elapsed_ns;
> +       genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
>         genpd->max_off_time_changed = true;
>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>                  genpd->name, "off", elapsed_ns);
> @@ -582,6 +590,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
>             || atomic_read(&genpd->sd_count) > 0)
>                 return;
>
> +       /* Choose the deepest state when suspending */
> +       genpd->state_idx = genpd->state_count - 1;
>         genpd_power_off(genpd, timed);
>
>         genpd->status = GPD_STATE_POWER_OFF;
> @@ -1205,6 +1215,61 @@ static void genpd_free_dev_data(struct device *dev,
>         dev_pm_put_subsys_data(dev);
>  }
>
> +static int genpd_alloc_states_data(struct generic_pm_domain *genpd,

In this patch I would rather just add *one* new "alloc" function and
name it like below.

static int genpd_alloc_default_state(struct generic_pm_domain *genpd)

I assume the name I suggest for it, indicates what it needs to do and
*not* needs to do.

> +                                  const struct genpd_power_state *st,
> +                                  unsigned int st_count)
> +{
> +       int ret = 0;
> +       unsigned int i;
> +
> +       if (IS_ERR_OR_NULL(genpd)) {
> +               ret = -EINVAL;
> +               goto err;
> +       }
> +
> +       if (!st || (st_count < 1)) {
> +               ret = -EINVAL;
> +               goto err;
> +       }
> +
> +       /* Allocate the local memory to keep the states for this genpd */
> +       genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
> +       if (!genpd->states) {
> +               ret = -ENOMEM;
> +               goto err;
> +       }
> +
> +       for (i = 0; i < st_count; i++) {
> +               genpd->states[i].power_on_latency_ns =
> +                       st[i].power_on_latency_ns;
> +               genpd->states[i].power_off_latency_ns =
> +                       st[i].power_off_latency_ns;
> +       }
> +
> +       /*
> +        * Copy the latency values To keep compatibility with
> +        * platforms that are not converted to use the multiple states.
> +        * This will be removed once all platforms are converted to use
> +        * multiple states. note that non converted platforms will use the
> +        * default single off state.
> +        */
> +       if (genpd->power_on_latency_ns != 0)
> +               genpd->states[0].power_on_latency_ns =
> +                               genpd->power_on_latency_ns;
> +
> +       if (genpd->power_off_latency_ns != 0)
> +               genpd->states[0].power_off_latency_ns =
> +                               genpd->power_off_latency_ns;
> +
> +       genpd->state_count = st_count;
> +
> +       /* to save memory, Name allocation will happen if debug is enabled */

Urgh. :-)

I instead suggest we skip the entire "name" attribute" and just use
the state_idx to provide the same information.

For sure at this point, this information won't be interpreted by
"anybody". Reading an integer value instead of string, shouldn't be
that difficult to understand.

Future wise, if we see that it could be beneficial to add the "name"
attribute, we can do that then.

Removing the name attribute will also simplify this patch, quite much.
Can you please do that.

> +       pm_genpd_alloc_states_names(genpd, st, st_count);
> +
> +err:
> +       return ret;
> +}
> +
>  /**
>   * __pm_genpd_add_device - Add a device to an I/O PM domain.
>   * @genpd: PM domain to add the device to.
> @@ -1459,6 +1524,15 @@ static int pm_genpd_default_restore_state(struct device *dev)
>  void pm_genpd_init(struct generic_pm_domain *genpd,
>                    struct dev_power_governor *gov, bool is_off)
>  {
> +       int ret;
> +       static const struct genpd_power_state genpd_default_off[] = {
> +               {
> +                       .name = "OFF",
> +                       .power_off_latency_ns = 0,
> +                       .power_on_latency_ns = 0,
> +               },
> +       };

I suggest you remove this and instead handle that within
genpd_alloc_default_state().

> +
>         if (IS_ERR_OR_NULL(genpd))
>                 return;
>
> @@ -1503,6 +1577,19 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>                 genpd->dev_ops.start = pm_clk_resume;
>         }
>
> +       /*
> +        * Allocate the default state if genpd states
> +        * are not already defined.
> +        */
> +       if (!genpd->state_count) {
> +               ret = genpd_alloc_states_data(genpd, genpd_default_off, 1);

Call the new "genpd_alloc_default_state()" instead.

> +               if (ret)
> +                       return;
> +       }
> +
> +       /* Assume the deepest state on init*/
> +       genpd->state_idx = genpd->state_count - 1;

When the PM domain is powered on, in other words the genpd->status ==
GPD_STATE_ACTIVE, I guess this value doesn't matter much.

Although, what if the PM domain is powered off, don't you need to
respect the value that might have been assigned by the SoC PM domain
driver? Else you may at the next power on, indicate that you are
coming from a state that's not the correct one.

Perhaps, you should only set genpd->state_idx = 0, from
genpd_alloc_default_state() and in the other case leave the value as
is?

> +
>         mutex_lock(&gpd_list_lock);
>         list_add(&genpd->gpd_list_node, &gpd_list);
>         mutex_unlock(&gpd_list_lock);
> @@ -1822,6 +1909,33 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>  #include <linux/kobject.h>
>  static struct dentry *pm_genpd_debugfs_dir;
>
> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
> +                                      const struct genpd_power_state *st,
> +                                      unsigned int st_count)
> +{
> +       unsigned int i;
> +
> +       if (IS_ERR_OR_NULL(genpd))
> +               return -EINVAL;
> +
> +       if (genpd->state_count != st_count) {
> +               pr_err("Invalid allocated state count\n");
> +               return -EINVAL;
> +       }
> +
> +       for (i = 0; i < st_count; i++) {
> +               genpd->states[i].name = kstrndup(st[i].name,
> +                               GENPD_MAX_NAME_SIZE, GFP_KERNEL);
> +               if (!genpd->states[i].name) {
> +                       pr_err("%s Failed to allocate state %d name.\n",
> +                               genpd->name, i);
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
>  /*
>   * TODO: This function is a slightly modified version of rtpm_status_show
>   * from sysfs.c, so generalize it.
> @@ -1855,6 +1969,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
>                 [GPD_STATE_ACTIVE] = "on",
>                 [GPD_STATE_POWER_OFF] = "off"
>         };
> +       unsigned int state_idx = genpd->state_idx;
>         struct pm_domain_data *pm_data;
>         const char *kobj_path;
>         struct gpd_link *link;
> @@ -1866,7 +1981,11 @@ static int pm_genpd_summary_one(struct seq_file *s,
>
>         if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
>                 goto exit;
> -       seq_printf(s, "%-30s  %-15s ", genpd->name, status_lookup[genpd->status]);
> +
> +       seq_printf(s, "%-30s  %-15s  ", genpd->name,
> +                  (genpd->status == GPD_STATE_POWER_OFF) ?
> +                  genpd->states[state_idx].name :
> +                  status_lookup[genpd->status]);
>
>         /*
>          * Modifications on the list require holding locks on both
> @@ -1954,4 +2073,11 @@ static void __exit pm_genpd_debug_exit(void)
>         debugfs_remove_recursive(pm_genpd_debugfs_dir);
>  }
>  __exitcall(pm_genpd_debug_exit);
> +#else
> +static inline int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
> +                                       const struct genpd_power_state *st,
> +                                       unsigned int st_count)
> +{
> +       return 0;
> +}
>  #endif /* CONFIG_PM_ADVANCED_DEBUG */
> diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
> index e60dd12..b4984f5 100644
> --- a/drivers/base/power/domain_governor.c
> +++ b/drivers/base/power/domain_governor.c
> @@ -125,8 +125,12 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>                 return genpd->cached_power_down_ok;
>         }
>
> -       off_on_time_ns = genpd->power_off_latency_ns +
> -                               genpd->power_on_latency_ns;
> +       /*
> +        * Use the only available state, until multiple state support is added
> +        * to the governor.
> +        */

So you want to delay this step into a later patch. I am fine with
that, but you need to state that in the change-log.

Perhaps it's better to say that we will always try with the
shallowest/deepest off state, and just ignore the other states in this
phase?

> +       off_on_time_ns = genpd->states[0].power_off_latency_ns +
> +                               genpd->states[0].power_on_latency_ns;

If you think my above idea seems reasonable, that should change the above to:

off_on_time_ns = genpd->states[genpd->state_count - 1].power_off_latency_ns +
     genpd->states[genpd->state_count - 1].power_on_latency_ns;

>
>         min_off_time_ns = -1;
>         /*
> @@ -203,8 +207,11 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>          * The difference between the computed minimum subdomain or device off
>          * time and the time needed to turn the domain on is the maximum
>          * theoretical time this domain can spend in the "off" state.
> +        * Use the only available state, until multiple state support is added
> +        * to the governor.
>          */
> -       genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
> +       genpd->max_off_time_ns = min_off_time_ns -
> +               genpd->states[0].power_on_latency_ns;

Ditto.

>         return true;
>  }
>
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index ba4ced3..11763cf 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -37,6 +37,12 @@ struct gpd_dev_ops {
>         bool (*active_wakeup)(struct device *dev);
>  };
>
> +struct genpd_power_state {
> +       char *name;

As stated, suggest to remove "name".

> +       s64 power_off_latency_ns;
> +       s64 power_on_latency_ns;
> +};
> +
>  struct generic_pm_domain {
>         struct dev_pm_domain domain;    /* PM domain operations */
>         struct list_head gpd_list_node; /* Node in the global PM domains list */
> @@ -66,6 +72,10 @@ struct generic_pm_domain {
>         void (*detach_dev)(struct generic_pm_domain *domain,
>                            struct device *dev);
>         unsigned int flags;             /* Bit field of configs for genpd */
> +       struct genpd_power_state *states;
> +       unsigned int state_count; /* number of states */
> +       unsigned int state_idx; /* state that genpd will go to when off */
> +
>  };
>
>  static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
> --
> 2.1.4
>

Kind regards
Uffe

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

* Re: [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-10 16:53     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-10 16:53 UTC (permalink / raw)
  To: Lina Iyer, Marc Titinger
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Marc Titinger <mtitinger+renesas@baylibre.com>
>
> From: Marc Titinger <mtitinger@baylibre.com>
>
> This patch allows cluster-level idle-states to being soaked in as
> generic domain power states, in order for the domain governor to chose
> the most efficient power state compatible with the device constraints.

That was possible before this patch, although you are now making it
possible to describe this in DT and also modifying genpd to parse this
information.

Also, I don't get what this has to do with the governor. Of course
that governor needs to care about the multiple states you added in
patch1, but it should do that no matter if the information comes from
DT or not, right.

Please re-phrase this to make it bit more clear.

> Similarly, devices can register power-states into the cluster domain, in
> a manner consistent with idle-states.

I don't get this. Can you please elaborate?

>
> This is a attempt to address device-retention states for devices that
> are not hooked to runtime-pm, but feature a retention state handled by
> the same firmware that handles idle-states. For instance a L2 caches.

I guess whether devices may use runtime PM or not, they still can be
attached to a PM domain with multiple power states?

>
> With Juno, in this example the idle-state 'cluster-sleep-0 ' is known
> from each cluster generic domain, as the deepest sate.
>
> cat /sys/kernel/debug/pm_genpd/*
>
> Domain             State name        Enter (ns) / Exit (ns)
> -------------------------------------------------------------
> a53_pd               cluster-sleep-0      1500000 / 800000
> a57_pd               cluster-sleep-0      1500000 / 800000
>
> domain                      status pstate     slaves
> /device                                      runtime status
> -----------------------------------------------------------------------
> a53_pd                          on
> /devices/system/cpu/cpu0                            active
> /devices/system/cpu/cpu3                            suspended
> /devices/system/cpu/cpu4                            suspended
> /devices/system/cpu/cpu5                            suspended
> /devices/platform/D1                                suspended
> a57_pd                          cluster-sleep-0
> /devices/system/cpu/cpu1                            suspended
> /devices/system/cpu/cpu2                            suspended
>
> Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> [Lina: removed dependency on dynamic states, simplified initalization,
> added of_pm_genpd_init() API]
> ---
>  .../devicetree/bindings/power/power_domain.txt     |  63 ++++++++++

Please split the documentation of the suggested new DT bindings into a
separate patch that is preceding this one.

Also, you need to send it to the DT maintainers.

>  drivers/base/power/domain.c                        | 128 +++++++++++++++++++++
>  include/linux/pm_domain.h                          |   6 +
>  3 files changed, 197 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index 025b5e7..e2f542e 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -29,6 +29,44 @@ Optional properties:
>     specified by this binding. More details about power domain specifier are
>     available in the next section.
>
> +- power-states : A phandle of an idle-state that shall be soaked into a
> +                generic domain power state. The power-state shall be
> +               compatible with "linux,domain-state".

Why mention the Linux specific "generic power domain" here?

Let's instead try to describe this without using specific terminology
from Linux.

> +
> +==Power state==
> +
> +A PM domain power state describes an idle state of a domain and must be
> +have the following properties -
> +
> +       - compatible
> +               Usage: Required
> +               Value type: <stringlist>
> +               Definition: Must be "linux,domain-state"

Why do you need a compatible string?

You already have the phandle available, I suppose you can use that
instead of parsing for a new compatible string.

> +
> +       - entry-latency-us
> +               Usage: Not required if wakeup-latency-us is provided.
> +               Value type: <prop-encoded-array>
> +               Definition: u32 value representing worst case latency in
> +               microseconds required to enter the idle state.
> +               The exit-latency-us duration may be guaranteed
> +               only after entry-latency-us has passed.
> +
> +       - exit-latency-us
> +               Usage: Not required if wakeup-latency-us is provided.
> +               Value type: <prop-encoded-array>
> +               Definition: u32 value representing worst case latency
> +               in microseconds required to exit the idle state.
> +
> +       - wakeup-latency-us:
> +               Usage: Not required if entry-latency-us and exit-latency-us
> +               are provided.
> +               Value type: <prop-encoded-array>
> +               Definition: u32 value representing maximum delay between the
> +               signaling the wakeup of the domain and the domain resuming
> +               regular operation.
> +               If omitted, this is assumed to be equal to:
> +                       entry-latency-us + exit-latency-us

I think we should decide which of the two alternatives to use, we
shouldn't make it more complicated than needed.

> +
>  Example:
>
>         power: power-controller@12340000 {
> @@ -55,6 +93,31 @@ Example 2:
>                 #power-domain-cells = <1>;
>         };
>
> +Example 3:
> +
> +       pm-domains {
> +               a57_pd: a57_pd@ {
> +                       /* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/
> +                       compatible = "arm,pd","arm,cortex-a57";
> +                       #power-domain-cells = <0>;
> +                       power-states = <&CLUSTER_SLEEP_0>;
> +               };
> +
> +               a53_pd: a53_pd@ {
> +                       /* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/
> +                       compatible = "arm,pd","arm,cortex-a53";
> +                       #power-domain-cells = <0>;
> +                       power-states = <&CLUSTER_SLEEP_0>;
> +               };
> +
> +               CLUSTER_SLEEP_0: power-state@0 {
> +                       compatible = "pm-domain,power-state";
> +                       entry-latency-us = <1000>;
> +                       exit-latency-us = <2000>;
> +               };

I think we should also cover the case when power-controller has
"#power-domain-cells = <[n>0]>".

Perhaps extending the first example is then better than adding a new one!?

> +       };
> +
> +
>  The nodes above define two power controllers: 'parent' and 'child'.
>  Domains created by the 'child' power controller are subdomains of '0' power
>  domain provided by the 'parent' power controller.
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 3242854..fe1be88 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -35,6 +35,7 @@
>  })
>
>  #define GENPD_MAX_NAME_SIZE 20
> +#define GENPD_MAX_DOMAIN_STATES 10

Instead of setting a hard limit, let's pre-parse the DTB to get the
number of power states. In that way, it should be fairly easy to
convert the below code to be more dynamic.

>
>  static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>                                        const struct genpd_power_state *st,
> @@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev)
>         return cb ? cb(dev) : 0;
>  }
>
> +static const struct of_device_id power_state_match[] = {
> +       { .compatible = "linux,domain-state" },
> +       { }
> +};
> +
> +static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
> +                                          struct device_node *state_node)
> +{
> +       const struct of_device_id *match_id;
> +       int err = 0;
> +       u32 latency;
> +
> +       match_id = of_match_node(power_state_match, state_node);
> +       if (!match_id)
> +               return -ENODEV;
> +
> +       err = of_property_read_u32(state_node, "wakeup-latency-us", &latency);
> +       if (err) {
> +               u32 entry_latency, exit_latency;
> +
> +               err = of_property_read_u32(state_node, "entry-latency-us",
> +                                          &entry_latency);
> +               if (err) {
> +                       pr_debug(" * %s missing entry-latency-us property\n",
> +                                state_node->full_name);
> +                       return -EINVAL;
> +               }
> +
> +               err = of_property_read_u32(state_node, "exit-latency-us",
> +                                          &exit_latency);
> +               if (err) {
> +                       pr_debug(" * %s missing exit-latency-us property\n",
> +                                state_node->full_name);
> +                       return -EINVAL;
> +               }
> +               /*
> +                * If wakeup-latency-us is missing, default to entry+exit
> +                * latencies as defined in idle states bindings
> +                */
> +               latency = entry_latency + exit_latency;
> +       }
> +
> +       genpd_state->power_on_latency_ns = 1000 * latency;
> +
> +       err = of_property_read_u32(state_node, "entry-latency-us", &latency);
> +       if (err) {
> +               pr_debug(" * %s missing min-residency-us property\n",
> +                        state_node->full_name);
> +               return -EINVAL;
> +       }
> +
> +       genpd_state->power_off_latency_ns = 1000 * latency;
> +
> +       return 0;
> +}
> +
> +static int of_genpd_device_parse_states(struct device_node *np,
> +                                struct genpd_power_state *genpd_states,
> +                                int *state_count)
> +{
> +       struct device_node *state_node;
> +       int i, err = 0;
> +
> +       for (i = 0;; i++) {
> +               struct genpd_power_state genpd_state;
> +
> +               state_node = of_parse_phandle(np, "power-states", i);
> +               if (!state_node)
> +                       break;
> +
> +               if (i == GENPD_MAX_DOMAIN_STATES) {
> +                       err = -ENOMEM;
> +                       break;
> +               }
> +
> +               err = of_get_genpd_power_state(&genpd_state, state_node);
> +               if (err) {
> +                       pr_err
> +                           ("Parsing idle state node %s failed with err %d\n",
> +                            state_node->full_name, err);
> +                       err = -EINVAL;
> +                       break;
> +               }
> +#ifdef CONFIG_PM_ADVANCED_DEBUG
> +               genpd_state.name = kstrndup(state_node->full_name,
> +                                           GENPD_MAX_NAME_SIZE, GFP_KERNEL);
> +               if (!genpd_state.name)
> +                       err = -ENOMEM;
> +#endif
> +               of_node_put(state_node);
> +               memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state));
> +#ifdef CONFIG_PM_ADVANCED_DEBUG
> +               kfree(genpd_state.name);
> +#endif
> +       }
> +       *state_count = i;
> +       return err;
> +}
> +
>  /**
>   * pm_genpd_init - Initialize a generic I/O PM domain object.
>   * @genpd: PM domain object to initialize.
> @@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>  }
>  EXPORT_SYMBOL_GPL(pm_genpd_init);
>
> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
> +                  struct dev_power_governor *gov, bool is_off)
> +{
> +       struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } };
> +       int state_count = GENPD_MAX_DOMAIN_STATES;
> +       int ret;
> +
> +       if (IS_ERR_OR_NULL(genpd))
> +               return -EINVAL;
> +
> +       ret = of_genpd_device_parse_states(dn, states, &state_count);
> +       if (ret) {
> +               pr_err("Error parsing genpd states for %s\n", genpd->name);
> +               return ret;
> +       }
> +
> +       ret = genpd_alloc_states_data(genpd, states, state_count);
> +       if (ret) {
> +               pr_err("Failed to allocate states for %s\n", genpd->name);
> +               return ret;
> +       }
> +
> +       pm_genpd_init(genpd, gov, is_off);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_pm_genpd_init);
> +
>  #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
>  /*
>   * Device Tree based PM domain providers.
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 11763cf..e425911 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
>                                         void *data);
>
>  int genpd_dev_pm_attach(struct device *dev);
> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
> +                  struct dev_power_governor *gov, bool is_off);
>  #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
>  static inline int __of_genpd_add_provider(struct device_node *np,
>                                         genpd_xlate_t xlate, void *data)
> @@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev)
>  {
>         return -ENODEV;
>  }
> +
> +static inline int of_pm_genpd_init(struct device_node *dn,
> +               struct generic_pm_domain *genpd,
> +               struct dev_power_governor *gov, bool is_off) {}
>  #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
>
>  static inline int of_genpd_add_provider_simple(struct device_node *np,
> --
> 2.1.4
>

Instead of commenting directly to the changes above, let me instead
raise a couple of concerns for the overall approach.

1)
The case when the power-controller node has "#power-domain-cells =
<[n>0]>", isn't covered by $subject patch. I guess we should fix
that!?

2)
I think that it needs to be the SOC PM domain driver that assigns the
initial value for "genpd->state_idx", as I stated also for patch1 when
I noticed pm_genpd_init() overrides that value.

If you share my view around this, it also means that the parsing of
the DTB for "power-states" needs to be done prior the SOC PM domain
driver assigns this initial value for "genpd->state_idx". Following
your approach in $subject patch, means that its value needs to be
updated *after* pm_genpd_init() have been called, perhaps not ideal.

Can we find a better way to deal with this? Maybe by instead of adding
the of_pm_genpd_init() API, we should provide APIs which manages the
DT parsing and the allocation of the struct genpd_power_state? Just an
idea though.


Kind regards
Uffe

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

* [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
@ 2015-12-10 16:53     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-10 16:53 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Marc Titinger <mtitinger+renesas@baylibre.com>
>
> From: Marc Titinger <mtitinger@baylibre.com>
>
> This patch allows cluster-level idle-states to being soaked in as
> generic domain power states, in order for the domain governor to chose
> the most efficient power state compatible with the device constraints.

That was possible before this patch, although you are now making it
possible to describe this in DT and also modifying genpd to parse this
information.

Also, I don't get what this has to do with the governor. Of course
that governor needs to care about the multiple states you added in
patch1, but it should do that no matter if the information comes from
DT or not, right.

Please re-phrase this to make it bit more clear.

> Similarly, devices can register power-states into the cluster domain, in
> a manner consistent with idle-states.

I don't get this. Can you please elaborate?

>
> This is a attempt to address device-retention states for devices that
> are not hooked to runtime-pm, but feature a retention state handled by
> the same firmware that handles idle-states. For instance a L2 caches.

I guess whether devices may use runtime PM or not, they still can be
attached to a PM domain with multiple power states?

>
> With Juno, in this example the idle-state 'cluster-sleep-0 ' is known
> from each cluster generic domain, as the deepest sate.
>
> cat /sys/kernel/debug/pm_genpd/*
>
> Domain             State name        Enter (ns) / Exit (ns)
> -------------------------------------------------------------
> a53_pd               cluster-sleep-0      1500000 / 800000
> a57_pd               cluster-sleep-0      1500000 / 800000
>
> domain                      status pstate     slaves
> /device                                      runtime status
> -----------------------------------------------------------------------
> a53_pd                          on
> /devices/system/cpu/cpu0                            active
> /devices/system/cpu/cpu3                            suspended
> /devices/system/cpu/cpu4                            suspended
> /devices/system/cpu/cpu5                            suspended
> /devices/platform/D1                                suspended
> a57_pd                          cluster-sleep-0
> /devices/system/cpu/cpu1                            suspended
> /devices/system/cpu/cpu2                            suspended
>
> Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> [Lina: removed dependency on dynamic states, simplified initalization,
> added of_pm_genpd_init() API]
> ---
>  .../devicetree/bindings/power/power_domain.txt     |  63 ++++++++++

Please split the documentation of the suggested new DT bindings into a
separate patch that is preceding this one.

Also, you need to send it to the DT maintainers.

>  drivers/base/power/domain.c                        | 128 +++++++++++++++++++++
>  include/linux/pm_domain.h                          |   6 +
>  3 files changed, 197 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index 025b5e7..e2f542e 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -29,6 +29,44 @@ Optional properties:
>     specified by this binding. More details about power domain specifier are
>     available in the next section.
>
> +- power-states : A phandle of an idle-state that shall be soaked into a
> +                generic domain power state. The power-state shall be
> +               compatible with "linux,domain-state".

Why mention the Linux specific "generic power domain" here?

Let's instead try to describe this without using specific terminology
from Linux.

> +
> +==Power state==
> +
> +A PM domain power state describes an idle state of a domain and must be
> +have the following properties -
> +
> +       - compatible
> +               Usage: Required
> +               Value type: <stringlist>
> +               Definition: Must be "linux,domain-state"

Why do you need a compatible string?

You already have the phandle available, I suppose you can use that
instead of parsing for a new compatible string.

> +
> +       - entry-latency-us
> +               Usage: Not required if wakeup-latency-us is provided.
> +               Value type: <prop-encoded-array>
> +               Definition: u32 value representing worst case latency in
> +               microseconds required to enter the idle state.
> +               The exit-latency-us duration may be guaranteed
> +               only after entry-latency-us has passed.
> +
> +       - exit-latency-us
> +               Usage: Not required if wakeup-latency-us is provided.
> +               Value type: <prop-encoded-array>
> +               Definition: u32 value representing worst case latency
> +               in microseconds required to exit the idle state.
> +
> +       - wakeup-latency-us:
> +               Usage: Not required if entry-latency-us and exit-latency-us
> +               are provided.
> +               Value type: <prop-encoded-array>
> +               Definition: u32 value representing maximum delay between the
> +               signaling the wakeup of the domain and the domain resuming
> +               regular operation.
> +               If omitted, this is assumed to be equal to:
> +                       entry-latency-us + exit-latency-us

I think we should decide which of the two alternatives to use, we
shouldn't make it more complicated than needed.

> +
>  Example:
>
>         power: power-controller at 12340000 {
> @@ -55,6 +93,31 @@ Example 2:
>                 #power-domain-cells = <1>;
>         };
>
> +Example 3:
> +
> +       pm-domains {
> +               a57_pd: a57_pd@ {
> +                       /* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/
> +                       compatible = "arm,pd","arm,cortex-a57";
> +                       #power-domain-cells = <0>;
> +                       power-states = <&CLUSTER_SLEEP_0>;
> +               };
> +
> +               a53_pd: a53_pd@ {
> +                       /* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/
> +                       compatible = "arm,pd","arm,cortex-a53";
> +                       #power-domain-cells = <0>;
> +                       power-states = <&CLUSTER_SLEEP_0>;
> +               };
> +
> +               CLUSTER_SLEEP_0: power-state at 0 {
> +                       compatible = "pm-domain,power-state";
> +                       entry-latency-us = <1000>;
> +                       exit-latency-us = <2000>;
> +               };

I think we should also cover the case when power-controller has
"#power-domain-cells = <[n>0]>".

Perhaps extending the first example is then better than adding a new one!?

> +       };
> +
> +
>  The nodes above define two power controllers: 'parent' and 'child'.
>  Domains created by the 'child' power controller are subdomains of '0' power
>  domain provided by the 'parent' power controller.
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 3242854..fe1be88 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -35,6 +35,7 @@
>  })
>
>  #define GENPD_MAX_NAME_SIZE 20
> +#define GENPD_MAX_DOMAIN_STATES 10

Instead of setting a hard limit, let's pre-parse the DTB to get the
number of power states. In that way, it should be fairly easy to
convert the below code to be more dynamic.

>
>  static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>                                        const struct genpd_power_state *st,
> @@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev)
>         return cb ? cb(dev) : 0;
>  }
>
> +static const struct of_device_id power_state_match[] = {
> +       { .compatible = "linux,domain-state" },
> +       { }
> +};
> +
> +static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
> +                                          struct device_node *state_node)
> +{
> +       const struct of_device_id *match_id;
> +       int err = 0;
> +       u32 latency;
> +
> +       match_id = of_match_node(power_state_match, state_node);
> +       if (!match_id)
> +               return -ENODEV;
> +
> +       err = of_property_read_u32(state_node, "wakeup-latency-us", &latency);
> +       if (err) {
> +               u32 entry_latency, exit_latency;
> +
> +               err = of_property_read_u32(state_node, "entry-latency-us",
> +                                          &entry_latency);
> +               if (err) {
> +                       pr_debug(" * %s missing entry-latency-us property\n",
> +                                state_node->full_name);
> +                       return -EINVAL;
> +               }
> +
> +               err = of_property_read_u32(state_node, "exit-latency-us",
> +                                          &exit_latency);
> +               if (err) {
> +                       pr_debug(" * %s missing exit-latency-us property\n",
> +                                state_node->full_name);
> +                       return -EINVAL;
> +               }
> +               /*
> +                * If wakeup-latency-us is missing, default to entry+exit
> +                * latencies as defined in idle states bindings
> +                */
> +               latency = entry_latency + exit_latency;
> +       }
> +
> +       genpd_state->power_on_latency_ns = 1000 * latency;
> +
> +       err = of_property_read_u32(state_node, "entry-latency-us", &latency);
> +       if (err) {
> +               pr_debug(" * %s missing min-residency-us property\n",
> +                        state_node->full_name);
> +               return -EINVAL;
> +       }
> +
> +       genpd_state->power_off_latency_ns = 1000 * latency;
> +
> +       return 0;
> +}
> +
> +static int of_genpd_device_parse_states(struct device_node *np,
> +                                struct genpd_power_state *genpd_states,
> +                                int *state_count)
> +{
> +       struct device_node *state_node;
> +       int i, err = 0;
> +
> +       for (i = 0;; i++) {
> +               struct genpd_power_state genpd_state;
> +
> +               state_node = of_parse_phandle(np, "power-states", i);
> +               if (!state_node)
> +                       break;
> +
> +               if (i == GENPD_MAX_DOMAIN_STATES) {
> +                       err = -ENOMEM;
> +                       break;
> +               }
> +
> +               err = of_get_genpd_power_state(&genpd_state, state_node);
> +               if (err) {
> +                       pr_err
> +                           ("Parsing idle state node %s failed with err %d\n",
> +                            state_node->full_name, err);
> +                       err = -EINVAL;
> +                       break;
> +               }
> +#ifdef CONFIG_PM_ADVANCED_DEBUG
> +               genpd_state.name = kstrndup(state_node->full_name,
> +                                           GENPD_MAX_NAME_SIZE, GFP_KERNEL);
> +               if (!genpd_state.name)
> +                       err = -ENOMEM;
> +#endif
> +               of_node_put(state_node);
> +               memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state));
> +#ifdef CONFIG_PM_ADVANCED_DEBUG
> +               kfree(genpd_state.name);
> +#endif
> +       }
> +       *state_count = i;
> +       return err;
> +}
> +
>  /**
>   * pm_genpd_init - Initialize a generic I/O PM domain object.
>   * @genpd: PM domain object to initialize.
> @@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>  }
>  EXPORT_SYMBOL_GPL(pm_genpd_init);
>
> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
> +                  struct dev_power_governor *gov, bool is_off)
> +{
> +       struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } };
> +       int state_count = GENPD_MAX_DOMAIN_STATES;
> +       int ret;
> +
> +       if (IS_ERR_OR_NULL(genpd))
> +               return -EINVAL;
> +
> +       ret = of_genpd_device_parse_states(dn, states, &state_count);
> +       if (ret) {
> +               pr_err("Error parsing genpd states for %s\n", genpd->name);
> +               return ret;
> +       }
> +
> +       ret = genpd_alloc_states_data(genpd, states, state_count);
> +       if (ret) {
> +               pr_err("Failed to allocate states for %s\n", genpd->name);
> +               return ret;
> +       }
> +
> +       pm_genpd_init(genpd, gov, is_off);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_pm_genpd_init);
> +
>  #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
>  /*
>   * Device Tree based PM domain providers.
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 11763cf..e425911 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
>                                         void *data);
>
>  int genpd_dev_pm_attach(struct device *dev);
> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
> +                  struct dev_power_governor *gov, bool is_off);
>  #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
>  static inline int __of_genpd_add_provider(struct device_node *np,
>                                         genpd_xlate_t xlate, void *data)
> @@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev)
>  {
>         return -ENODEV;
>  }
> +
> +static inline int of_pm_genpd_init(struct device_node *dn,
> +               struct generic_pm_domain *genpd,
> +               struct dev_power_governor *gov, bool is_off) {}
>  #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
>
>  static inline int of_genpd_add_provider_simple(struct device_node *np,
> --
> 2.1.4
>

Instead of commenting directly to the changes above, let me instead
raise a couple of concerns for the overall approach.

1)
The case when the power-controller node has "#power-domain-cells =
<[n>0]>", isn't covered by $subject patch. I guess we should fix
that!?

2)
I think that it needs to be the SOC PM domain driver that assigns the
initial value for "genpd->state_idx", as I stated also for patch1 when
I noticed pm_genpd_init() overrides that value.

If you share my view around this, it also means that the parsing of
the DTB for "power-states" needs to be done prior the SOC PM domain
driver assigns this initial value for "genpd->state_idx". Following
your approach in $subject patch, means that its value needs to be
updated *after* pm_genpd_init() have been called, perhaps not ideal.

Can we find a better way to deal with this? Maybe by instead of adding
the of_pm_genpd_init() API, we should provide APIs which manages the
DT parsing and the allocation of the struct genpd_power_state? Just an
idea though.


Kind regards
Uffe

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

* Re: [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
  2015-12-08 18:05       ` Lina Iyer
@ 2015-12-10 18:11         ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-12-10 18:11 UTC (permalink / raw)
  To: Lina Iyer
  Cc: ulf.hansson, khilman, linux-pm, linux-arm-kernel, geert,
	k.kozlowski, msivasub, agross, sboyd, linux-arm-msm, ahaslam,
	mtitinger, Rob Herring

On Tue, Dec 08, 2015 at 11:05:36AM -0700, Lina Iyer wrote:

[...]

> On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
> >>+/**
> >>+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
> >>+ * topology node in DT.
> >>+ *
> >>+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
> >>+ */
> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
> >>+{
> >>+	struct device_node *cn, *map;
> >>+	int ret = 0;
> >>+
> >>+	cn = of_find_node_by_path("/cpus");
> >>+	if (!cn) {
> >>+		pr_err("No CPU information found in DT\n");
> >>+		return 0;
> >>+	}
> >>+
> >>+	map = of_get_child_by_name(cn, "cpu-map");
> >>+	if (!map)
> >>+		goto out;
> >
> >I commented on this before, is this reliance on cpu-map necessary ?
> >Could not you just rely on the "power-domains" phandle in the cpu
> >nodes to build the cpumask for a specific power domain ? I think
> >you should try to decouple the concept of power domain from the cpu-map
> >cluster and I think this would also simplify your code in the process.
> >
> Sorry, I missed seeing your comment on this earlier.
> 
> Hmm, it can be done, but I felt out of place to define just power
> domains that have no devices in Linux, since they are handled in PSCI,
> but also have no relation to PSCI. Hence, I felt cpu-map to be a good
> place for the cluster domain. But I am not strongly inclined. I can
> remove them from the cpu-map and keep them as separate nodes. However,
> it would be nice to have a way to say these nodes are PSCI controlled.

I do not agree with the way you described the system.

Here is how I see it. DT must model HW, and in HW your cpus will be part
of a power domain(s) that of course can be hierarchical. Every cpus has a
phandle to the power domain it belongs into, and to group them as "cluster"
you should follow the power domains hierarchy (ie if you have a cluster
power domain, it will contain the core power domains, through the
hierarchy it is easy to detect what cpus are part of the cluster power
domain by detecting which cpus are part of its children). It is much
simpler than the current solution I think, you get rid of cpu-map
dependency (honestly it is a bit weird what you did, with cpu-map
containing a cluster phandle to a power domain and cpu phandles to
cpu nodes, and the DT bindings you posted does not seem to match your
dts).

For PSCI, nothing prevents you from defining the same bindings except
that the power domain(s) is not explicitly controlled by the OS, still,
the DT would always describe the HW and you can use it to detect the
power domain topology and which cpus are part of a given power domain.

Please let me know what you think, thanks.

Lorenzo

> 
> Thanks,
> Lina
> 
> >So to sum it up, I'd suggest you build the power domain cpumask by
> >enumerating the cpus pointing at a specific power-domain node.
> >
> 
> >>+
> >>+	ret = of_parse_cpu_pd(map, ops);
> >>+	if (ret != 0)
> >>+		goto out_map;
> >>+
> >>+out_map:
> >>+	of_node_put(map);
> >>+out:
> >>+	of_node_put(cn);
> >>+	return ret;
> >>+}
> >>+EXPORT_SYMBOL(of_setup_cpu_domain_topology);
> >>diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
> >>index 489ee2f..e8290db 100644
> >>--- a/include/linux/cpu-pd.h
> >>+++ b/include/linux/cpu-pd.h
> >>@@ -32,4 +32,5 @@ struct cpu_pm_domain {
> >> struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
> >> 		const struct cpu_pd_ops *ops);
> >> int of_attach_cpu_pm_domain(struct device_node *dn);
> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
> >> #endif /* __CPU_PD_H__ */
> >>--
> >>2.1.4
> >>
> 

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
@ 2015-12-10 18:11         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 166+ messages in thread
From: Lorenzo Pieralisi @ 2015-12-10 18:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 08, 2015 at 11:05:36AM -0700, Lina Iyer wrote:

[...]

> On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
> >>+/**
> >>+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
> >>+ * topology node in DT.
> >>+ *
> >>+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
> >>+ */
> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
> >>+{
> >>+	struct device_node *cn, *map;
> >>+	int ret = 0;
> >>+
> >>+	cn = of_find_node_by_path("/cpus");
> >>+	if (!cn) {
> >>+		pr_err("No CPU information found in DT\n");
> >>+		return 0;
> >>+	}
> >>+
> >>+	map = of_get_child_by_name(cn, "cpu-map");
> >>+	if (!map)
> >>+		goto out;
> >
> >I commented on this before, is this reliance on cpu-map necessary ?
> >Could not you just rely on the "power-domains" phandle in the cpu
> >nodes to build the cpumask for a specific power domain ? I think
> >you should try to decouple the concept of power domain from the cpu-map
> >cluster and I think this would also simplify your code in the process.
> >
> Sorry, I missed seeing your comment on this earlier.
> 
> Hmm, it can be done, but I felt out of place to define just power
> domains that have no devices in Linux, since they are handled in PSCI,
> but also have no relation to PSCI. Hence, I felt cpu-map to be a good
> place for the cluster domain. But I am not strongly inclined. I can
> remove them from the cpu-map and keep them as separate nodes. However,
> it would be nice to have a way to say these nodes are PSCI controlled.

I do not agree with the way you described the system.

Here is how I see it. DT must model HW, and in HW your cpus will be part
of a power domain(s) that of course can be hierarchical. Every cpus has a
phandle to the power domain it belongs into, and to group them as "cluster"
you should follow the power domains hierarchy (ie if you have a cluster
power domain, it will contain the core power domains, through the
hierarchy it is easy to detect what cpus are part of the cluster power
domain by detecting which cpus are part of its children). It is much
simpler than the current solution I think, you get rid of cpu-map
dependency (honestly it is a bit weird what you did, with cpu-map
containing a cluster phandle to a power domain and cpu phandles to
cpu nodes, and the DT bindings you posted does not seem to match your
dts).

For PSCI, nothing prevents you from defining the same bindings except
that the power domain(s) is not explicitly controlled by the OS, still,
the DT would always describe the HW and you can use it to detect the
power domain topology and which cpus are part of a given power domain.

Please let me know what you think, thanks.

Lorenzo

> 
> Thanks,
> Lina
> 
> >So to sum it up, I'd suggest you build the power domain cpumask by
> >enumerating the cpus pointing at a specific power-domain node.
> >
> 
> >>+
> >>+	ret = of_parse_cpu_pd(map, ops);
> >>+	if (ret != 0)
> >>+		goto out_map;
> >>+
> >>+out_map:
> >>+	of_node_put(map);
> >>+out:
> >>+	of_node_put(cn);
> >>+	return ret;
> >>+}
> >>+EXPORT_SYMBOL(of_setup_cpu_domain_topology);
> >>diff --git a/include/linux/cpu-pd.h b/include/linux/cpu-pd.h
> >>index 489ee2f..e8290db 100644
> >>--- a/include/linux/cpu-pd.h
> >>+++ b/include/linux/cpu-pd.h
> >>@@ -32,4 +32,5 @@ struct cpu_pm_domain {
> >> struct generic_pm_domain *of_init_cpu_pm_domain(struct device_node *dn,
> >> 		const struct cpu_pd_ops *ops);
> >> int of_attach_cpu_pm_domain(struct device_node *dn);
> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops);
> >> #endif /* __CPU_PD_H__ */
> >>--
> >>2.1.4
> >>
> 

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

* Re: [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
  2015-12-10 18:11         ` Lorenzo Pieralisi
@ 2015-12-11  9:04           ` Geert Uytterhoeven
  -1 siblings, 0 replies; 166+ messages in thread
From: Geert Uytterhoeven @ 2015-12-11  9:04 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: Lina Iyer, Ulf Hansson, Kevin Hilman, Linux PM list,
	linux-arm-kernel, Krzysztof Kozłowski, msivasub, Andy Gross,
	Stephen Boyd, linux-arm-msm, Axel Haslam, mtitinger, Rob Herring

On Thu, Dec 10, 2015 at 7:11 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On Tue, Dec 08, 2015 at 11:05:36AM -0700, Lina Iyer wrote:
>
> [...]
>
>> On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
>> >>+/**
>> >>+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
>> >>+ * topology node in DT.
>> >>+ *
>> >>+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
>> >>+ */
>> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
>> >>+{
>> >>+   struct device_node *cn, *map;
>> >>+   int ret = 0;
>> >>+
>> >>+   cn = of_find_node_by_path("/cpus");
>> >>+   if (!cn) {
>> >>+           pr_err("No CPU information found in DT\n");
>> >>+           return 0;
>> >>+   }
>> >>+
>> >>+   map = of_get_child_by_name(cn, "cpu-map");
>> >>+   if (!map)
>> >>+           goto out;
>> >
>> >I commented on this before, is this reliance on cpu-map necessary ?
>> >Could not you just rely on the "power-domains" phandle in the cpu
>> >nodes to build the cpumask for a specific power domain ? I think
>> >you should try to decouple the concept of power domain from the cpu-map
>> >cluster and I think this would also simplify your code in the process.
>> >
>> Sorry, I missed seeing your comment on this earlier.
>>
>> Hmm, it can be done, but I felt out of place to define just power
>> domains that have no devices in Linux, since they are handled in PSCI,
>> but also have no relation to PSCI. Hence, I felt cpu-map to be a good
>> place for the cluster domain. But I am not strongly inclined. I can
>> remove them from the cpu-map and keep them as separate nodes. However,
>> it would be nice to have a way to say these nodes are PSCI controlled.
>
> I do not agree with the way you described the system.
>
> Here is how I see it. DT must model HW, and in HW your cpus will be part
> of a power domain(s) that of course can be hierarchical. Every cpus has a
> phandle to the power domain it belongs into, and to group them as "cluster"
> you should follow the power domains hierarchy (ie if you have a cluster
> power domain, it will contain the core power domains, through the
> hierarchy it is easy to detect what cpus are part of the cluster power
> domain by detecting which cpus are part of its children). It is much
> simpler than the current solution I think, you get rid of cpu-map
> dependency (honestly it is a bit weird what you did, with cpu-map
> containing a cluster phandle to a power domain and cpu phandles to
> cpu nodes, and the DT bindings you posted does not seem to match your
> dts).
>
> For PSCI, nothing prevents you from defining the same bindings except
> that the power domain(s) is not explicitly controlled by the OS, still,
> the DT would always describe the HW and you can use it to detect the
> power domain topology and which cpus are part of a given power domain.
>
> Please let me know what you think, thanks.

+1

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
@ 2015-12-11  9:04           ` Geert Uytterhoeven
  0 siblings, 0 replies; 166+ messages in thread
From: Geert Uytterhoeven @ 2015-12-11  9:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 10, 2015 at 7:11 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On Tue, Dec 08, 2015 at 11:05:36AM -0700, Lina Iyer wrote:
>
> [...]
>
>> On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
>> >>+/**
>> >>+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
>> >>+ * topology node in DT.
>> >>+ *
>> >>+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
>> >>+ */
>> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
>> >>+{
>> >>+   struct device_node *cn, *map;
>> >>+   int ret = 0;
>> >>+
>> >>+   cn = of_find_node_by_path("/cpus");
>> >>+   if (!cn) {
>> >>+           pr_err("No CPU information found in DT\n");
>> >>+           return 0;
>> >>+   }
>> >>+
>> >>+   map = of_get_child_by_name(cn, "cpu-map");
>> >>+   if (!map)
>> >>+           goto out;
>> >
>> >I commented on this before, is this reliance on cpu-map necessary ?
>> >Could not you just rely on the "power-domains" phandle in the cpu
>> >nodes to build the cpumask for a specific power domain ? I think
>> >you should try to decouple the concept of power domain from the cpu-map
>> >cluster and I think this would also simplify your code in the process.
>> >
>> Sorry, I missed seeing your comment on this earlier.
>>
>> Hmm, it can be done, but I felt out of place to define just power
>> domains that have no devices in Linux, since they are handled in PSCI,
>> but also have no relation to PSCI. Hence, I felt cpu-map to be a good
>> place for the cluster domain. But I am not strongly inclined. I can
>> remove them from the cpu-map and keep them as separate nodes. However,
>> it would be nice to have a way to say these nodes are PSCI controlled.
>
> I do not agree with the way you described the system.
>
> Here is how I see it. DT must model HW, and in HW your cpus will be part
> of a power domain(s) that of course can be hierarchical. Every cpus has a
> phandle to the power domain it belongs into, and to group them as "cluster"
> you should follow the power domains hierarchy (ie if you have a cluster
> power domain, it will contain the core power domains, through the
> hierarchy it is easy to detect what cpus are part of the cluster power
> domain by detecting which cpus are part of its children). It is much
> simpler than the current solution I think, you get rid of cpu-map
> dependency (honestly it is a bit weird what you did, with cpu-map
> containing a cluster phandle to a power domain and cpu phandles to
> cpu nodes, and the DT bindings you posted does not seem to match your
> dts).
>
> For PSCI, nothing prevents you from defining the same bindings except
> that the power domain(s) is not explicitly controlled by the OS, still,
> the DT would always describe the HW and you can use it to detect the
> power domain topology and which cpus are part of a given power domain.
>
> Please let me know what you think, thanks.

+1

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH RFC 04/27] PM / Domains: make governor select deepest state
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-11  9:13     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11  9:13 UTC (permalink / raw)
  To: Lina Iyer, Axel Haslam
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Marc Titinger, Axel Haslam

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>
> Now that the structures of genpd can support multiple state definitions,
> add the logic in the governor to select the deepest possible state when
> powering down.
>
> For this, create the new function power_down_ok_for_state which will test
> if a particular state will not violate the devices and sub-domains
> constraints.
>
> default_power_down_ok is modified to try each state starting from the
> deepest until a valid state is found or there are no more states to test.
>
> the resulting state will be valid until there are latency or constraint
> changes, thus, we can avoid looping every power_down, and use the cached
> results instead.
>
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> ---
>  drivers/base/power/domain_governor.c | 75 +++++++++++++++++++++---------------
>  1 file changed, 45 insertions(+), 30 deletions(-)

Browsing the changes here and I think it looks good and quite trivial.

I would therefore suggest that you fold this change into patch1 as
it's where it really belongs. Can you please do that?

>
> diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
> index b4984f5..ad69dc0 100644
> --- a/drivers/base/power/domain_governor.c
> +++ b/drivers/base/power/domain_governor.c
> @@ -98,7 +98,8 @@ static bool default_stop_ok(struct device *dev)
>   *
>   * This routine must be executed under the PM domain's lock.
>   */
> -static bool default_power_down_ok(struct dev_pm_domain *pd)
> +static bool power_down_ok_for_state(struct dev_pm_domain *pd,
> +                                    unsigned int state)

I suggest you re-name this function "__default_power_down_ok()" instead.

>  {
>         struct generic_pm_domain *genpd = pd_to_genpd(pd);
>         struct gpd_link *link;
> @@ -106,31 +107,9 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>         s64 min_off_time_ns;
>         s64 off_on_time_ns;
>
> -       if (genpd->max_off_time_changed) {
> -               struct gpd_link *link;
> +       off_on_time_ns = genpd->states[state].power_off_latency_ns +
> +               genpd->states[state].power_on_latency_ns;
>
> -               /*
> -                * We have to invalidate the cached results for the masters, so
> -                * use the observation that default_power_down_ok() is not
> -                * going to be called for any master until this instance
> -                * returns.
> -                */
> -               list_for_each_entry(link, &genpd->slave_links, slave_node)
> -                       link->master->max_off_time_changed = true;
> -
> -               genpd->max_off_time_changed = false;
> -               genpd->cached_power_down_ok = false;
> -               genpd->max_off_time_ns = -1;
> -       } else {
> -               return genpd->cached_power_down_ok;
> -       }
> -
> -       /*
> -        * Use the only available state, until multiple state support is added
> -        * to the governor.
> -        */
> -       off_on_time_ns = genpd->states[0].power_off_latency_ns +
> -                               genpd->states[0].power_on_latency_ns;
>
>         min_off_time_ns = -1;
>         /*
> @@ -193,8 +172,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>                         min_off_time_ns = constraint_ns;
>         }
>
> -       genpd->cached_power_down_ok = true;
> -
>         /*
>          * If the computed minimum device off time is negative, there are no
>          * latency constraints, so the domain can spend arbitrary time in the
> @@ -207,14 +184,52 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>          * The difference between the computed minimum subdomain or device off
>          * time and the time needed to turn the domain on is the maximum
>          * theoretical time this domain can spend in the "off" state.
> -        * Use the only available state, until multiple state support is added
> -        * to the governor.
>          */
>         genpd->max_off_time_ns = min_off_time_ns -
> -               genpd->states[0].power_on_latency_ns;
> +                       genpd->states[state].power_on_latency_ns;
>         return true;
>  }
>
> +static bool default_power_down_ok(struct dev_pm_domain *pd)
> +{
> +       struct generic_pm_domain *genpd = pd_to_genpd(pd);
> +       unsigned int last_state_idx = genpd->state_count - 1;
> +       struct gpd_link *link;
> +       bool retval = false;
> +       unsigned int i;
> +
> +       /*
> +        * if there was no change on max_off_time, we can return the
> +        * cached value and we dont need to find a new target_state
> +        */

The related code speaks for itself, I think you can drop the above comment.

> +       if (!genpd->max_off_time_changed)
> +               return genpd->cached_power_down_ok;
> +
> +       /*
> +        * We have to invalidate the cached results for the masters, so
> +        * use the observation that default_power_down_ok() is not
> +        * going to be called for any master until this instance
> +        * returns.
> +        */
> +       list_for_each_entry(link, &genpd->slave_links, slave_node)
> +               link->master->max_off_time_changed = true;
> +
> +       genpd->max_off_time_ns = -1;
> +       genpd->max_off_time_changed = false;
> +
> +       /* find a state to power down to, starting from the deepest */

Please start sentence with an upper case letter and end it with a dot.

> +       for (i = 0; i < genpd->state_count; i++) {
> +               if (power_down_ok_for_state(pd, last_state_idx - i)) {
> +                       genpd->state_idx = last_state_idx - i;
> +                       retval = true;

Instead of assigning a local copy "retval", I think you can assign
genpd->cached_power_down_ok and later below just return its value.

> +                       break;
> +               }
> +       }

I think you should convert this to a while loop instead as I think it
becomes easier to understand what goes on.

> +
> +       genpd->cached_power_down_ok = retval;
> +       return retval;
> +}
> +
>  static bool always_on_power_down_ok(struct dev_pm_domain *domain)
>  {
>         return false;
> --
> 2.1.4
>

Kind regards
Uffe

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

* [PATCH RFC 04/27] PM / Domains: make governor select deepest state
@ 2015-12-11  9:13     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11  9:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>
> Now that the structures of genpd can support multiple state definitions,
> add the logic in the governor to select the deepest possible state when
> powering down.
>
> For this, create the new function power_down_ok_for_state which will test
> if a particular state will not violate the devices and sub-domains
> constraints.
>
> default_power_down_ok is modified to try each state starting from the
> deepest until a valid state is found or there are no more states to test.
>
> the resulting state will be valid until there are latency or constraint
> changes, thus, we can avoid looping every power_down, and use the cached
> results instead.
>
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> ---
>  drivers/base/power/domain_governor.c | 75 +++++++++++++++++++++---------------
>  1 file changed, 45 insertions(+), 30 deletions(-)

Browsing the changes here and I think it looks good and quite trivial.

I would therefore suggest that you fold this change into patch1 as
it's where it really belongs. Can you please do that?

>
> diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
> index b4984f5..ad69dc0 100644
> --- a/drivers/base/power/domain_governor.c
> +++ b/drivers/base/power/domain_governor.c
> @@ -98,7 +98,8 @@ static bool default_stop_ok(struct device *dev)
>   *
>   * This routine must be executed under the PM domain's lock.
>   */
> -static bool default_power_down_ok(struct dev_pm_domain *pd)
> +static bool power_down_ok_for_state(struct dev_pm_domain *pd,
> +                                    unsigned int state)

I suggest you re-name this function "__default_power_down_ok()" instead.

>  {
>         struct generic_pm_domain *genpd = pd_to_genpd(pd);
>         struct gpd_link *link;
> @@ -106,31 +107,9 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>         s64 min_off_time_ns;
>         s64 off_on_time_ns;
>
> -       if (genpd->max_off_time_changed) {
> -               struct gpd_link *link;
> +       off_on_time_ns = genpd->states[state].power_off_latency_ns +
> +               genpd->states[state].power_on_latency_ns;
>
> -               /*
> -                * We have to invalidate the cached results for the masters, so
> -                * use the observation that default_power_down_ok() is not
> -                * going to be called for any master until this instance
> -                * returns.
> -                */
> -               list_for_each_entry(link, &genpd->slave_links, slave_node)
> -                       link->master->max_off_time_changed = true;
> -
> -               genpd->max_off_time_changed = false;
> -               genpd->cached_power_down_ok = false;
> -               genpd->max_off_time_ns = -1;
> -       } else {
> -               return genpd->cached_power_down_ok;
> -       }
> -
> -       /*
> -        * Use the only available state, until multiple state support is added
> -        * to the governor.
> -        */
> -       off_on_time_ns = genpd->states[0].power_off_latency_ns +
> -                               genpd->states[0].power_on_latency_ns;
>
>         min_off_time_ns = -1;
>         /*
> @@ -193,8 +172,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>                         min_off_time_ns = constraint_ns;
>         }
>
> -       genpd->cached_power_down_ok = true;
> -
>         /*
>          * If the computed minimum device off time is negative, there are no
>          * latency constraints, so the domain can spend arbitrary time in the
> @@ -207,14 +184,52 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>          * The difference between the computed minimum subdomain or device off
>          * time and the time needed to turn the domain on is the maximum
>          * theoretical time this domain can spend in the "off" state.
> -        * Use the only available state, until multiple state support is added
> -        * to the governor.
>          */
>         genpd->max_off_time_ns = min_off_time_ns -
> -               genpd->states[0].power_on_latency_ns;
> +                       genpd->states[state].power_on_latency_ns;
>         return true;
>  }
>
> +static bool default_power_down_ok(struct dev_pm_domain *pd)
> +{
> +       struct generic_pm_domain *genpd = pd_to_genpd(pd);
> +       unsigned int last_state_idx = genpd->state_count - 1;
> +       struct gpd_link *link;
> +       bool retval = false;
> +       unsigned int i;
> +
> +       /*
> +        * if there was no change on max_off_time, we can return the
> +        * cached value and we dont need to find a new target_state
> +        */

The related code speaks for itself, I think you can drop the above comment.

> +       if (!genpd->max_off_time_changed)
> +               return genpd->cached_power_down_ok;
> +
> +       /*
> +        * We have to invalidate the cached results for the masters, so
> +        * use the observation that default_power_down_ok() is not
> +        * going to be called for any master until this instance
> +        * returns.
> +        */
> +       list_for_each_entry(link, &genpd->slave_links, slave_node)
> +               link->master->max_off_time_changed = true;
> +
> +       genpd->max_off_time_ns = -1;
> +       genpd->max_off_time_changed = false;
> +
> +       /* find a state to power down to, starting from the deepest */

Please start sentence with an upper case letter and end it with a dot.

> +       for (i = 0; i < genpd->state_count; i++) {
> +               if (power_down_ok_for_state(pd, last_state_idx - i)) {
> +                       genpd->state_idx = last_state_idx - i;
> +                       retval = true;

Instead of assigning a local copy "retval", I think you can assign
genpd->cached_power_down_ok and later below just return its value.

> +                       break;
> +               }
> +       }

I think you should convert this to a while loop instead as I think it
becomes easier to understand what goes on.

> +
> +       genpd->cached_power_down_ok = retval;
> +       return retval;
> +}
> +
>  static bool always_on_power_down_ok(struct dev_pm_domain *domain)
>  {
>         return false;
> --
> 2.1.4
>

Kind regards
Uffe

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

* Re: [PATCH RFC 05/27] PM / Domains: remove old power on/off latencies.
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-11  9:16     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11  9:16 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Axel Haslam

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>
> Now that all known users have been converted to use state latencies,
> we can remove the latency field in the generic_pm_domain structure.

I couldn't see that happen in this patchset.

As arch/arm/mach-imx/gpc.c is still using this, you will break that platform.

Kind regards
Uffe

>
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> ---
>  drivers/base/power/domain.c | 15 ---------------
>  include/linux/pm_domain.h   |  2 --
>  2 files changed, 17 deletions(-)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 3fb4c93..c300293 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -1248,21 +1248,6 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>                 genpd->states[i].param = st[i].param;
>         }
>
> -       /*
> -        * Copy the latency values To keep compatibility with
> -        * platforms that are not converted to use the multiple states.
> -        * This will be removed once all platforms are converted to use
> -        * multiple states. note that non converted platforms will use the
> -        * default single off state.
> -        */
> -       if (genpd->power_on_latency_ns != 0)
> -               genpd->states[0].power_on_latency_ns =
> -                               genpd->power_on_latency_ns;
> -
> -       if (genpd->power_off_latency_ns != 0)
> -               genpd->states[0].power_off_latency_ns =
> -                               genpd->power_off_latency_ns;
> -
>         genpd->state_count = st_count;
>
>         /* to save memory, Name allocation will happen if debug is enabled */
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 15df24c..108a4b3 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -61,9 +61,7 @@ struct generic_pm_domain {
>         unsigned int prepared_count;    /* Suspend counter of prepared devices */
>         bool suspend_power_off; /* Power status before system suspend */
>         int (*power_off)(struct generic_pm_domain *domain);
> -       s64 power_off_latency_ns;
>         int (*power_on)(struct generic_pm_domain *domain);
> -       s64 power_on_latency_ns;
>         struct gpd_dev_ops dev_ops;
>         s64 max_off_time_ns;    /* Maximum allowed "suspended" time. */
>         bool max_off_time_changed;
> --
> 2.1.4
>

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

* [PATCH RFC 05/27] PM / Domains: remove old power on/off latencies.
@ 2015-12-11  9:16     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>
> Now that all known users have been converted to use state latencies,
> we can remove the latency field in the generic_pm_domain structure.

I couldn't see that happen in this patchset.

As arch/arm/mach-imx/gpc.c is still using this, you will break that platform.

Kind regards
Uffe

>
> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
> ---
>  drivers/base/power/domain.c | 15 ---------------
>  include/linux/pm_domain.h   |  2 --
>  2 files changed, 17 deletions(-)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 3fb4c93..c300293 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -1248,21 +1248,6 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>                 genpd->states[i].param = st[i].param;
>         }
>
> -       /*
> -        * Copy the latency values To keep compatibility with
> -        * platforms that are not converted to use the multiple states.
> -        * This will be removed once all platforms are converted to use
> -        * multiple states. note that non converted platforms will use the
> -        * default single off state.
> -        */
> -       if (genpd->power_on_latency_ns != 0)
> -               genpd->states[0].power_on_latency_ns =
> -                               genpd->power_on_latency_ns;
> -
> -       if (genpd->power_off_latency_ns != 0)
> -               genpd->states[0].power_off_latency_ns =
> -                               genpd->power_off_latency_ns;
> -
>         genpd->state_count = st_count;
>
>         /* to save memory, Name allocation will happen if debug is enabled */
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 15df24c..108a4b3 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -61,9 +61,7 @@ struct generic_pm_domain {
>         unsigned int prepared_count;    /* Suspend counter of prepared devices */
>         bool suspend_power_off; /* Power status before system suspend */
>         int (*power_off)(struct generic_pm_domain *domain);
> -       s64 power_off_latency_ns;
>         int (*power_on)(struct generic_pm_domain *domain);
> -       s64 power_on_latency_ns;
>         struct gpd_dev_ops dev_ops;
>         s64 max_off_time_ns;    /* Maximum allowed "suspended" time. */
>         bool max_off_time_changed;
> --
> 2.1.4
>

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

* Re: [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-11 11:46     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11 11:46 UTC (permalink / raw)
  To: Lina Iyer, Marc Titinger
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Marc Titinger <mtitinger@baylibre.com>
>
> This purpose of these debug seq-files is to help investigate
> generic power domain state transitions, based on device constraints.
> requires the "multiple states" patches from Axel Haslam.

This last sentence doesn't belong in the change-log, please remove it.

>
> also rename 'summary' from 'pm_genpd_summary'
>
> sample output for 'states'
> ==========================
>
>   Domain             State name        Eval = 2200nter + Exit = Min_off_on (ns)
> -----------------------------------------------------------------------
> a53_pd               cluster-sleep-0      1500000+800000=2300000
> a57_pd               d1-retention         1000000+800000=1800000
> a57_pd               cluster-sleep-0      1500000+800000=2300000
>
> sample output for 'timings'
> ===========================
>
>     Domain Devices, Timings in ns
>                        Stop/Start Save/Restore, Effective
> ----------------------------------------------------  ---
> a53_pd
>     /cpus/cpu@100        1060  /660    1580  /1940  ,0 (cached stop)
>     /cpus/cpu@101        1060  /740    1520  /1600  ,0 (cached stop)
>     /cpus/cpu@102        880   /620    1380  /1780  ,0 (cached stop)
>     /cpus/cpu@103        1080  /640    1340  /1600  ,0 (cached stop)
> a57_pd
>     /cpus/cpu@0          1160  /740    3280  /1800  ,0 (cached stop)
>     /cpus/cpu@1          780   /1400   1440  /2080  ,0 (cached stop)
>     /D1                  600   /540    7140  /6420  ,2199460 (cached stop)
>
> Signed-off-by: Marc Titinger <mtitinger@baylibre.com>

A general comment. Static functions in genpd shall start with one of
the following prefix.

genpd_*
_genpd_*
__genpd_*

Please change accordingly.

> ---
>  drivers/base/power/domain.c | 115 +++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 107 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index c300293..9a0df09 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -2169,21 +2169,120 @@ static const struct file_operations pm_genpd_summary_fops = {
>         .release = single_release,
>  };
>
> +static int pm_genpd_states_show(struct seq_file *s, void *data)
> +{
> +       struct generic_pm_domain *genpd;
> +
> +       seq_puts(s,
> +                "\n  Domain             State name        Enter + Exit = Min_off_on (ns)\n");
> +       seq_puts(s,
> +                "-----------------------------------------------------------------------\n");
> +

You must hold the gpd_list_lock while traversing the gpd list.

> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
> +
> +               int i;
> +
> +               for (i = 0; i < genpd->state_count; i++) {

To be sure you have valid data, you should hold the genpd lock here.

> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
> +                                  genpd->name,
> +                                  genpd->states[i].name,
> +                                  genpd->states[i].power_on_latency_ns,
> +                                  genpd->states[i].power_off_latency_ns,
> +                                  genpd->states[i].power_off_latency_ns
> +                                  + genpd->states[i].power_on_latency_ns);
> +               }
> +
> +       }
> +
> +       seq_puts(s, "\n");
> +
> +       return 0;
> +}
> +
> +static int pm_genpd_states_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, pm_genpd_states_show, NULL);
> +}
> +
> +static const struct file_operations pm_genpd_states_fops = {
> +       .open = pm_genpd_states_open,
> +       .read = seq_read,
> +       .llseek = seq_lseek,
> +       .release = single_release,
> +};
> +
> +static int pm_genpd_timing_show(struct seq_file *s, void *data)
> +{
> +       struct generic_pm_domain *genpd;
> +
> +       seq_puts(s, "\n    Domain Devices, Timings in ns\n");
> +       seq_puts(s,
> +                "                       Stop/Start Save/Restore, Effective\n");
> +       seq_puts(s,
> +                "----------------------------------------------------  ---\n");
> +

You must hold the gpd_list_lock while traversing the gpd list.


> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
> +               struct pm_domain_data *pm_data;
> +
> +               seq_printf(s, "%-30s", genpd->name);
> +

You must hold the genpd lock while traversing the device list.

> +               list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
> +                       struct gpd_timing_data *td = &to_gpd_data(pm_data)->td;
> +
> +                       if (!pm_data->dev->of_node)
> +                               continue;
> +
> +                       seq_printf(s,
> +                                  "\n    %-20s %-6lld/%-6lld %-6lld/%-6lld,%lld %s%s",
> +                                  pm_data->dev->of_node->full_name,
> +                                  td->stop_latency_ns, td->start_latency_ns,
> +                                  td->save_state_latency_ns,
> +                                  td->restore_state_latency_ns,

This needs a re-base as these values have been merged.

> +                                  td->effective_constraint_ns,
> +                                  td->cached_stop_ok ? "(cached stop) " : "",
> +                                  td->constraint_changed ? "(changed)" : "");
> +               }
> +               seq_puts(s, "\n");
> +       }
> +       return 0;
> +}
> +
> +static int pm_genpd_timing_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, pm_genpd_timing_show, NULL);
> +}
> +
> +static const struct file_operations pm_genpd_timing_fops = {
> +       .open = pm_genpd_timing_open,
> +       .read = seq_read,
> +       .llseek = seq_lseek,
> +       .release = single_release,
> +};
> +
>  static int __init pm_genpd_debug_init(void)
>  {
> -       struct dentry *d;
> +       struct dentry *d = NULL;
>
>         pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
>
> -       if (!pm_genpd_debugfs_dir)
> -               return -ENOMEM;
> +       if (pm_genpd_debugfs_dir)

In case when CONFIG_DEBUG_FS is unset, this doesn't work very well, as
pm_genpd_debugfs_dir will contain an error code.

Since you are anyway make quite big change to the debugfs support for
genpd, perhaps you can try to fix that up as well!?

> +               d = debugfs_create_file("summary", S_IRUGO,
> +                               pm_genpd_debugfs_dir, NULL,
> +                               &pm_genpd_summary_fops);
> +       if (d)
> +               d = debugfs_create_file("states", S_IRUGO,
> +                               pm_genpd_debugfs_dir, NULL,
> +                               &pm_genpd_states_fops);
> +       if (d)
> +               d = debugfs_create_file("timings", S_IRUGO,
> +                               pm_genpd_debugfs_dir, NULL,
> +                               &pm_genpd_timing_fops);
> +       if (d)
> +               return 0;
>
> -       d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
> -                       pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops);
> -       if (!d)
> -               return -ENOMEM;
> +       debugfs_remove_recursive(pm_genpd_debugfs_dir /*can be null*/);
>
> -       return 0;
> +       return -ENOMEM;
>  }
>  late_initcall(pm_genpd_debug_init);
>

Kind regards
Uffe

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

* [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
@ 2015-12-11 11:46     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> From: Marc Titinger <mtitinger@baylibre.com>
>
> This purpose of these debug seq-files is to help investigate
> generic power domain state transitions, based on device constraints.
> requires the "multiple states" patches from Axel Haslam.

This last sentence doesn't belong in the change-log, please remove it.

>
> also rename 'summary' from 'pm_genpd_summary'
>
> sample output for 'states'
> ==========================
>
>   Domain             State name        Eval = 2200nter + Exit = Min_off_on (ns)
> -----------------------------------------------------------------------
> a53_pd               cluster-sleep-0      1500000+800000=2300000
> a57_pd               d1-retention         1000000+800000=1800000
> a57_pd               cluster-sleep-0      1500000+800000=2300000
>
> sample output for 'timings'
> ===========================
>
>     Domain Devices, Timings in ns
>                        Stop/Start Save/Restore, Effective
> ----------------------------------------------------  ---
> a53_pd
>     /cpus/cpu at 100        1060  /660    1580  /1940  ,0 (cached stop)
>     /cpus/cpu at 101        1060  /740    1520  /1600  ,0 (cached stop)
>     /cpus/cpu at 102        880   /620    1380  /1780  ,0 (cached stop)
>     /cpus/cpu at 103        1080  /640    1340  /1600  ,0 (cached stop)
> a57_pd
>     /cpus/cpu at 0          1160  /740    3280  /1800  ,0 (cached stop)
>     /cpus/cpu at 1          780   /1400   1440  /2080  ,0 (cached stop)
>     /D1                  600   /540    7140  /6420  ,2199460 (cached stop)
>
> Signed-off-by: Marc Titinger <mtitinger@baylibre.com>

A general comment. Static functions in genpd shall start with one of
the following prefix.

genpd_*
_genpd_*
__genpd_*

Please change accordingly.

> ---
>  drivers/base/power/domain.c | 115 +++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 107 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index c300293..9a0df09 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -2169,21 +2169,120 @@ static const struct file_operations pm_genpd_summary_fops = {
>         .release = single_release,
>  };
>
> +static int pm_genpd_states_show(struct seq_file *s, void *data)
> +{
> +       struct generic_pm_domain *genpd;
> +
> +       seq_puts(s,
> +                "\n  Domain             State name        Enter + Exit = Min_off_on (ns)\n");
> +       seq_puts(s,
> +                "-----------------------------------------------------------------------\n");
> +

You must hold the gpd_list_lock while traversing the gpd list.

> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
> +
> +               int i;
> +
> +               for (i = 0; i < genpd->state_count; i++) {

To be sure you have valid data, you should hold the genpd lock here.

> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
> +                                  genpd->name,
> +                                  genpd->states[i].name,
> +                                  genpd->states[i].power_on_latency_ns,
> +                                  genpd->states[i].power_off_latency_ns,
> +                                  genpd->states[i].power_off_latency_ns
> +                                  + genpd->states[i].power_on_latency_ns);
> +               }
> +
> +       }
> +
> +       seq_puts(s, "\n");
> +
> +       return 0;
> +}
> +
> +static int pm_genpd_states_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, pm_genpd_states_show, NULL);
> +}
> +
> +static const struct file_operations pm_genpd_states_fops = {
> +       .open = pm_genpd_states_open,
> +       .read = seq_read,
> +       .llseek = seq_lseek,
> +       .release = single_release,
> +};
> +
> +static int pm_genpd_timing_show(struct seq_file *s, void *data)
> +{
> +       struct generic_pm_domain *genpd;
> +
> +       seq_puts(s, "\n    Domain Devices, Timings in ns\n");
> +       seq_puts(s,
> +                "                       Stop/Start Save/Restore, Effective\n");
> +       seq_puts(s,
> +                "----------------------------------------------------  ---\n");
> +

You must hold the gpd_list_lock while traversing the gpd list.


> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
> +               struct pm_domain_data *pm_data;
> +
> +               seq_printf(s, "%-30s", genpd->name);
> +

You must hold the genpd lock while traversing the device list.

> +               list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
> +                       struct gpd_timing_data *td = &to_gpd_data(pm_data)->td;
> +
> +                       if (!pm_data->dev->of_node)
> +                               continue;
> +
> +                       seq_printf(s,
> +                                  "\n    %-20s %-6lld/%-6lld %-6lld/%-6lld,%lld %s%s",
> +                                  pm_data->dev->of_node->full_name,
> +                                  td->stop_latency_ns, td->start_latency_ns,
> +                                  td->save_state_latency_ns,
> +                                  td->restore_state_latency_ns,

This needs a re-base as these values have been merged.

> +                                  td->effective_constraint_ns,
> +                                  td->cached_stop_ok ? "(cached stop) " : "",
> +                                  td->constraint_changed ? "(changed)" : "");
> +               }
> +               seq_puts(s, "\n");
> +       }
> +       return 0;
> +}
> +
> +static int pm_genpd_timing_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, pm_genpd_timing_show, NULL);
> +}
> +
> +static const struct file_operations pm_genpd_timing_fops = {
> +       .open = pm_genpd_timing_open,
> +       .read = seq_read,
> +       .llseek = seq_lseek,
> +       .release = single_release,
> +};
> +
>  static int __init pm_genpd_debug_init(void)
>  {
> -       struct dentry *d;
> +       struct dentry *d = NULL;
>
>         pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
>
> -       if (!pm_genpd_debugfs_dir)
> -               return -ENOMEM;
> +       if (pm_genpd_debugfs_dir)

In case when CONFIG_DEBUG_FS is unset, this doesn't work very well, as
pm_genpd_debugfs_dir will contain an error code.

Since you are anyway make quite big change to the debugfs support for
genpd, perhaps you can try to fix that up as well!?

> +               d = debugfs_create_file("summary", S_IRUGO,
> +                               pm_genpd_debugfs_dir, NULL,
> +                               &pm_genpd_summary_fops);
> +       if (d)
> +               d = debugfs_create_file("states", S_IRUGO,
> +                               pm_genpd_debugfs_dir, NULL,
> +                               &pm_genpd_states_fops);
> +       if (d)
> +               d = debugfs_create_file("timings", S_IRUGO,
> +                               pm_genpd_debugfs_dir, NULL,
> +                               &pm_genpd_timing_fops);
> +       if (d)
> +               return 0;
>
> -       d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
> -                       pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops);
> -       if (!d)
> -               return -ENOMEM;
> +       debugfs_remove_recursive(pm_genpd_debugfs_dir /*can be null*/);
>
> -       return 0;
> +       return -ENOMEM;
>  }
>  late_initcall(pm_genpd_debug_init);
>

Kind regards
Uffe

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

* Re: [PATCH RFC 07/27] PM / Domains: Read domain residency from DT
  2015-11-17 22:37   ` Lina Iyer
@ 2015-12-11 11:54     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11 11:54 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> Domains that have expensive suspend resume operations, may require a
> certain amount of time be spent in an idle state to reap the power
> saving benefit. Such domains, may provide the residency requirement for
> a domain state.
>
> Read the residency for a domain state from the DT. A domain governor may
> use this information in determining the state for the domain.
>
> Cc: Axel Haslam <ahaslam@baylibre.com>
> Cc: Marc Titinger <mtitinger@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  Documentation/devicetree/bindings/power/power_domain.txt | 7 +++++++

Please split DT documentation into a separate patch preceding $subject
patch. Don't forget to send it to the DT maintainers as well.

>  drivers/base/power/domain.c                              | 6 ++++++
>  include/linux/pm_domain.h                                | 1 +
>  3 files changed, 14 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index ecfaf44..d71da29 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -67,6 +67,13 @@ have the following properties -
>                 If omitted, this is assumed to be equal to:
>                         entry-latency-us + exit-latency-us
>
> +       - residency-us:
> +               Usage: Optional
> +               Value type: <prop-encoded-array>
> +               Definition: A u32 value representing the time for which a
> +               domain must be idle in the state to reap power saving benefits
> +               of entering the state.
> +
>         - state-param:
>                 Usage: Optional
>                 Value type: <prop-encoded-array>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 9a0df09..abc81bd 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -1245,6 +1245,7 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>                         st[i].power_on_latency_ns;
>                 genpd->states[i].power_off_latency_ns =
>                         st[i].power_off_latency_ns;
> +               genpd->states[i].residency_ns = st[i].residency_ns;
>                 genpd->states[i].param = st[i].param;
>         }
>
> @@ -1513,6 +1514,7 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
>         const struct of_device_id *match_id;
>         int err = 0;
>         u32 latency;
> +       u32 residency;
>         u32 param;
>
>         match_id = of_match_node(power_state_match, state_node);
> @@ -1554,6 +1556,10 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
>                 return -EINVAL;
>         }
>
> +       err = of_property_read_u32(state_node, "residency-us", &residency);
> +       if (!err)
> +               genpd_state->residency_ns = 1000 * residency;
> +
>         err = of_property_read_u32(state_node, "state-param", &param);
>         if (!err)
>                 genpd_state->param = param;
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 108a4b3..fed024a 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -41,6 +41,7 @@ struct genpd_power_state {
>         char *name;
>         s64 power_off_latency_ns;
>         s64 power_on_latency_ns;
> +       s64 residency_ns;
>         u32 param;
>  };
>
> --
> 2.1.4
>

A general comment.

I would as step prior $subject patch, add the mechanism in genpd to
deal with this new concept of residency values. When *all* that
mechanism is in place (perhaps it needs more than one patch), then add
the DT parts.

Kind regards
Uffe

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

* [PATCH RFC 07/27] PM / Domains: Read domain residency from DT
@ 2015-12-11 11:54     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-11 11:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> Domains that have expensive suspend resume operations, may require a
> certain amount of time be spent in an idle state to reap the power
> saving benefit. Such domains, may provide the residency requirement for
> a domain state.
>
> Read the residency for a domain state from the DT. A domain governor may
> use this information in determining the state for the domain.
>
> Cc: Axel Haslam <ahaslam@baylibre.com>
> Cc: Marc Titinger <mtitinger@baylibre.com>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
>  Documentation/devicetree/bindings/power/power_domain.txt | 7 +++++++

Please split DT documentation into a separate patch preceding $subject
patch. Don't forget to send it to the DT maintainers as well.

>  drivers/base/power/domain.c                              | 6 ++++++
>  include/linux/pm_domain.h                                | 1 +
>  3 files changed, 14 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
> index ecfaf44..d71da29 100644
> --- a/Documentation/devicetree/bindings/power/power_domain.txt
> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
> @@ -67,6 +67,13 @@ have the following properties -
>                 If omitted, this is assumed to be equal to:
>                         entry-latency-us + exit-latency-us
>
> +       - residency-us:
> +               Usage: Optional
> +               Value type: <prop-encoded-array>
> +               Definition: A u32 value representing the time for which a
> +               domain must be idle in the state to reap power saving benefits
> +               of entering the state.
> +
>         - state-param:
>                 Usage: Optional
>                 Value type: <prop-encoded-array>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 9a0df09..abc81bd 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -1245,6 +1245,7 @@ static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>                         st[i].power_on_latency_ns;
>                 genpd->states[i].power_off_latency_ns =
>                         st[i].power_off_latency_ns;
> +               genpd->states[i].residency_ns = st[i].residency_ns;
>                 genpd->states[i].param = st[i].param;
>         }
>
> @@ -1513,6 +1514,7 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
>         const struct of_device_id *match_id;
>         int err = 0;
>         u32 latency;
> +       u32 residency;
>         u32 param;
>
>         match_id = of_match_node(power_state_match, state_node);
> @@ -1554,6 +1556,10 @@ static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
>                 return -EINVAL;
>         }
>
> +       err = of_property_read_u32(state_node, "residency-us", &residency);
> +       if (!err)
> +               genpd_state->residency_ns = 1000 * residency;
> +
>         err = of_property_read_u32(state_node, "state-param", &param);
>         if (!err)
>                 genpd_state->param = param;
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index 108a4b3..fed024a 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -41,6 +41,7 @@ struct genpd_power_state {
>         char *name;
>         s64 power_off_latency_ns;
>         s64 power_on_latency_ns;
> +       s64 residency_ns;
>         u32 param;
>  };
>
> --
> 2.1.4
>

A general comment.

I would as step prior $subject patch, add the mechanism in genpd to
deal with this new concept of residency values. When *all* that
mechanism is in place (perhaps it needs more than one patch), then add
the DT parts.

Kind regards
Uffe

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

* Re: [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
  2015-12-11  9:04           ` Geert Uytterhoeven
@ 2015-12-11 20:51             ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-11 20:51 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Lorenzo Pieralisi, Ulf Hansson, Kevin Hilman, Linux PM list,
	linux-arm-kernel, Krzysztof Kozłowski, msivasub, Andy Gross,
	Stephen Boyd, linux-arm-msm, Axel Haslam, mtitinger, Rob Herring

On Fri, Dec 11 2015 at 02:04 -0700, Geert Uytterhoeven wrote:
>On Thu, Dec 10, 2015 at 7:11 PM, Lorenzo Pieralisi
><lorenzo.pieralisi@arm.com> wrote:
>> On Tue, Dec 08, 2015 at 11:05:36AM -0700, Lina Iyer wrote:
>>
>> [...]
>>
>>> On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
>>> >>+/**
>>> >>+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
>>> >>+ * topology node in DT.
>>> >>+ *
>>> >>+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
>>> >>+ */
>>> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
>>> >>+{
>>> >>+   struct device_node *cn, *map;
>>> >>+   int ret = 0;
>>> >>+
>>> >>+   cn = of_find_node_by_path("/cpus");
>>> >>+   if (!cn) {
>>> >>+           pr_err("No CPU information found in DT\n");
>>> >>+           return 0;
>>> >>+   }
>>> >>+
>>> >>+   map = of_get_child_by_name(cn, "cpu-map");
>>> >>+   if (!map)
>>> >>+           goto out;
>>> >
>>> >I commented on this before, is this reliance on cpu-map necessary ?
>>> >Could not you just rely on the "power-domains" phandle in the cpu
>>> >nodes to build the cpumask for a specific power domain ? I think
>>> >you should try to decouple the concept of power domain from the cpu-map
>>> >cluster and I think this would also simplify your code in the process.
>>> >
>>> Sorry, I missed seeing your comment on this earlier.
>>>
>>> Hmm, it can be done, but I felt out of place to define just power
>>> domains that have no devices in Linux, since they are handled in PSCI,
>>> but also have no relation to PSCI. Hence, I felt cpu-map to be a good
>>> place for the cluster domain. But I am not strongly inclined. I can
>>> remove them from the cpu-map and keep them as separate nodes. However,
>>> it would be nice to have a way to say these nodes are PSCI controlled.
>>
>> I do not agree with the way you described the system.
>>
>> Here is how I see it. DT must model HW, and in HW your cpus will be part
>> of a power domain(s) that of course can be hierarchical. Every cpus has a
>> phandle to the power domain it belongs into, and to group them as "cluster"
>> you should follow the power domains hierarchy (ie if you have a cluster
>> power domain, it will contain the core power domains, through the
>> hierarchy it is easy to detect what cpus are part of the cluster power
>> domain by detecting which cpus are part of its children). It is much
>> simpler than the current solution I think, you get rid of cpu-map
>> dependency (honestly it is a bit weird what you did, with cpu-map
>> containing a cluster phandle to a power domain and cpu phandles to
>> cpu nodes, and the DT bindings you posted does not seem to match your
>> dts).
>>
>> For PSCI, nothing prevents you from defining the same bindings except
>> that the power domain(s) is not explicitly controlled by the OS, still,
>> the DT would always describe the HW and you can use it to detect the
>> power domain topology and which cpus are part of a given power domain.
>>
>> Please let me know what you think, thanks.
>
>+1
>
I have a version written up that builds up the hierarchy from the CPU
nodes. It doesnt use cpu-map. Will be part of the next submission.

Thanks,
Lina

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

* [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains
@ 2015-12-11 20:51             ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-11 20:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Dec 11 2015 at 02:04 -0700, Geert Uytterhoeven wrote:
>On Thu, Dec 10, 2015 at 7:11 PM, Lorenzo Pieralisi
><lorenzo.pieralisi@arm.com> wrote:
>> On Tue, Dec 08, 2015 at 11:05:36AM -0700, Lina Iyer wrote:
>>
>> [...]
>>
>>> On Mon, Dec 07 2015 at 07:53 -0700, Lorenzo Pieralisi wrote:
>>> >>+/**
>>> >>+ * of_setup_cpu_domain_topology() - Setup the CPU domains from the CPU
>>> >>+ * topology node in DT.
>>> >>+ *
>>> >>+ * @ops: The PM domain suspend/resume ops for all the domains in the topology
>>> >>+ */
>>> >>+int of_setup_cpu_domain_topology(const struct cpu_pd_ops *ops)
>>> >>+{
>>> >>+   struct device_node *cn, *map;
>>> >>+   int ret = 0;
>>> >>+
>>> >>+   cn = of_find_node_by_path("/cpus");
>>> >>+   if (!cn) {
>>> >>+           pr_err("No CPU information found in DT\n");
>>> >>+           return 0;
>>> >>+   }
>>> >>+
>>> >>+   map = of_get_child_by_name(cn, "cpu-map");
>>> >>+   if (!map)
>>> >>+           goto out;
>>> >
>>> >I commented on this before, is this reliance on cpu-map necessary ?
>>> >Could not you just rely on the "power-domains" phandle in the cpu
>>> >nodes to build the cpumask for a specific power domain ? I think
>>> >you should try to decouple the concept of power domain from the cpu-map
>>> >cluster and I think this would also simplify your code in the process.
>>> >
>>> Sorry, I missed seeing your comment on this earlier.
>>>
>>> Hmm, it can be done, but I felt out of place to define just power
>>> domains that have no devices in Linux, since they are handled in PSCI,
>>> but also have no relation to PSCI. Hence, I felt cpu-map to be a good
>>> place for the cluster domain. But I am not strongly inclined. I can
>>> remove them from the cpu-map and keep them as separate nodes. However,
>>> it would be nice to have a way to say these nodes are PSCI controlled.
>>
>> I do not agree with the way you described the system.
>>
>> Here is how I see it. DT must model HW, and in HW your cpus will be part
>> of a power domain(s) that of course can be hierarchical. Every cpus has a
>> phandle to the power domain it belongs into, and to group them as "cluster"
>> you should follow the power domains hierarchy (ie if you have a cluster
>> power domain, it will contain the core power domains, through the
>> hierarchy it is easy to detect what cpus are part of the cluster power
>> domain by detecting which cpus are part of its children). It is much
>> simpler than the current solution I think, you get rid of cpu-map
>> dependency (honestly it is a bit weird what you did, with cpu-map
>> containing a cluster phandle to a power domain and cpu phandles to
>> cpu nodes, and the DT bindings you posted does not seem to match your
>> dts).
>>
>> For PSCI, nothing prevents you from defining the same bindings except
>> that the power domain(s) is not explicitly controlled by the OS, still,
>> the DT would always describe the HW and you can use it to detect the
>> power domain topology and which cpus are part of a given power domain.
>>
>> Please let me know what you think, thanks.
>
>+1
>
I have a version written up that builds up the hierarchy from the CPU
nodes. It doesnt use cpu-map. Will be part of the next submission.

Thanks,
Lina

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

* Re: [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
  2015-12-10 16:53     ` Ulf Hansson
@ 2015-12-15 10:07       ` Marc Titinger
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-12-15 10:07 UTC (permalink / raw)
  To: Ulf Hansson, Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger

On 10/12/2015 17:53, Ulf Hansson wrote:
> On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> From: Marc Titinger <mtitinger+renesas@baylibre.com>
>>
>> From: Marc Titinger <mtitinger@baylibre.com>
>>
>> This patch allows cluster-level idle-states to being soaked in as
>> generic domain power states, in order for the domain governor to chose
>> the most efficient power state compatible with the device constraints.
>

Hi Ulf,


> That was possible before this patch, although you are now making it
> possible to describe this in DT and also modifying genpd to parse this
> information.

please correct if I'm wrong, but I think that before you could delegate 
the power-off of a power domain to the platform code called from the 
cpu-idle driver by toggling enable of an idle-state from genpd.

What is proposed here is different: the idea is to prepare for an 
os-initiated mode for the cluster power management, where genpd keeps 
track of the last-man cpu (or more generally the last-man IP in the 
cluster) and calls the platform code to enter the most effective power 
state compatible with the QoS constraints for devices in the 
power-domain. IOW it is genpd that controls the plaftormn code to go to 
sleep or retention state X, instead of cpuidle-driver calling the method 
indexed for each state.

>
> Also, I don't get what this has to do with the governor. Of course
> that governor needs to care about the multiple states you added in
> patch1, but it should do that no matter if the information comes from
> DT or not, right.
>
Agreed, that part should go to the cover-letter instead.

> Please re-phrase this to make it bit more clear.

Ok.

>
>> Similarly, devices can register power-states into the cluster domain, in
>> a manner consistent with idle-states.
>
> I don't get this. Can you please elaborate?


Alexes addition of "power states" to the power domains was to have a 
better representation of features of power controllers. For instance QoS 
may prevent to enter/exit complete power-off, but setting the core 
voltage to say 0.7v is feasible in terms of timing, and still better 
than full-power-on etc... Hence the domain has a list of possible states 
to chose upon, between full power-on and full-power-off, and genpd will 
call the platform code for this.

Now, this patch maps the idle-states as possible power states for the 
domain: upon the last CPU runtime_put, the domain can chose the deepest
state that can be reached given the enter/exit time available, and call 
the platform code for this. This selected state can be any of:
* cluster-sleep (power OFF)
* cluster-retention A (L2RAM retention for instance)
* cluster-retention B (some device is still on, like PMU or bus 
analyzer, healthckeck IP etc...)
...
* cluster-on, but lower voltage A
* cluster-on, but lower voltage B
etc...

Put short: CPUs, like any other devices in the domain may register a 
power state.

>
>>
>> This is a attempt to address device-retention states for devices that
>> are not hooked to runtime-pm, but feature a retention state handled by
>> the same firmware that handles idle-states. For instance a L2 caches.
>
> I guess whether devices may use runtime PM or not, they still can be
> attached to a PM domain with multiple power states?

yes.
>
>>
>> With Juno, in this example the idle-state 'cluster-sleep-0 ' is known
>> from each cluster generic domain, as the deepest sate.
>>
>> cat /sys/kernel/debug/pm_genpd/*
>>
>> Domain             State name        Enter (ns) / Exit (ns)
>> -------------------------------------------------------------
>> a53_pd               cluster-sleep-0      1500000 / 800000
>> a57_pd               cluster-sleep-0      1500000 / 800000
>>
>> domain                      status pstate     slaves
>> /device                                      runtime status
>> -----------------------------------------------------------------------
>> a53_pd                          on
>> /devices/system/cpu/cpu0                            active
>> /devices/system/cpu/cpu3                            suspended
>> /devices/system/cpu/cpu4                            suspended
>> /devices/system/cpu/cpu5                            suspended
>> /devices/platform/D1                                suspended
>> a57_pd                          cluster-sleep-0
>> /devices/system/cpu/cpu1                            suspended
>> /devices/system/cpu/cpu2                            suspended
>>
>> Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> [Lina: removed dependency on dynamic states, simplified initalization,
>> added of_pm_genpd_init() API]
>> ---
>>   .../devicetree/bindings/power/power_domain.txt     |  63 ++++++++++
>
> Please split the documentation of the suggested new DT bindings into a
> separate patch that is preceding this one.
>
> Also, you need to send it to the DT maintainers.

>
>>   drivers/base/power/domain.c                        | 128 +++++++++++++++++++++
>>   include/linux/pm_domain.h                          |   6 +
>>   3 files changed, 197 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
>> index 025b5e7..e2f542e 100644
>> --- a/Documentation/devicetree/bindings/power/power_domain.txt
>> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
>> @@ -29,6 +29,44 @@ Optional properties:
>>      specified by this binding. More details about power domain specifier are
>>      available in the next section.
>>
>> +- power-states : A phandle of an idle-state that shall be soaked into a
>> +                generic domain power state. The power-state shall be
>> +               compatible with "linux,domain-state".
>
> Why mention the Linux specific "generic power domain" here?
>
> Let's instead try to describe this without using specific terminology
> from Linux.

Hmm, I will need Lina's help to answer this one.
Following a previous review actually I dropped this power-states 
compatible, to stick with idle-states.

>
>> +
>> +==Power state==
>> +
>> +A PM domain power state describes an idle state of a domain and must be
>> +have the following properties -
>> +
>> +       - compatible
>> +               Usage: Required
>> +               Value type: <stringlist>
>> +               Definition: Must be "linux,domain-state"
>
> Why do you need a compatible string?
>
> You already have the phandle available, I suppose you can use that
> instead of parsing for a new compatible string.
>
>> +
>> +       - entry-latency-us
>> +               Usage: Not required if wakeup-latency-us is provided.
>> +               Value type: <prop-encoded-array>
>> +               Definition: u32 value representing worst case latency in
>> +               microseconds required to enter the idle state.
>> +               The exit-latency-us duration may be guaranteed
>> +               only after entry-latency-us has passed.
>> +
>> +       - exit-latency-us
>> +               Usage: Not required if wakeup-latency-us is provided.
>> +               Value type: <prop-encoded-array>
>> +               Definition: u32 value representing worst case latency
>> +               in microseconds required to exit the idle state.
>> +
>> +       - wakeup-latency-us:
>> +               Usage: Not required if entry-latency-us and exit-latency-us
>> +               are provided.
>> +               Value type: <prop-encoded-array>
>> +               Definition: u32 value representing maximum delay between the
>> +               signaling the wakeup of the domain and the domain resuming
>> +               regular operation.
>> +               If omitted, this is assumed to be equal to:
>> +                       entry-latency-us + exit-latency-us
>
> I think we should decide which of the two alternatives to use, we
> shouldn't make it more complicated than needed.

Agreed.

>
>> +
>>   Example:
>>
>>          power: power-controller@12340000 {
>> @@ -55,6 +93,31 @@ Example 2:
>>                  #power-domain-cells = <1>;
>>          };
>>
>> +Example 3:
>> +
>> +       pm-domains {
>> +               a57_pd: a57_pd@ {
>> +                       /* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/
>> +                       compatible = "arm,pd","arm,cortex-a57";
>> +                       #power-domain-cells = <0>;
>> +                       power-states = <&CLUSTER_SLEEP_0>;
>> +               };
>> +
>> +               a53_pd: a53_pd@ {
>> +                       /* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/
>> +                       compatible = "arm,pd","arm,cortex-a53";
>> +                       #power-domain-cells = <0>;
>> +                       power-states = <&CLUSTER_SLEEP_0>;
>> +               };
>> +
>> +               CLUSTER_SLEEP_0: power-state@0 {
>> +                       compatible = "pm-domain,power-state";
>> +                       entry-latency-us = <1000>;
>> +                       exit-latency-us = <2000>;
>> +               };
>
> I think we should also cover the case when power-controller has
> "#power-domain-cells = <[n>0]>".
>
> Perhaps extending the first example is then better than adding a new one!?
>
>> +       };
>> +
>> +
>>   The nodes above define two power controllers: 'parent' and 'child'.
>>   Domains created by the 'child' power controller are subdomains of '0' power
>>   domain provided by the 'parent' power controller.
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index 3242854..fe1be88 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -35,6 +35,7 @@
>>   })
>>
>>   #define GENPD_MAX_NAME_SIZE 20
>> +#define GENPD_MAX_DOMAIN_STATES 10
>
> Instead of setting a hard limit, let's pre-parse the DTB to get the
> number of power states. In that way, it should be fairly easy to
> convert the below code to be more dynamic.

>
>>
>>   static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>>                                         const struct genpd_power_state *st,
>> @@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev)
>>          return cb ? cb(dev) : 0;
>>   }
>>
>> +static const struct of_device_id power_state_match[] = {
>> +       { .compatible = "linux,domain-state" },
>> +       { }
>> +};
>> +
>> +static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
>> +                                          struct device_node *state_node)
>> +{
>> +       const struct of_device_id *match_id;
>> +       int err = 0;
>> +       u32 latency;
>> +
>> +       match_id = of_match_node(power_state_match, state_node);
>> +       if (!match_id)
>> +               return -ENODEV;
>> +
>> +       err = of_property_read_u32(state_node, "wakeup-latency-us", &latency);
>> +       if (err) {
>> +               u32 entry_latency, exit_latency;
>> +
>> +               err = of_property_read_u32(state_node, "entry-latency-us",
>> +                                          &entry_latency);
>> +               if (err) {
>> +                       pr_debug(" * %s missing entry-latency-us property\n",
>> +                                state_node->full_name);
>> +                       return -EINVAL;
>> +               }
>> +
>> +               err = of_property_read_u32(state_node, "exit-latency-us",
>> +                                          &exit_latency);
>> +               if (err) {
>> +                       pr_debug(" * %s missing exit-latency-us property\n",
>> +                                state_node->full_name);
>> +                       return -EINVAL;
>> +               }
>> +               /*
>> +                * If wakeup-latency-us is missing, default to entry+exit
>> +                * latencies as defined in idle states bindings
>> +                */
>> +               latency = entry_latency + exit_latency;
>> +       }
>> +
>> +       genpd_state->power_on_latency_ns = 1000 * latency;
>> +
>> +       err = of_property_read_u32(state_node, "entry-latency-us", &latency);
>> +       if (err) {
>> +               pr_debug(" * %s missing min-residency-us property\n",
>> +                        state_node->full_name);
>> +               return -EINVAL;
>> +       }
>> +
>> +       genpd_state->power_off_latency_ns = 1000 * latency;
>> +
>> +       return 0;
>> +}
>> +
>> +static int of_genpd_device_parse_states(struct device_node *np,
>> +                                struct genpd_power_state *genpd_states,
>> +                                int *state_count)
>> +{
>> +       struct device_node *state_node;
>> +       int i, err = 0;
>> +
>> +       for (i = 0;; i++) {
>> +               struct genpd_power_state genpd_state;
>> +
>> +               state_node = of_parse_phandle(np, "power-states", i);
>> +               if (!state_node)
>> +                       break;
>> +
>> +               if (i == GENPD_MAX_DOMAIN_STATES) {
>> +                       err = -ENOMEM;
>> +                       break;
>> +               }
>> +
>> +               err = of_get_genpd_power_state(&genpd_state, state_node);
>> +               if (err) {
>> +                       pr_err
>> +                           ("Parsing idle state node %s failed with err %d\n",
>> +                            state_node->full_name, err);
>> +                       err = -EINVAL;
>> +                       break;
>> +               }
>> +#ifdef CONFIG_PM_ADVANCED_DEBUG
>> +               genpd_state.name = kstrndup(state_node->full_name,
>> +                                           GENPD_MAX_NAME_SIZE, GFP_KERNEL);
>> +               if (!genpd_state.name)
>> +                       err = -ENOMEM;
>> +#endif
>> +               of_node_put(state_node);
>> +               memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state));
>> +#ifdef CONFIG_PM_ADVANCED_DEBUG
>> +               kfree(genpd_state.name);
>> +#endif
>> +       }
>> +       *state_count = i;
>> +       return err;
>> +}
>> +
>>   /**
>>    * pm_genpd_init - Initialize a generic I/O PM domain object.
>>    * @genpd: PM domain object to initialize.
>> @@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>>   }
>>   EXPORT_SYMBOL_GPL(pm_genpd_init);
>>
>> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
>> +                  struct dev_power_governor *gov, bool is_off)
>> +{
>> +       struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } };
>> +       int state_count = GENPD_MAX_DOMAIN_STATES;
>> +       int ret;
>> +
>> +       if (IS_ERR_OR_NULL(genpd))
>> +               return -EINVAL;
>> +
>> +       ret = of_genpd_device_parse_states(dn, states, &state_count);
>> +       if (ret) {
>> +               pr_err("Error parsing genpd states for %s\n", genpd->name);
>> +               return ret;
>> +       }
>> +
>> +       ret = genpd_alloc_states_data(genpd, states, state_count);
>> +       if (ret) {
>> +               pr_err("Failed to allocate states for %s\n", genpd->name);
>> +               return ret;
>> +       }
>> +
>> +       pm_genpd_init(genpd, gov, is_off);
>> +
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(of_pm_genpd_init);
>> +
>>   #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
>>   /*
>>    * Device Tree based PM domain providers.
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index 11763cf..e425911 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
>>                                          void *data);
>>
>>   int genpd_dev_pm_attach(struct device *dev);
>> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
>> +                  struct dev_power_governor *gov, bool is_off);
>>   #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
>>   static inline int __of_genpd_add_provider(struct device_node *np,
>>                                          genpd_xlate_t xlate, void *data)
>> @@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev)
>>   {
>>          return -ENODEV;
>>   }
>> +
>> +static inline int of_pm_genpd_init(struct device_node *dn,
>> +               struct generic_pm_domain *genpd,
>> +               struct dev_power_governor *gov, bool is_off) {}
>>   #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
>>
>>   static inline int of_genpd_add_provider_simple(struct device_node *np,
>> --
>> 2.1.4
>>
>
> Instead of commenting directly to the changes above, let me instead
> raise a couple of concerns for the overall approach.
>
> 1)
> The case when the power-controller node has "#power-domain-cells =
> <[n>0]>", isn't covered by $subject patch. I guess we should fix
> that!?
>

Indeed, I must confess a bit of procrastination here, my apologies :)

> 2)
> I think that it needs to be the SOC PM domain driver that assigns the
> initial value for "genpd->state_idx", as I stated also for patch1 when
> I noticed pm_genpd_init() overrides that value.
> dev_pm_domain_attach
> If you share my view around this, it also means that the parsing of
> the DTB for "power-states" needs to be done prior the SOC PM domain
> driver assigns this initial value for "genpd->state_idx". Following
> your approach in $subject patch, means that its value needs to be
> updated *after* pm_genpd_init() have been called, perhaps not ideal.
>
> Can we find a better way to deal with this? Maybe by instead of adding
> the of_pm_genpd_init() API, we should provide APIs which manages the
> DT parsing and the allocation of the struct genpd_power_state? Just an
> idea though.

In my original patch, I was adding the states from the 
dev_pm_domain_attach (genpd_devm_pm_attach) API. But since it's called 
before we know if a matching device driver could be successfully probed 
anyway, I reckon those device-bound states can be parsed/sorted early on 
as well.

Regarding the initial (exploratory) purpose of my series of handling IPs 
with special retention states with genpd, this can probably be done more 
simply with the existing runtime PM framework as discussed in a previous 
review, let me quote Kevin here:

<quote>
... I think has a first pass, rather than add the additional complexity
required for a dynamic set of genpd states, I think it's much better to
start by assuming that all devices in the domain that affect the domain
state should have an associated device and a driver using runtime PM.
For example, performance montitoring units (PMUs) like CoreSight have
this same issue, and the upstream support for those is already using
runtime PM.

For really simple/dump devices like L2$ or similar, it might be that we
don't need a real driver, but instead the CPU "devices" could do
gets/puts on any dependent devices directly
</quote>


I will see with Lina how much I shall keep from this patch that is 
useful to the purpose of her series for os-initiated mode.

Many thanks,
Marc.


>
>
> Kind regards
> Uffe
>

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

* [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
@ 2015-12-15 10:07       ` Marc Titinger
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-12-15 10:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/12/2015 17:53, Ulf Hansson wrote:
> On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> From: Marc Titinger <mtitinger+renesas@baylibre.com>
>>
>> From: Marc Titinger <mtitinger@baylibre.com>
>>
>> This patch allows cluster-level idle-states to being soaked in as
>> generic domain power states, in order for the domain governor to chose
>> the most efficient power state compatible with the device constraints.
>

Hi Ulf,


> That was possible before this patch, although you are now making it
> possible to describe this in DT and also modifying genpd to parse this
> information.

please correct if I'm wrong, but I think that before you could delegate 
the power-off of a power domain to the platform code called from the 
cpu-idle driver by toggling enable of an idle-state from genpd.

What is proposed here is different: the idea is to prepare for an 
os-initiated mode for the cluster power management, where genpd keeps 
track of the last-man cpu (or more generally the last-man IP in the 
cluster) and calls the platform code to enter the most effective power 
state compatible with the QoS constraints for devices in the 
power-domain. IOW it is genpd that controls the plaftormn code to go to 
sleep or retention state X, instead of cpuidle-driver calling the method 
indexed for each state.

>
> Also, I don't get what this has to do with the governor. Of course
> that governor needs to care about the multiple states you added in
> patch1, but it should do that no matter if the information comes from
> DT or not, right.
>
Agreed, that part should go to the cover-letter instead.

> Please re-phrase this to make it bit more clear.

Ok.

>
>> Similarly, devices can register power-states into the cluster domain, in
>> a manner consistent with idle-states.
>
> I don't get this. Can you please elaborate?


Alexes addition of "power states" to the power domains was to have a 
better representation of features of power controllers. For instance QoS 
may prevent to enter/exit complete power-off, but setting the core 
voltage to say 0.7v is feasible in terms of timing, and still better 
than full-power-on etc... Hence the domain has a list of possible states 
to chose upon, between full power-on and full-power-off, and genpd will 
call the platform code for this.

Now, this patch maps the idle-states as possible power states for the 
domain: upon the last CPU runtime_put, the domain can chose the deepest
state that can be reached given the enter/exit time available, and call 
the platform code for this. This selected state can be any of:
* cluster-sleep (power OFF)
* cluster-retention A (L2RAM retention for instance)
* cluster-retention B (some device is still on, like PMU or bus 
analyzer, healthckeck IP etc...)
...
* cluster-on, but lower voltage A
* cluster-on, but lower voltage B
etc...

Put short: CPUs, like any other devices in the domain may register a 
power state.

>
>>
>> This is a attempt to address device-retention states for devices that
>> are not hooked to runtime-pm, but feature a retention state handled by
>> the same firmware that handles idle-states. For instance a L2 caches.
>
> I guess whether devices may use runtime PM or not, they still can be
> attached to a PM domain with multiple power states?

yes.
>
>>
>> With Juno, in this example the idle-state 'cluster-sleep-0 ' is known
>> from each cluster generic domain, as the deepest sate.
>>
>> cat /sys/kernel/debug/pm_genpd/*
>>
>> Domain             State name        Enter (ns) / Exit (ns)
>> -------------------------------------------------------------
>> a53_pd               cluster-sleep-0      1500000 / 800000
>> a57_pd               cluster-sleep-0      1500000 / 800000
>>
>> domain                      status pstate     slaves
>> /device                                      runtime status
>> -----------------------------------------------------------------------
>> a53_pd                          on
>> /devices/system/cpu/cpu0                            active
>> /devices/system/cpu/cpu3                            suspended
>> /devices/system/cpu/cpu4                            suspended
>> /devices/system/cpu/cpu5                            suspended
>> /devices/platform/D1                                suspended
>> a57_pd                          cluster-sleep-0
>> /devices/system/cpu/cpu1                            suspended
>> /devices/system/cpu/cpu2                            suspended
>>
>> Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> [Lina: removed dependency on dynamic states, simplified initalization,
>> added of_pm_genpd_init() API]
>> ---
>>   .../devicetree/bindings/power/power_domain.txt     |  63 ++++++++++
>
> Please split the documentation of the suggested new DT bindings into a
> separate patch that is preceding this one.
>
> Also, you need to send it to the DT maintainers.

>
>>   drivers/base/power/domain.c                        | 128 +++++++++++++++++++++
>>   include/linux/pm_domain.h                          |   6 +
>>   3 files changed, 197 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
>> index 025b5e7..e2f542e 100644
>> --- a/Documentation/devicetree/bindings/power/power_domain.txt
>> +++ b/Documentation/devicetree/bindings/power/power_domain.txt
>> @@ -29,6 +29,44 @@ Optional properties:
>>      specified by this binding. More details about power domain specifier are
>>      available in the next section.
>>
>> +- power-states : A phandle of an idle-state that shall be soaked into a
>> +                generic domain power state. The power-state shall be
>> +               compatible with "linux,domain-state".
>
> Why mention the Linux specific "generic power domain" here?
>
> Let's instead try to describe this without using specific terminology
> from Linux.

Hmm, I will need Lina's help to answer this one.
Following a previous review actually I dropped this power-states 
compatible, to stick with idle-states.

>
>> +
>> +==Power state==
>> +
>> +A PM domain power state describes an idle state of a domain and must be
>> +have the following properties -
>> +
>> +       - compatible
>> +               Usage: Required
>> +               Value type: <stringlist>
>> +               Definition: Must be "linux,domain-state"
>
> Why do you need a compatible string?
>
> You already have the phandle available, I suppose you can use that
> instead of parsing for a new compatible string.
>
>> +
>> +       - entry-latency-us
>> +               Usage: Not required if wakeup-latency-us is provided.
>> +               Value type: <prop-encoded-array>
>> +               Definition: u32 value representing worst case latency in
>> +               microseconds required to enter the idle state.
>> +               The exit-latency-us duration may be guaranteed
>> +               only after entry-latency-us has passed.
>> +
>> +       - exit-latency-us
>> +               Usage: Not required if wakeup-latency-us is provided.
>> +               Value type: <prop-encoded-array>
>> +               Definition: u32 value representing worst case latency
>> +               in microseconds required to exit the idle state.
>> +
>> +       - wakeup-latency-us:
>> +               Usage: Not required if entry-latency-us and exit-latency-us
>> +               are provided.
>> +               Value type: <prop-encoded-array>
>> +               Definition: u32 value representing maximum delay between the
>> +               signaling the wakeup of the domain and the domain resuming
>> +               regular operation.
>> +               If omitted, this is assumed to be equal to:
>> +                       entry-latency-us + exit-latency-us
>
> I think we should decide which of the two alternatives to use, we
> shouldn't make it more complicated than needed.

Agreed.

>
>> +
>>   Example:
>>
>>          power: power-controller at 12340000 {
>> @@ -55,6 +93,31 @@ Example 2:
>>                  #power-domain-cells = <1>;
>>          };
>>
>> +Example 3:
>> +
>> +       pm-domains {
>> +               a57_pd: a57_pd@ {
>> +                       /* will have a57 platform ARM_PD_METHOD_OF_DECLARE*/
>> +                       compatible = "arm,pd","arm,cortex-a57";
>> +                       #power-domain-cells = <0>;
>> +                       power-states = <&CLUSTER_SLEEP_0>;
>> +               };
>> +
>> +               a53_pd: a53_pd@ {
>> +                       /* will have a a53 platform ARM_PD_METHOD_OF_DECLARE*/
>> +                       compatible = "arm,pd","arm,cortex-a53";
>> +                       #power-domain-cells = <0>;
>> +                       power-states = <&CLUSTER_SLEEP_0>;
>> +               };
>> +
>> +               CLUSTER_SLEEP_0: power-state at 0 {
>> +                       compatible = "pm-domain,power-state";
>> +                       entry-latency-us = <1000>;
>> +                       exit-latency-us = <2000>;
>> +               };
>
> I think we should also cover the case when power-controller has
> "#power-domain-cells = <[n>0]>".
>
> Perhaps extending the first example is then better than adding a new one!?
>
>> +       };
>> +
>> +
>>   The nodes above define two power controllers: 'parent' and 'child'.
>>   Domains created by the 'child' power controller are subdomains of '0' power
>>   domain provided by the 'parent' power controller.
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index 3242854..fe1be88 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -35,6 +35,7 @@
>>   })
>>
>>   #define GENPD_MAX_NAME_SIZE 20
>> +#define GENPD_MAX_DOMAIN_STATES 10
>
> Instead of setting a hard limit, let's pre-parse the DTB to get the
> number of power states. In that way, it should be fairly easy to
> convert the below code to be more dynamic.

>
>>
>>   static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>>                                         const struct genpd_power_state *st,
>> @@ -1515,6 +1516,105 @@ static int pm_genpd_default_restore_state(struct device *dev)
>>          return cb ? cb(dev) : 0;
>>   }
>>
>> +static const struct of_device_id power_state_match[] = {
>> +       { .compatible = "linux,domain-state" },
>> +       { }
>> +};
>> +
>> +static int of_get_genpd_power_state(struct genpd_power_state *genpd_state,
>> +                                          struct device_node *state_node)
>> +{
>> +       const struct of_device_id *match_id;
>> +       int err = 0;
>> +       u32 latency;
>> +
>> +       match_id = of_match_node(power_state_match, state_node);
>> +       if (!match_id)
>> +               return -ENODEV;
>> +
>> +       err = of_property_read_u32(state_node, "wakeup-latency-us", &latency);
>> +       if (err) {
>> +               u32 entry_latency, exit_latency;
>> +
>> +               err = of_property_read_u32(state_node, "entry-latency-us",
>> +                                          &entry_latency);
>> +               if (err) {
>> +                       pr_debug(" * %s missing entry-latency-us property\n",
>> +                                state_node->full_name);
>> +                       return -EINVAL;
>> +               }
>> +
>> +               err = of_property_read_u32(state_node, "exit-latency-us",
>> +                                          &exit_latency);
>> +               if (err) {
>> +                       pr_debug(" * %s missing exit-latency-us property\n",
>> +                                state_node->full_name);
>> +                       return -EINVAL;
>> +               }
>> +               /*
>> +                * If wakeup-latency-us is missing, default to entry+exit
>> +                * latencies as defined in idle states bindings
>> +                */
>> +               latency = entry_latency + exit_latency;
>> +       }
>> +
>> +       genpd_state->power_on_latency_ns = 1000 * latency;
>> +
>> +       err = of_property_read_u32(state_node, "entry-latency-us", &latency);
>> +       if (err) {
>> +               pr_debug(" * %s missing min-residency-us property\n",
>> +                        state_node->full_name);
>> +               return -EINVAL;
>> +       }
>> +
>> +       genpd_state->power_off_latency_ns = 1000 * latency;
>> +
>> +       return 0;
>> +}
>> +
>> +static int of_genpd_device_parse_states(struct device_node *np,
>> +                                struct genpd_power_state *genpd_states,
>> +                                int *state_count)
>> +{
>> +       struct device_node *state_node;
>> +       int i, err = 0;
>> +
>> +       for (i = 0;; i++) {
>> +               struct genpd_power_state genpd_state;
>> +
>> +               state_node = of_parse_phandle(np, "power-states", i);
>> +               if (!state_node)
>> +                       break;
>> +
>> +               if (i == GENPD_MAX_DOMAIN_STATES) {
>> +                       err = -ENOMEM;
>> +                       break;
>> +               }
>> +
>> +               err = of_get_genpd_power_state(&genpd_state, state_node);
>> +               if (err) {
>> +                       pr_err
>> +                           ("Parsing idle state node %s failed with err %d\n",
>> +                            state_node->full_name, err);
>> +                       err = -EINVAL;
>> +                       break;
>> +               }
>> +#ifdef CONFIG_PM_ADVANCED_DEBUG
>> +               genpd_state.name = kstrndup(state_node->full_name,
>> +                                           GENPD_MAX_NAME_SIZE, GFP_KERNEL);
>> +               if (!genpd_state.name)
>> +                       err = -ENOMEM;
>> +#endif
>> +               of_node_put(state_node);
>> +               memcpy(&genpd_states[i], &genpd_state, sizeof(genpd_state));
>> +#ifdef CONFIG_PM_ADVANCED_DEBUG
>> +               kfree(genpd_state.name);
>> +#endif
>> +       }
>> +       *state_count = i;
>> +       return err;
>> +}
>> +
>>   /**
>>    * pm_genpd_init - Initialize a generic I/O PM domain object.
>>    * @genpd: PM domain object to initialize.
>> @@ -1596,6 +1696,34 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>>   }
>>   EXPORT_SYMBOL_GPL(pm_genpd_init);
>>
>> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
>> +                  struct dev_power_governor *gov, bool is_off)
>> +{
>> +       struct genpd_power_state states[GENPD_MAX_DOMAIN_STATES] = { { 0 } };
>> +       int state_count = GENPD_MAX_DOMAIN_STATES;
>> +       int ret;
>> +
>> +       if (IS_ERR_OR_NULL(genpd))
>> +               return -EINVAL;
>> +
>> +       ret = of_genpd_device_parse_states(dn, states, &state_count);
>> +       if (ret) {
>> +               pr_err("Error parsing genpd states for %s\n", genpd->name);
>> +               return ret;
>> +       }
>> +
>> +       ret = genpd_alloc_states_data(genpd, states, state_count);
>> +       if (ret) {
>> +               pr_err("Failed to allocate states for %s\n", genpd->name);
>> +               return ret;
>> +       }
>> +
>> +       pm_genpd_init(genpd, gov, is_off);
>> +
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(of_pm_genpd_init);
>> +
>>   #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
>>   /*
>>    * Device Tree based PM domain providers.
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index 11763cf..e425911 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -213,6 +213,8 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
>>                                          void *data);
>>
>>   int genpd_dev_pm_attach(struct device *dev);
>> +int of_pm_genpd_init(struct device_node *dn, struct generic_pm_domain *genpd,
>> +                  struct dev_power_governor *gov, bool is_off);
>>   #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
>>   static inline int __of_genpd_add_provider(struct device_node *np,
>>                                          genpd_xlate_t xlate, void *data)
>> @@ -234,6 +236,10 @@ static inline int genpd_dev_pm_attach(struct device *dev)
>>   {
>>          return -ENODEV;
>>   }
>> +
>> +static inline int of_pm_genpd_init(struct device_node *dn,
>> +               struct generic_pm_domain *genpd,
>> +               struct dev_power_governor *gov, bool is_off) {}
>>   #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
>>
>>   static inline int of_genpd_add_provider_simple(struct device_node *np,
>> --
>> 2.1.4
>>
>
> Instead of commenting directly to the changes above, let me instead
> raise a couple of concerns for the overall approach.
>
> 1)
> The case when the power-controller node has "#power-domain-cells =
> <[n>0]>", isn't covered by $subject patch. I guess we should fix
> that!?
>

Indeed, I must confess a bit of procrastination here, my apologies :)

> 2)
> I think that it needs to be the SOC PM domain driver that assigns the
> initial value for "genpd->state_idx", as I stated also for patch1 when
> I noticed pm_genpd_init() overrides that value.
> dev_pm_domain_attach
> If you share my view around this, it also means that the parsing of
> the DTB for "power-states" needs to be done prior the SOC PM domain
> driver assigns this initial value for "genpd->state_idx". Following
> your approach in $subject patch, means that its value needs to be
> updated *after* pm_genpd_init() have been called, perhaps not ideal.
>
> Can we find a better way to deal with this? Maybe by instead of adding
> the of_pm_genpd_init() API, we should provide APIs which manages the
> DT parsing and the allocation of the struct genpd_power_state? Just an
> idea though.

In my original patch, I was adding the states from the 
dev_pm_domain_attach (genpd_devm_pm_attach) API. But since it's called 
before we know if a matching device driver could be successfully probed 
anyway, I reckon those device-bound states can be parsed/sorted early on 
as well.

Regarding the initial (exploratory) purpose of my series of handling IPs 
with special retention states with genpd, this can probably be done more 
simply with the existing runtime PM framework as discussed in a previous 
review, let me quote Kevin here:

<quote>
... I think has a first pass, rather than add the additional complexity
required for a dynamic set of genpd states, I think it's much better to
start by assuming that all devices in the domain that affect the domain
state should have an associated device and a driver using runtime PM.
For example, performance montitoring units (PMUs) like CoreSight have
this same issue, and the upstream support for those is already using
runtime PM.

For really simple/dump devices like L2$ or similar, it might be that we
don't need a real driver, but instead the CPU "devices" could do
gets/puts on any dependent devices directly
</quote>


I will see with Lina how much I shall keep from this patch that is 
useful to the purpose of her series for os-initiated mode.

Many thanks,
Marc.


>
>
> Kind regards
> Uffe
>

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

* Re: [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
  2015-12-15 10:07       ` Marc Titinger
@ 2015-12-15 22:14         ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-15 22:14 UTC (permalink / raw)
  To: Marc Titinger
  Cc: Ulf Hansson, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	Axel Haslam, Marc Titinger

On Tue, Dec 15 2015 at 03:07 -0700, Marc Titinger wrote:
>On 10/12/2015 17:53, Ulf Hansson wrote:
>>On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:

>>>diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
>>>index 025b5e7..e2f542e 100644
>>>--- a/Documentation/devicetree/bindings/power/power_domain.txt
>>>+++ b/Documentation/devicetree/bindings/power/power_domain.txt
>>>@@ -29,6 +29,44 @@ Optional properties:
>>>     specified by this binding. More details about power domain specifier are
>>>     available in the next section.
>>>
>>>+- power-states : A phandle of an idle-state that shall be soaked into a
>>>+                generic domain power state. The power-state shall be
>>>+               compatible with "linux,domain-state".
>>
>>Why mention the Linux specific "generic power domain" here?
>>
>>Let's instead try to describe this without using specific terminology
>>from Linux.
>
>Hmm, I will need Lina's help to answer this one.
>Following a previous review actually I dropped this power-states 
>compatible, to stick with idle-states.
>
I didnt want this to be ARM specific. An arm,idle-state is too specific
to be reused for generic PM domains, hence this compatible. We dont need
a compatible property, but I thought it would be nice to have the
property to give structure to the power state node.

>>
>>>+
>>>+==Power state==
>>>+
>>>+A PM domain power state describes an idle state of a domain and must be
>>>+have the following properties -
>>>+
>>>+       - compatible
>>>+               Usage: Required
>>>+               Value type: <stringlist>
>>>+               Definition: Must be "linux,domain-state"
>>
>>Why do you need a compatible string?
>>
>>You already have the phandle available, I suppose you can use that
>>instead of parsing for a new compatible string.
>>
Hmm.. okay.

>>>+
>>>+       - entry-latency-us
>>>+               Usage: Not required if wakeup-latency-us is provided.
>>>+               Value type: <prop-encoded-array>
>>>+               Definition: u32 value representing worst case latency in
>>>+               microseconds required to enter the idle state.
>>>+               The exit-latency-us duration may be guaranteed
>>>+               only after entry-latency-us has passed.
>>>+
>>>+       - exit-latency-us
>>>+               Usage: Not required if wakeup-latency-us is provided.
>>>+               Value type: <prop-encoded-array>
>>>+               Definition: u32 value representing worst case latency
>>>+               in microseconds required to exit the idle state.
>>>+
>>>+       - wakeup-latency-us:
>>>+               Usage: Not required if entry-latency-us and exit-latency-us
>>>+               are provided.
>>>+               Value type: <prop-encoded-array>
>>>+               Definition: u32 value representing maximum delay between the
>>>+               signaling the wakeup of the domain and the domain resuming
>>>+               regular operation.
>>>+               If omitted, this is assumed to be equal to:
>>>+                       entry-latency-us + exit-latency-us
>>
>>I think we should decide which of the two alternatives to use, we
>>shouldn't make it more complicated than needed.
>
>Agreed.
>
I like the entry + exit option.

Thanks,
Lina

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

* [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
@ 2015-12-15 22:14         ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-15 22:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 15 2015 at 03:07 -0700, Marc Titinger wrote:
>On 10/12/2015 17:53, Ulf Hansson wrote:
>>On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:

>>>diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
>>>index 025b5e7..e2f542e 100644
>>>--- a/Documentation/devicetree/bindings/power/power_domain.txt
>>>+++ b/Documentation/devicetree/bindings/power/power_domain.txt
>>>@@ -29,6 +29,44 @@ Optional properties:
>>>     specified by this binding. More details about power domain specifier are
>>>     available in the next section.
>>>
>>>+- power-states : A phandle of an idle-state that shall be soaked into a
>>>+                generic domain power state. The power-state shall be
>>>+               compatible with "linux,domain-state".
>>
>>Why mention the Linux specific "generic power domain" here?
>>
>>Let's instead try to describe this without using specific terminology
>>from Linux.
>
>Hmm, I will need Lina's help to answer this one.
>Following a previous review actually I dropped this power-states 
>compatible, to stick with idle-states.
>
I didnt want this to be ARM specific. An arm,idle-state is too specific
to be reused for generic PM domains, hence this compatible. We dont need
a compatible property, but I thought it would be nice to have the
property to give structure to the power state node.

>>
>>>+
>>>+==Power state==
>>>+
>>>+A PM domain power state describes an idle state of a domain and must be
>>>+have the following properties -
>>>+
>>>+       - compatible
>>>+               Usage: Required
>>>+               Value type: <stringlist>
>>>+               Definition: Must be "linux,domain-state"
>>
>>Why do you need a compatible string?
>>
>>You already have the phandle available, I suppose you can use that
>>instead of parsing for a new compatible string.
>>
Hmm.. okay.

>>>+
>>>+       - entry-latency-us
>>>+               Usage: Not required if wakeup-latency-us is provided.
>>>+               Value type: <prop-encoded-array>
>>>+               Definition: u32 value representing worst case latency in
>>>+               microseconds required to enter the idle state.
>>>+               The exit-latency-us duration may be guaranteed
>>>+               only after entry-latency-us has passed.
>>>+
>>>+       - exit-latency-us
>>>+               Usage: Not required if wakeup-latency-us is provided.
>>>+               Value type: <prop-encoded-array>
>>>+               Definition: u32 value representing worst case latency
>>>+               in microseconds required to exit the idle state.
>>>+
>>>+       - wakeup-latency-us:
>>>+               Usage: Not required if entry-latency-us and exit-latency-us
>>>+               are provided.
>>>+               Value type: <prop-encoded-array>
>>>+               Definition: u32 value representing maximum delay between the
>>>+               signaling the wakeup of the domain and the domain resuming
>>>+               regular operation.
>>>+               If omitted, this is assumed to be equal to:
>>>+                       entry-latency-us + exit-latency-us
>>
>>I think we should decide which of the two alternatives to use, we
>>shouldn't make it more complicated than needed.
>
>Agreed.
>
I like the entry + exit option.

Thanks,
Lina

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

* Re: [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
  2015-12-11 11:46     ` Ulf Hansson
@ 2015-12-16 11:07       ` Marc Titinger
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-12-16 11:07 UTC (permalink / raw)
  To: Ulf Hansson, Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam

On 11/12/2015 12:46, Ulf Hansson wrote:
> On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:


Hi Ulf,

thanks for the review, comments and questions below.

Best Regards,
Marc.

>> From: Marc Titinger <mtitinger@baylibre.com>
>>
>> This purpose of these debug seq-files is to help investigate
>> generic power domain state transitions, based on device constraints.
>> requires the "multiple states" patches from Axel Haslam.
>
> This last sentence doesn't belong in the change-log, please remove it.
>
>>
>> also rename 'summary' from 'pm_genpd_summary'
>>
>> sample output for 'states'
>> ==========================
>>
>>    Domain             State name        Eval = 2200nter + Exit = Min_off_on (ns)
>> -----------------------------------------------------------------------
>> a53_pd               cluster-sleep-0      1500000+800000=2300000
>> a57_pd               d1-retention         1000000+800000=1800000
>> a57_pd               cluster-sleep-0      1500000+800000=2300000
>>
>> sample output for 'timings'
>> ===========================
>>
>>      Domain Devices, Timings in ns
>>                         Stop/Start Save/Restore, Effective
>> ----------------------------------------------------  ---
>> a53_pd
>>      /cpus/cpu@100        1060  /660    1580  /1940  ,0 (cached stop)
>>      /cpus/cpu@101        1060  /740    1520  /1600  ,0 (cached stop)
>>      /cpus/cpu@102        880   /620    1380  /1780  ,0 (cached stop)
>>      /cpus/cpu@103        1080  /640    1340  /1600  ,0 (cached stop)
>> a57_pd
>>      /cpus/cpu@0          1160  /740    3280  /1800  ,0 (cached stop)
>>      /cpus/cpu@1          780   /1400   1440  /2080  ,0 (cached stop)
>>      /D1                  600   /540    7140  /6420  ,2199460 (cached stop)
>>
>> Signed-off-by: Marc Titinger <mtitinger@baylibre.com>
>
> A general comment. Static functions in genpd shall start with one of
> the following prefix.
>
> genpd_*
> _genpd_*
> __genpd_*
>
> Please change accordingly.

Many static routines were already prefixed like the exported functions 
with "pm_", shall I make a separate patch for this renaming ?

>
>> ---
>>   drivers/base/power/domain.c | 115 +++++++++++++++++++++++++++++++++++++++++---
>>   1 file changed, 107 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index c300293..9a0df09 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -2169,21 +2169,120 @@ static const struct file_operations pm_genpd_summary_fops = {
>>          .release = single_release,
>>   };
>>
>> +static int pm_genpd_states_show(struct seq_file *s, void *data)
>> +{
>> +       struct generic_pm_domain *genpd;
>> +
>> +       seq_puts(s,
>> +                "\n  Domain             State name        Enter + Exit = Min_off_on (ns)\n");
>> +       seq_puts(s,
>> +                "-----------------------------------------------------------------------\n");
>> +
>
> You must hold the gpd_list_lock while traversing the gpd list.
>
>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>> +
>> +               int i;
>> +
>> +               for (i = 0; i < genpd->state_count; i++) {
>
> To be sure you have valid data, you should hold the genpd lock here.
>

At some point while testing with calling suspend from the power_off 
handler, the cpu would go to sleep with the lock held, hence using this 
seq-file would not work.

while I agree, I think it is not super likely that a 
domain/child/devices/states are added or removed at this point (the DT 
is parsed already), would using list_for_each_entry_safe be safe enough ?

>> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
>> +                                  genpd->name,
>> +                                  genpd->states[i].name,
>> +                                  genpd->states[i].power_on_latency_ns,
>> +                                  genpd->states[i].power_off_latency_ns,
>> +                                  genpd->states[i].power_off_latency_ns
>> +                                  + genpd->states[i].power_on_latency_ns);
>> +               }
>> +
>> +       }
>> +
>> +       seq_puts(s, "\n");
>> +
>> +       return 0;
>> +}
>> +
>> +static int pm_genpd_states_open(struct inode *inode, struct file *file)
>> +{
>> +       return single_open(file, pm_genpd_states_show, NULL);
>> +}
>> +
>> +static const struct file_operations pm_genpd_states_fops = {
>> +       .open = pm_genpd_states_open,
>> +       .read = seq_read,
>> +       .llseek = seq_lseek,
>> +       .release = single_release,
>> +};
>> +
>> +static int pm_genpd_timing_show(struct seq_file *s, void *data)
>> +{
>> +       struct generic_pm_domain *genpd;
>> +
>> +       seq_puts(s, "\n    Domain Devices, Timings in ns\n");
>> +       seq_puts(s,
>> +                "                       Stop/Start Save/Restore, Effective\n");
>> +       seq_puts(s,
>> +                "----------------------------------------------------  ---\n");
>> +
>
> You must hold the gpd_list_lock while traversing the gpd list.
>
>
>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>> +               struct pm_domain_data *pm_data;
>> +
>> +               seq_printf(s, "%-30s", genpd->name);
>> +
>
> You must hold the genpd lock while traversing the device list.
>
>> +               list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
>> +                       struct gpd_timing_data *td = &to_gpd_data(pm_data)->td;
>> +
>> +                       if (!pm_data->dev->of_node)
>> +                               continue;
>> +
>> +                       seq_printf(s,
>> +                                  "\n    %-20s %-6lld/%-6lld %-6lld/%-6lld,%lld %s%s",
>> +                                  pm_data->dev->of_node->full_name,
>> +                                  td->stop_latency_ns, td->start_latency_ns,
>> +                                  td->save_state_latency_ns,
>> +                                  td->restore_state_latency_ns,
>
> This needs a re-base as these values have been merged.
>
>> +                                  td->effective_constraint_ns,
>> +                                  td->cached_stop_ok ? "(cached stop) " : "",
>> +                                  td->constraint_changed ? "(changed)" : "");
>> +               }
>> +               seq_puts(s, "\n");
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int pm_genpd_timing_open(struct inode *inode, struct file *file)
>> +{
>> +       return single_open(file, pm_genpd_timing_show, NULL);
>> +}
>> +
>> +static const struct file_operations pm_genpd_timing_fops = {
>> +       .open = pm_genpd_timing_open,
>> +       .read = seq_read,
>> +       .llseek = seq_lseek,
>> +       .release = single_release,
>> +};
>> +
>>   static int __init pm_genpd_debug_init(void)
>>   {
>> -       struct dentry *d;
>> +       struct dentry *d = NULL;
>>
>>          pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
>>
>> -       if (!pm_genpd_debugfs_dir)
>> -               return -ENOMEM;
>> +       if (pm_genpd_debugfs_dir)
>
> In case when CONFIG_DEBUG_FS is unset, this doesn't work very well, as
> pm_genpd_debugfs_dir will contain an error code.
>
> Since you are anyway make quite big change to the debugfs support for
> genpd, perhaps you can try to fix that up as well!?

Ah yes ok, will do.

>
>> +               d = debugfs_create_file("summary", S_IRUGO,
>> +                               pm_genpd_debugfs_dir, NULL,
>> +                               &pm_genpd_summary_fops);
>> +       if (d)
>> +               d = debugfs_create_file("states", S_IRUGO,
>> +                               pm_genpd_debugfs_dir, NULL,
>> +                               &pm_genpd_states_fops);
>> +       if (d)
>> +               d = debugfs_create_file("timings", S_IRUGO,
>> +                               pm_genpd_debugfs_dir, NULL,
>> +                               &pm_genpd_timing_fops);
>> +       if (d)
>> +               return 0;
>>
>> -       d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
>> -                       pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops);
>> -       if (!d)
>> -               return -ENOMEM;
>> +       debugfs_remove_recursive(pm_genpd_debugfs_dir /*can be null*/);
>>
>> -       return 0;
>> +       return -ENOMEM;
>>   }
>>   late_initcall(pm_genpd_debug_init);
>>
>
> Kind regards
> Uffe
>

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

* [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
@ 2015-12-16 11:07       ` Marc Titinger
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-12-16 11:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/12/2015 12:46, Ulf Hansson wrote:
> On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:


Hi Ulf,

thanks for the review, comments and questions below.

Best Regards,
Marc.

>> From: Marc Titinger <mtitinger@baylibre.com>
>>
>> This purpose of these debug seq-files is to help investigate
>> generic power domain state transitions, based on device constraints.
>> requires the "multiple states" patches from Axel Haslam.
>
> This last sentence doesn't belong in the change-log, please remove it.
>
>>
>> also rename 'summary' from 'pm_genpd_summary'
>>
>> sample output for 'states'
>> ==========================
>>
>>    Domain             State name        Eval = 2200nter + Exit = Min_off_on (ns)
>> -----------------------------------------------------------------------
>> a53_pd               cluster-sleep-0      1500000+800000=2300000
>> a57_pd               d1-retention         1000000+800000=1800000
>> a57_pd               cluster-sleep-0      1500000+800000=2300000
>>
>> sample output for 'timings'
>> ===========================
>>
>>      Domain Devices, Timings in ns
>>                         Stop/Start Save/Restore, Effective
>> ----------------------------------------------------  ---
>> a53_pd
>>      /cpus/cpu at 100        1060  /660    1580  /1940  ,0 (cached stop)
>>      /cpus/cpu at 101        1060  /740    1520  /1600  ,0 (cached stop)
>>      /cpus/cpu at 102        880   /620    1380  /1780  ,0 (cached stop)
>>      /cpus/cpu at 103        1080  /640    1340  /1600  ,0 (cached stop)
>> a57_pd
>>      /cpus/cpu at 0          1160  /740    3280  /1800  ,0 (cached stop)
>>      /cpus/cpu at 1          780   /1400   1440  /2080  ,0 (cached stop)
>>      /D1                  600   /540    7140  /6420  ,2199460 (cached stop)
>>
>> Signed-off-by: Marc Titinger <mtitinger@baylibre.com>
>
> A general comment. Static functions in genpd shall start with one of
> the following prefix.
>
> genpd_*
> _genpd_*
> __genpd_*
>
> Please change accordingly.

Many static routines were already prefixed like the exported functions 
with "pm_", shall I make a separate patch for this renaming ?

>
>> ---
>>   drivers/base/power/domain.c | 115 +++++++++++++++++++++++++++++++++++++++++---
>>   1 file changed, 107 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index c300293..9a0df09 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -2169,21 +2169,120 @@ static const struct file_operations pm_genpd_summary_fops = {
>>          .release = single_release,
>>   };
>>
>> +static int pm_genpd_states_show(struct seq_file *s, void *data)
>> +{
>> +       struct generic_pm_domain *genpd;
>> +
>> +       seq_puts(s,
>> +                "\n  Domain             State name        Enter + Exit = Min_off_on (ns)\n");
>> +       seq_puts(s,
>> +                "-----------------------------------------------------------------------\n");
>> +
>
> You must hold the gpd_list_lock while traversing the gpd list.
>
>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>> +
>> +               int i;
>> +
>> +               for (i = 0; i < genpd->state_count; i++) {
>
> To be sure you have valid data, you should hold the genpd lock here.
>

At some point while testing with calling suspend from the power_off 
handler, the cpu would go to sleep with the lock held, hence using this 
seq-file would not work.

while I agree, I think it is not super likely that a 
domain/child/devices/states are added or removed at this point (the DT 
is parsed already), would using list_for_each_entry_safe be safe enough ?

>> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
>> +                                  genpd->name,
>> +                                  genpd->states[i].name,
>> +                                  genpd->states[i].power_on_latency_ns,
>> +                                  genpd->states[i].power_off_latency_ns,
>> +                                  genpd->states[i].power_off_latency_ns
>> +                                  + genpd->states[i].power_on_latency_ns);
>> +               }
>> +
>> +       }
>> +
>> +       seq_puts(s, "\n");
>> +
>> +       return 0;
>> +}
>> +
>> +static int pm_genpd_states_open(struct inode *inode, struct file *file)
>> +{
>> +       return single_open(file, pm_genpd_states_show, NULL);
>> +}
>> +
>> +static const struct file_operations pm_genpd_states_fops = {
>> +       .open = pm_genpd_states_open,
>> +       .read = seq_read,
>> +       .llseek = seq_lseek,
>> +       .release = single_release,
>> +};
>> +
>> +static int pm_genpd_timing_show(struct seq_file *s, void *data)
>> +{
>> +       struct generic_pm_domain *genpd;
>> +
>> +       seq_puts(s, "\n    Domain Devices, Timings in ns\n");
>> +       seq_puts(s,
>> +                "                       Stop/Start Save/Restore, Effective\n");
>> +       seq_puts(s,
>> +                "----------------------------------------------------  ---\n");
>> +
>
> You must hold the gpd_list_lock while traversing the gpd list.
>
>
>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>> +               struct pm_domain_data *pm_data;
>> +
>> +               seq_printf(s, "%-30s", genpd->name);
>> +
>
> You must hold the genpd lock while traversing the device list.
>
>> +               list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
>> +                       struct gpd_timing_data *td = &to_gpd_data(pm_data)->td;
>> +
>> +                       if (!pm_data->dev->of_node)
>> +                               continue;
>> +
>> +                       seq_printf(s,
>> +                                  "\n    %-20s %-6lld/%-6lld %-6lld/%-6lld,%lld %s%s",
>> +                                  pm_data->dev->of_node->full_name,
>> +                                  td->stop_latency_ns, td->start_latency_ns,
>> +                                  td->save_state_latency_ns,
>> +                                  td->restore_state_latency_ns,
>
> This needs a re-base as these values have been merged.
>
>> +                                  td->effective_constraint_ns,
>> +                                  td->cached_stop_ok ? "(cached stop) " : "",
>> +                                  td->constraint_changed ? "(changed)" : "");
>> +               }
>> +               seq_puts(s, "\n");
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int pm_genpd_timing_open(struct inode *inode, struct file *file)
>> +{
>> +       return single_open(file, pm_genpd_timing_show, NULL);
>> +}
>> +
>> +static const struct file_operations pm_genpd_timing_fops = {
>> +       .open = pm_genpd_timing_open,
>> +       .read = seq_read,
>> +       .llseek = seq_lseek,
>> +       .release = single_release,
>> +};
>> +
>>   static int __init pm_genpd_debug_init(void)
>>   {
>> -       struct dentry *d;
>> +       struct dentry *d = NULL;
>>
>>          pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
>>
>> -       if (!pm_genpd_debugfs_dir)
>> -               return -ENOMEM;
>> +       if (pm_genpd_debugfs_dir)
>
> In case when CONFIG_DEBUG_FS is unset, this doesn't work very well, as
> pm_genpd_debugfs_dir will contain an error code.
>
> Since you are anyway make quite big change to the debugfs support for
> genpd, perhaps you can try to fix that up as well!?

Ah yes ok, will do.

>
>> +               d = debugfs_create_file("summary", S_IRUGO,
>> +                               pm_genpd_debugfs_dir, NULL,
>> +                               &pm_genpd_summary_fops);
>> +       if (d)
>> +               d = debugfs_create_file("states", S_IRUGO,
>> +                               pm_genpd_debugfs_dir, NULL,
>> +                               &pm_genpd_states_fops);
>> +       if (d)
>> +               d = debugfs_create_file("timings", S_IRUGO,
>> +                               pm_genpd_debugfs_dir, NULL,
>> +                               &pm_genpd_timing_fops);
>> +       if (d)
>> +               return 0;
>>
>> -       d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
>> -                       pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops);
>> -       if (!d)
>> -               return -ENOMEM;
>> +       debugfs_remove_recursive(pm_genpd_debugfs_dir /*can be null*/);
>>
>> -       return 0;
>> +       return -ENOMEM;
>>   }
>>   late_initcall(pm_genpd_debug_init);
>>
>
> Kind regards
> Uffe
>

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

* Re: [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
  2015-12-16 11:07       ` Marc Titinger
@ 2015-12-16 12:48         ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-16 12:48 UTC (permalink / raw)
  To: Marc Titinger
  Cc: Lina Iyer, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	Axel Haslam

[...]

>>
>> A general comment. Static functions in genpd shall start with one of
>> the following prefix.
>>
>> genpd_*
>> _genpd_*
>> __genpd_*
>>
>> Please change accordingly.
>
>
> Many static routines were already prefixed like the exported functions with
> "pm_", shall I make a separate patch for this renaming ?

My point is that I don't want it to becomes worse.

If you follow the above rule for new changes, I am happy.

Whether you want to send a separate patch fixing the other existing
name to be consistent with above rule, I would also be happy. :-)

>
>
>>
>>> ---
>>>   drivers/base/power/domain.c | 115
>>> +++++++++++++++++++++++++++++++++++++++++---
>>>   1 file changed, 107 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>>> index c300293..9a0df09 100644
>>> --- a/drivers/base/power/domain.c
>>> +++ b/drivers/base/power/domain.c
>>> @@ -2169,21 +2169,120 @@ static const struct file_operations
>>> pm_genpd_summary_fops = {
>>>          .release = single_release,
>>>   };
>>>
>>> +static int pm_genpd_states_show(struct seq_file *s, void *data)
>>> +{
>>> +       struct generic_pm_domain *genpd;
>>> +
>>> +       seq_puts(s,
>>> +                "\n  Domain             State name        Enter + Exit =
>>> Min_off_on (ns)\n");
>>> +       seq_puts(s,
>>> +
>>> "-----------------------------------------------------------------------\n");
>>> +
>>
>>
>> You must hold the gpd_list_lock while traversing the gpd list.
>>
>>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>>> +
>>> +               int i;
>>> +
>>> +               for (i = 0; i < genpd->state_count; i++) {
>>
>>
>> To be sure you have valid data, you should hold the genpd lock here.
>>
>
> At some point while testing with calling suspend from the power_off handler,
> the cpu would go to sleep with the lock held, hence using this seq-file
> would not work.

That seems like a bad behaviour during suspend. Why does it hold the lock?

On the other it shouldn't matter as userspace can't access the debugfs
nodes, since its frozen at those times, right!?

>
> while I agree, I think it is not super likely that a
> domain/child/devices/states are added or removed at this point (the DT is
> parsed already), would using list_for_each_entry_safe be safe enough ?

No it's not.

The gpd_list is protected with the gdp_list_lock, which is needed
because new genpds can be added at any point.

You also need the genpd lock here, as otherwise you may print the
latency-values in the middle of when these are being updated.

>
>
>>> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
>>> +                                  genpd->name,
>>> +                                  genpd->states[i].name,
>>> +                                  genpd->states[i].power_on_latency_ns,
>>> +                                  genpd->states[i].power_off_latency_ns,
>>> +                                  genpd->states[i].power_off_latency_ns
>>> +                                  +
>>> genpd->states[i].power_on_latency_ns);
>>> +               }
>>> +
>>> +       }
>>> +
>>> +       seq_puts(s, "\n");
>>> +
>>> +       return 0;
>>> +}
>>> +

[...]

Kind regards
Uffe

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

* [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
@ 2015-12-16 12:48         ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-16 12:48 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

>>
>> A general comment. Static functions in genpd shall start with one of
>> the following prefix.
>>
>> genpd_*
>> _genpd_*
>> __genpd_*
>>
>> Please change accordingly.
>
>
> Many static routines were already prefixed like the exported functions with
> "pm_", shall I make a separate patch for this renaming ?

My point is that I don't want it to becomes worse.

If you follow the above rule for new changes, I am happy.

Whether you want to send a separate patch fixing the other existing
name to be consistent with above rule, I would also be happy. :-)

>
>
>>
>>> ---
>>>   drivers/base/power/domain.c | 115
>>> +++++++++++++++++++++++++++++++++++++++++---
>>>   1 file changed, 107 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>>> index c300293..9a0df09 100644
>>> --- a/drivers/base/power/domain.c
>>> +++ b/drivers/base/power/domain.c
>>> @@ -2169,21 +2169,120 @@ static const struct file_operations
>>> pm_genpd_summary_fops = {
>>>          .release = single_release,
>>>   };
>>>
>>> +static int pm_genpd_states_show(struct seq_file *s, void *data)
>>> +{
>>> +       struct generic_pm_domain *genpd;
>>> +
>>> +       seq_puts(s,
>>> +                "\n  Domain             State name        Enter + Exit =
>>> Min_off_on (ns)\n");
>>> +       seq_puts(s,
>>> +
>>> "-----------------------------------------------------------------------\n");
>>> +
>>
>>
>> You must hold the gpd_list_lock while traversing the gpd list.
>>
>>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>>> +
>>> +               int i;
>>> +
>>> +               for (i = 0; i < genpd->state_count; i++) {
>>
>>
>> To be sure you have valid data, you should hold the genpd lock here.
>>
>
> At some point while testing with calling suspend from the power_off handler,
> the cpu would go to sleep with the lock held, hence using this seq-file
> would not work.

That seems like a bad behaviour during suspend. Why does it hold the lock?

On the other it shouldn't matter as userspace can't access the debugfs
nodes, since its frozen at those times, right!?

>
> while I agree, I think it is not super likely that a
> domain/child/devices/states are added or removed at this point (the DT is
> parsed already), would using list_for_each_entry_safe be safe enough ?

No it's not.

The gpd_list is protected with the gdp_list_lock, which is needed
because new genpds can be added at any point.

You also need the genpd lock here, as otherwise you may print the
latency-values in the middle of when these are being updated.

>
>
>>> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
>>> +                                  genpd->name,
>>> +                                  genpd->states[i].name,
>>> +                                  genpd->states[i].power_on_latency_ns,
>>> +                                  genpd->states[i].power_off_latency_ns,
>>> +                                  genpd->states[i].power_off_latency_ns
>>> +                                  +
>>> genpd->states[i].power_on_latency_ns);
>>> +               }
>>> +
>>> +       }
>>> +
>>> +       seq_puts(s, "\n");
>>> +
>>> +       return 0;
>>> +}
>>> +

[...]

Kind regards
Uffe

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

* Re: [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
  2015-12-16 12:48         ` Ulf Hansson
@ 2015-12-16 14:12           ` Marc Titinger
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-12-16 14:12 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Lina Iyer, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	Axel Haslam

On 16/12/2015 13:48, Ulf Hansson wrote:
> [...]
>
>>>
>>> A general comment. Static functions in genpd shall start with one of
>>> the following prefix.
>>>
>>> genpd_*
>>> _genpd_*
>>> __genpd_*
>>>
>>> Please change accordingly.
>>
>>
>> Many static routines were already prefixed like the exported functions with
>> "pm_", shall I make a separate patch for this renaming ?
>
> My point is that I don't want it to becomes worse.
>
> If you follow the above rule for new changes, I am happy.
>
> Whether you want to send a separate patch fixing the other existing
> name to be consistent with above rule, I would also be happy. :-)

Fair enough, I'll do a renaming patch :)

>
>>
>>
>>>
>>>> ---
>>>>    drivers/base/power/domain.c | 115
>>>> +++++++++++++++++++++++++++++++++++++++++---
>>>>    1 file changed, 107 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>>>> index c300293..9a0df09 100644
>>>> --- a/drivers/base/power/domain.c
>>>> +++ b/drivers/base/power/domain.c
>>>> @@ -2169,21 +2169,120 @@ static const struct file_operations
>>>> pm_genpd_summary_fops = {
>>>>           .release = single_release,
>>>>    };
>>>>
>>>> +static int pm_genpd_states_show(struct seq_file *s, void *data)
>>>> +{
>>>> +       struct generic_pm_domain *genpd;
>>>> +
>>>> +       seq_puts(s,
>>>> +                "\n  Domain             State name        Enter + Exit =
>>>> Min_off_on (ns)\n");
>>>> +       seq_puts(s,
>>>> +
>>>> "-----------------------------------------------------------------------\n");
>>>> +
>>>
>>>
>>> You must hold the gpd_list_lock while traversing the gpd list.
>>>
>>>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>>>> +
>>>> +               int i;
>>>> +
>>>> +               for (i = 0; i < genpd->state_count; i++) {
>>>
>>>
>>> To be sure you have valid data, you should hold the genpd lock here.
>>>
>>
>> At some point while testing with calling suspend from the power_off handler,
>> the cpu would go to sleep with the lock held, hence using this seq-file
>> would not work.
>
> That seems like a bad behaviour during suspend. Why does it hold the lock?

that was in the scenario where 2 or more cpus are devices of the same 
power domain. IIRC you would have something like:

arm_enter_idle_state(cpu)
	pm_runtime_put_sync
		rpm_suspend
		__rpm_get_callback
			pm_genpd_runtime_suspend
				[Take lock]
				->platform code to enter sleep...

and race condition with another cpu of the same cluster trying to 
suspend or resume at the same time. it is a bad behaviour, I cannot test
the os-initiated mode here but I assume this is done differently and is 
no longer an issue (sorry for not being more specific).

>
> On the other it shouldn't matter as userspace can't access the debugfs
> nodes, since its frozen at those times, right!?

you can have cpu_j off, and cpu_i running the shell, in the scenario 
above. But since this was while hacking calling psci from 
genpd.power_off, I'm not sure it's worth mentioning...

>
>>
>> while I agree, I think it is not super likely that a
>> domain/child/devices/states are added or removed at this point (the DT is
>> parsed already), would using list_for_each_entry_safe be safe enough ?
>
> No it's not.
>
> The gpd_list is protected with the gdp_list_lock, which is needed
> because new genpds can be added at any point.
>
> You also need the genpd lock here, as otherwise you may print the
> latency-values in the middle of when these are being updated.

Understood, I'll put the lock back.

>
>>
>>
>>>> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
>>>> +                                  genpd->name,
>>>> +                                  genpd->states[i].name,
>>>> +                                  genpd->states[i].power_on_latency_ns,
>>>> +                                  genpd->states[i].power_off_latency_ns,
>>>> +                                  genpd->states[i].power_off_latency_ns
>>>> +                                  +
>>>> genpd->states[i].power_on_latency_ns);
>>>> +               }
>>>> +
>>>> +       }
>>>> +
>>>> +       seq_puts(s, "\n");
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>
> [...]
>
> Kind regards
> Uffe
>


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

* [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files
@ 2015-12-16 14:12           ` Marc Titinger
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Titinger @ 2015-12-16 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/12/2015 13:48, Ulf Hansson wrote:
> [...]
>
>>>
>>> A general comment. Static functions in genpd shall start with one of
>>> the following prefix.
>>>
>>> genpd_*
>>> _genpd_*
>>> __genpd_*
>>>
>>> Please change accordingly.
>>
>>
>> Many static routines were already prefixed like the exported functions with
>> "pm_", shall I make a separate patch for this renaming ?
>
> My point is that I don't want it to becomes worse.
>
> If you follow the above rule for new changes, I am happy.
>
> Whether you want to send a separate patch fixing the other existing
> name to be consistent with above rule, I would also be happy. :-)

Fair enough, I'll do a renaming patch :)

>
>>
>>
>>>
>>>> ---
>>>>    drivers/base/power/domain.c | 115
>>>> +++++++++++++++++++++++++++++++++++++++++---
>>>>    1 file changed, 107 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>>>> index c300293..9a0df09 100644
>>>> --- a/drivers/base/power/domain.c
>>>> +++ b/drivers/base/power/domain.c
>>>> @@ -2169,21 +2169,120 @@ static const struct file_operations
>>>> pm_genpd_summary_fops = {
>>>>           .release = single_release,
>>>>    };
>>>>
>>>> +static int pm_genpd_states_show(struct seq_file *s, void *data)
>>>> +{
>>>> +       struct generic_pm_domain *genpd;
>>>> +
>>>> +       seq_puts(s,
>>>> +                "\n  Domain             State name        Enter + Exit =
>>>> Min_off_on (ns)\n");
>>>> +       seq_puts(s,
>>>> +
>>>> "-----------------------------------------------------------------------\n");
>>>> +
>>>
>>>
>>> You must hold the gpd_list_lock while traversing the gpd list.
>>>
>>>> +       list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
>>>> +
>>>> +               int i;
>>>> +
>>>> +               for (i = 0; i < genpd->state_count; i++) {
>>>
>>>
>>> To be sure you have valid data, you should hold the genpd lock here.
>>>
>>
>> At some point while testing with calling suspend from the power_off handler,
>> the cpu would go to sleep with the lock held, hence using this seq-file
>> would not work.
>
> That seems like a bad behaviour during suspend. Why does it hold the lock?

that was in the scenario where 2 or more cpus are devices of the same 
power domain. IIRC you would have something like:

arm_enter_idle_state(cpu)
	pm_runtime_put_sync
		rpm_suspend
		__rpm_get_callback
			pm_genpd_runtime_suspend
				[Take lock]
				->platform code to enter sleep...

and race condition with another cpu of the same cluster trying to 
suspend or resume at the same time. it is a bad behaviour, I cannot test
the os-initiated mode here but I assume this is done differently and is 
no longer an issue (sorry for not being more specific).

>
> On the other it shouldn't matter as userspace can't access the debugfs
> nodes, since its frozen at those times, right!?

you can have cpu_j off, and cpu_i running the shell, in the scenario 
above. But since this was while hacking calling psci from 
genpd.power_off, I'm not sure it's worth mentioning...

>
>>
>> while I agree, I think it is not super likely that a
>> domain/child/devices/states are added or removed at this point (the DT is
>> parsed already), would using list_for_each_entry_safe be safe enough ?
>
> No it's not.
>
> The gpd_list is protected with the gdp_list_lock, which is needed
> because new genpds can be added at any point.
>
> You also need the genpd lock here, as otherwise you may print the
> latency-values in the middle of when these are being updated.

Understood, I'll put the lock back.

>
>>
>>
>>>> +                       seq_printf(s, "%-20s %-20s %lld+%lld=%lld\n",
>>>> +                                  genpd->name,
>>>> +                                  genpd->states[i].name,
>>>> +                                  genpd->states[i].power_on_latency_ns,
>>>> +                                  genpd->states[i].power_off_latency_ns,
>>>> +                                  genpd->states[i].power_off_latency_ns
>>>> +                                  +
>>>> genpd->states[i].power_on_latency_ns);
>>>> +               }
>>>> +
>>>> +       }
>>>> +
>>>> +       seq_puts(s, "\n");
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>
> [...]
>
> Kind regards
> Uffe
>

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

* Re: [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
  2015-12-15 10:07       ` Marc Titinger
@ 2015-12-16 21:36         ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-16 21:36 UTC (permalink / raw)
  To: Marc Titinger
  Cc: Ulf Hansson, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	Axel Haslam, Marc Titinger

On Tue, Dec 15 2015 at 03:07 -0700, Marc Titinger wrote:
>On 10/12/2015 17:53, Ulf Hansson wrote:
>>On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:

>>>Similarly, devices can register power-states into the cluster domain, in
>>>a manner consistent with idle-states.
>>
>>I don't get this. Can you please elaborate?
>
>
>Alexes addition of "power states" to the power domains was to have a 
>better representation of features of power controllers. For instance 
>QoS may prevent to enter/exit complete power-off, but setting the core 
>voltage to say 0.7v is feasible in terms of timing, and still better 
>than full-power-on etc... Hence the domain has a list of possible 
>states to chose upon, between full power-on and full-power-off, and 
>genpd will call the platform code for this.
>
>Now, this patch maps the idle-states as possible power states for the 
>domain: upon the last CPU runtime_put, the domain can chose the 
>deepest
>state that can be reached given the enter/exit time available, and 
>call the platform code for this. This selected state can be any of:
>* cluster-sleep (power OFF)
>* cluster-retention A (L2RAM retention for instance)
>* cluster-retention B (some device is still on, like PMU or bus 
>analyzer, healthckeck IP etc...)
>...
>* cluster-on, but lower voltage A
>* cluster-on, but lower voltage B
>etc...
>
>Put short: CPUs, like any other devices in the domain may register a 
>power state.
>
>>
>>>
>>>This is a attempt to address device-retention states for devices that
>>>are not hooked to runtime-pm, but feature a retention state handled by
>>>the same firmware that handles idle-states. For instance a L2 caches.
>>
>>I guess whether devices may use runtime PM or not, they still can be
>>attached to a PM domain with multiple power states?
>
>yes.
>
>From what I understand, it seems like you want to have a constraint on a
domain state based on the device's idle state. This seems more like a
job for a governor. You could write a governor that chooses the domain
state based on these dependencies.

I am not sure this can be solved generically without increasing the
complexity of genpd idle states.

Thanks,
Lina

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

* [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT
@ 2015-12-16 21:36         ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2015-12-16 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 15 2015 at 03:07 -0700, Marc Titinger wrote:
>On 10/12/2015 17:53, Ulf Hansson wrote:
>>On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:

>>>Similarly, devices can register power-states into the cluster domain, in
>>>a manner consistent with idle-states.
>>
>>I don't get this. Can you please elaborate?
>
>
>Alexes addition of "power states" to the power domains was to have a 
>better representation of features of power controllers. For instance 
>QoS may prevent to enter/exit complete power-off, but setting the core 
>voltage to say 0.7v is feasible in terms of timing, and still better 
>than full-power-on etc... Hence the domain has a list of possible 
>states to chose upon, between full power-on and full-power-off, and 
>genpd will call the platform code for this.
>
>Now, this patch maps the idle-states as possible power states for the 
>domain: upon the last CPU runtime_put, the domain can chose the 
>deepest
>state that can be reached given the enter/exit time available, and 
>call the platform code for this. This selected state can be any of:
>* cluster-sleep (power OFF)
>* cluster-retention A (L2RAM retention for instance)
>* cluster-retention B (some device is still on, like PMU or bus 
>analyzer, healthckeck IP etc...)
>...
>* cluster-on, but lower voltage A
>* cluster-on, but lower voltage B
>etc...
>
>Put short: CPUs, like any other devices in the domain may register a 
>power state.
>
>>
>>>
>>>This is a attempt to address device-retention states for devices that
>>>are not hooked to runtime-pm, but feature a retention state handled by
>>>the same firmware that handles idle-states. For instance a L2 caches.
>>
>>I guess whether devices may use runtime PM or not, they still can be
>>attached to a PM domain with multiple power states?
>
>yes.
>
>From what I understand, it seems like you want to have a constraint on a
domain state based on the device's idle state. This seems more like a
job for a governor. You could write a governor that chooses the domain
state based on these dependencies.

I am not sure this can be solved generically without increasing the
complexity of genpd idle states.

Thanks,
Lina

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

* Re: [PATCH RFC 01/27] PM / Domains: core changes for multiple states
  2015-12-09 13:58     ` Ulf Hansson
@ 2015-12-17 17:58       ` Axel Haslam
  -1 siblings, 0 replies; 166+ messages in thread
From: Axel Haslam @ 2015-12-17 17:58 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Lina Iyer, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	Marc Titinger, Axel Haslam

On Wed, Dec 9, 2015 at 2:58 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>>
>> From: Axel Haslam <ahaslam@baylibre.com>
>>
>> Add the core changes to be able to declare multiple states.
>> When trying to set a power domain to off, genpd will be able to choose
>> from an array of states declared by the platform. The power on and off
>> latencies are now tied to a state.
>
> I would like to get an answer to *why* we need this.
>
> For example, we should mention that some HWs supports these multiple
> states - at least.
>
>>
>> States should be declared in ascending order from shallowest to deepest,
>
> I guess *should* isn't good enough. Perhaps *shall* is better?
>
>> deepest meaning the state which takes longer to enter and exit.
>>
>> the power_off and power_on function can use the 'state_idx' field of the
>> generic_pm_domain structure, to distinguish between the different states
>> and act accordingly.
>
> This needs some more explanation.
>
> First, please use the wording of "callbacks", like ->power_on() to
> better describe what function you are talking about.
> Second, what is "state_idx"? What's does it really tell the SOC PM
> domain driver here?
>
>>
>> Example:
>>
>> static int pd1_power_on(struct generic_pm_domain *domain)
>> {
>>         /* domain->state_idx = state the domain is coming from */
>> }
>>
>> static int pd1_power_off(struct generic_pm_domain *domain)
>> {
>>         /* domain->state_idx = desired powered off state */
>> }
>>
>> const struct genpd_power_state pd_states[] = {
>>         {
>>                 .name = "RET",
>>                 .power_on_latency_ns = ON_LATENCY_FAST,
>>                 .power_off_latency_ns = OFF_LATENCY_FAST,
>>         },
>>         {
>>                 .name = "DEEP_RET",
>>                 .power_on_latency_ns = ON_LATENCY_MED,
>>                 .power_off_latency_ns = OFF_LATENCY_MED,
>>         },
>>         {
>>                 .name = "OFF",
>>                 .power_on_latency_ns = ON_LATENCY_SLOW,
>>                 .power_off_latency_ns = OFF_LATENCY_SLOW,
>>         }
>> };
>>
>> struct generic_pm_domain pd1 = {
>>         .name = "PD1",
>>         .power_on = pd1_power_on,
>>         .power_off = pd1_power_off,
>>         [...]
>> };
>>
>> int xxx_init_pm_domain(){
>>
>>         pd1->state = copy_of(pd_states);
>>         pd1->state_count = ARRAY_SIZE(pd_states);
>>         pm_genpd_init(pd1, true);
>>
>> }
>
> Well, even if the above describes this quite good, I think it better
> belongs in the Documentation rather than in the change log.
>
> Can we try to the improve the text in the change-log instead?
>
>>
>> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> [Lina: Modified genpd state initialization and remove use of
>> save_state_latency_ns in genpd timing data]
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/base/power/domain.c          | 136 +++++++++++++++++++++++++++++++++--
>>  drivers/base/power/domain_governor.c |  13 +++-
>>  include/linux/pm_domain.h            |  10 +++
>>  3 files changed, 151 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index e03b1ad..3242854 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -34,6 +34,12 @@
>>         __ret;                                                  \
>>  })
>>
>> +#define GENPD_MAX_NAME_SIZE 20
>> +
>> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>
> Please avoid forward declarations.
>
> Also, we have just got rid of all *name* based genpd API/functions. I
> don't want us to start adding another.
>
> Or perhaps it's just the name of the function that I don't like!? :-)
>
>> +                                      const struct genpd_power_state *st,
>> +                                      unsigned int st_count);
>> +
>>  static LIST_HEAD(gpd_list);
>>  static DEFINE_MUTEX(gpd_list_lock);
>>
>> @@ -102,6 +108,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
>>
>>  static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>  {
>> +       unsigned int state_idx = genpd->state_idx;
>>         ktime_t time_start;
>>         s64 elapsed_ns;
>>         int ret;
>> @@ -118,10 +125,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>                 return ret;
>>
>>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
>> -       if (elapsed_ns <= genpd->power_on_latency_ns)
>> +       if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
>>                 return ret;
>>
>> -       genpd->power_on_latency_ns = elapsed_ns;
>> +       genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
>>         genpd->max_off_time_changed = true;
>>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>>                  genpd->name, "on", elapsed_ns);
>> @@ -131,6 +138,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>
>>  static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>>  {
>> +       unsigned int state_idx = genpd->state_idx;
>>         ktime_t time_start;
>>         s64 elapsed_ns;
>>         int ret;
>> @@ -147,10 +155,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>>                 return ret;
>>
>>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
>> -       if (elapsed_ns <= genpd->power_off_latency_ns)
>> +       if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
>>                 return ret;
>>
>> -       genpd->power_off_latency_ns = elapsed_ns;
>> +       genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
>>         genpd->max_off_time_changed = true;
>>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>>                  genpd->name, "off", elapsed_ns);
>> @@ -582,6 +590,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
>>             || atomic_read(&genpd->sd_count) > 0)
>>                 return;
>>
>> +       /* Choose the deepest state when suspending */
>> +       genpd->state_idx = genpd->state_count - 1;
>>         genpd_power_off(genpd, timed);
>>
>>         genpd->status = GPD_STATE_POWER_OFF;
>> @@ -1205,6 +1215,61 @@ static void genpd_free_dev_data(struct device *dev,
>>         dev_pm_put_subsys_data(dev);
>>  }
>>
>> +static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>
> In this patch I would rather just add *one* new "alloc" function and
> name it like below.
>
> static int genpd_alloc_default_state(struct generic_pm_domain *genpd)
>
> I assume the name I suggest for it, indicates what it needs to do and
> *not* needs to do.

Hi Ulf,

Thanks for your thorough review!
i will implement your suggestions for the next spin,

However I have a doubt about this comment, do you mean that i should get rid of
genpd_alloc_states_data completly? i had a static number of states before
but that was droped because o wasted memory if no states were needed.

if you just meant that it should be added in a separate patch, since i
will be sqashing
this patch with "PM / Domains: make governor select deepest state"   can
i keep it here? maybe it should  go with the dt parsing patch from Marc?

Regards
Axel


>
>> +                                  const struct genpd_power_state *st,
>> +                                  unsigned int st_count)
>> +{
>> +       int ret = 0;
>> +       unsigned int i;
>> +
>> +       if (IS_ERR_OR_NULL(genpd)) {
>> +               ret = -EINVAL;
>> +               goto err;
>> +       }
>> +
>> +       if (!st || (st_count < 1)) {
>> +               ret = -EINVAL;
>> +               goto err;
>> +       }
>> +
>> +       /* Allocate the local memory to keep the states for this genpd */
>> +       genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
>> +       if (!genpd->states) {
>> +               ret = -ENOMEM;
>> +               goto err;
>> +       }
>> +
>> +       for (i = 0; i < st_count; i++) {
>> +               genpd->states[i].power_on_latency_ns =
>> +                       st[i].power_on_latency_ns;
>> +               genpd->states[i].power_off_latency_ns =
>> +                       st[i].power_off_latency_ns;
>> +       }
>> +
>> +       /*
>> +        * Copy the latency values To keep compatibility with
>> +        * platforms that are not converted to use the multiple states.
>> +        * This will be removed once all platforms are converted to use
>> +        * multiple states. note that non converted platforms will use the
>> +        * default single off state.
>> +        */
>> +       if (genpd->power_on_latency_ns != 0)
>> +               genpd->states[0].power_on_latency_ns =
>> +                               genpd->power_on_latency_ns;
>> +
>> +       if (genpd->power_off_latency_ns != 0)
>> +               genpd->states[0].power_off_latency_ns =
>> +                               genpd->power_off_latency_ns;
>> +
>> +       genpd->state_count = st_count;
>> +
>> +       /* to save memory, Name allocation will happen if debug is enabled */
>
> Urgh. :-)
>
> I instead suggest we skip the entire "name" attribute" and just use
> the state_idx to provide the same information.
>
> For sure at this point, this information won't be interpreted by
> "anybody". Reading an integer value instead of string, shouldn't be
> that difficult to understand.
>
> Future wise, if we see that it could be beneficial to add the "name"
> attribute, we can do that then.
>
> Removing the name attribute will also simplify this patch, quite much.
> Can you please do that.
>
>> +       pm_genpd_alloc_states_names(genpd, st, st_count);
>> +
>> +err:
>> +       return ret;
>> +}
>> +
>>  /**
>>   * __pm_genpd_add_device - Add a device to an I/O PM domain.
>>   * @genpd: PM domain to add the device to.
>> @@ -1459,6 +1524,15 @@ static int pm_genpd_default_restore_state(struct device *dev)
>>  void pm_genpd_init(struct generic_pm_domain *genpd,
>>                    struct dev_power_governor *gov, bool is_off)
>>  {
>> +       int ret;
>> +       static const struct genpd_power_state genpd_default_off[] = {
>> +               {
>> +                       .name = "OFF",
>> +                       .power_off_latency_ns = 0,
>> +                       .power_on_latency_ns = 0,
>> +               },
>> +       };
>
> I suggest you remove this and instead handle that within
> genpd_alloc_default_state().
>
>> +
>>         if (IS_ERR_OR_NULL(genpd))
>>                 return;
>>
>> @@ -1503,6 +1577,19 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>>                 genpd->dev_ops.start = pm_clk_resume;
>>         }
>>
>> +       /*
>> +        * Allocate the default state if genpd states
>> +        * are not already defined.
>> +        */
>> +       if (!genpd->state_count) {
>> +               ret = genpd_alloc_states_data(genpd, genpd_default_off, 1);
>
> Call the new "genpd_alloc_default_state()" instead.
>
>> +               if (ret)
>> +                       return;
>> +       }
>> +
>> +       /* Assume the deepest state on init*/
>> +       genpd->state_idx = genpd->state_count - 1;
>
> When the PM domain is powered on, in other words the genpd->status ==
> GPD_STATE_ACTIVE, I guess this value doesn't matter much.
>
> Although, what if the PM domain is powered off, don't you need to
> respect the value that might have been assigned by the SoC PM domain
> driver? Else you may at the next power on, indicate that you are
> coming from a state that's not the correct one.
>
> Perhaps, you should only set genpd->state_idx = 0, from
> genpd_alloc_default_state() and in the other case leave the value as
> is?
>
>> +
>>         mutex_lock(&gpd_list_lock);
>>         list_add(&genpd->gpd_list_node, &gpd_list);
>>         mutex_unlock(&gpd_list_lock);
>> @@ -1822,6 +1909,33 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>>  #include <linux/kobject.h>
>>  static struct dentry *pm_genpd_debugfs_dir;
>>
>> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>> +                                      const struct genpd_power_state *st,
>> +                                      unsigned int st_count)
>> +{
>> +       unsigned int i;
>> +
>> +       if (IS_ERR_OR_NULL(genpd))
>> +               return -EINVAL;
>> +
>> +       if (genpd->state_count != st_count) {
>> +               pr_err("Invalid allocated state count\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       for (i = 0; i < st_count; i++) {
>> +               genpd->states[i].name = kstrndup(st[i].name,
>> +                               GENPD_MAX_NAME_SIZE, GFP_KERNEL);
>> +               if (!genpd->states[i].name) {
>> +                       pr_err("%s Failed to allocate state %d name.\n",
>> +                               genpd->name, i);
>> +                       return -ENOMEM;
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>  /*
>>   * TODO: This function is a slightly modified version of rtpm_status_show
>>   * from sysfs.c, so generalize it.
>> @@ -1855,6 +1969,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
>>                 [GPD_STATE_ACTIVE] = "on",
>>                 [GPD_STATE_POWER_OFF] = "off"
>>         };
>> +       unsigned int state_idx = genpd->state_idx;
>>         struct pm_domain_data *pm_data;
>>         const char *kobj_path;
>>         struct gpd_link *link;
>> @@ -1866,7 +1981,11 @@ static int pm_genpd_summary_one(struct seq_file *s,
>>
>>         if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
>>                 goto exit;
>> -       seq_printf(s, "%-30s  %-15s ", genpd->name, status_lookup[genpd->status]);
>> +
>> +       seq_printf(s, "%-30s  %-15s  ", genpd->name,
>> +                  (genpd->status == GPD_STATE_POWER_OFF) ?
>> +                  genpd->states[state_idx].name :
>> +                  status_lookup[genpd->status]);
>>
>>         /*
>>          * Modifications on the list require holding locks on both
>> @@ -1954,4 +2073,11 @@ static void __exit pm_genpd_debug_exit(void)
>>         debugfs_remove_recursive(pm_genpd_debugfs_dir);
>>  }
>>  __exitcall(pm_genpd_debug_exit);
>> +#else
>> +static inline int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>> +                                       const struct genpd_power_state *st,
>> +                                       unsigned int st_count)
>> +{
>> +       return 0;
>> +}
>>  #endif /* CONFIG_PM_ADVANCED_DEBUG */
>> diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
>> index e60dd12..b4984f5 100644
>> --- a/drivers/base/power/domain_governor.c
>> +++ b/drivers/base/power/domain_governor.c
>> @@ -125,8 +125,12 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>>                 return genpd->cached_power_down_ok;
>>         }
>>
>> -       off_on_time_ns = genpd->power_off_latency_ns +
>> -                               genpd->power_on_latency_ns;
>> +       /*
>> +        * Use the only available state, until multiple state support is added
>> +        * to the governor.
>> +        */
>
> So you want to delay this step into a later patch. I am fine with
> that, but you need to state that in the change-log.
>
> Perhaps it's better to say that we will always try with the
> shallowest/deepest off state, and just ignore the other states in this
> phase?
>
>> +       off_on_time_ns = genpd->states[0].power_off_latency_ns +
>> +                               genpd->states[0].power_on_latency_ns;
>
> If you think my above idea seems reasonable, that should change the above to:
>
> off_on_time_ns = genpd->states[genpd->state_count - 1].power_off_latency_ns +
>      genpd->states[genpd->state_count - 1].power_on_latency_ns;
>
>>
>>         min_off_time_ns = -1;
>>         /*
>> @@ -203,8 +207,11 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>>          * The difference between the computed minimum subdomain or device off
>>          * time and the time needed to turn the domain on is the maximum
>>          * theoretical time this domain can spend in the "off" state.
>> +        * Use the only available state, until multiple state support is added
>> +        * to the governor.
>>          */
>> -       genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
>> +       genpd->max_off_time_ns = min_off_time_ns -
>> +               genpd->states[0].power_on_latency_ns;
>
> Ditto.
>
>>         return true;
>>  }
>>
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index ba4ced3..11763cf 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -37,6 +37,12 @@ struct gpd_dev_ops {
>>         bool (*active_wakeup)(struct device *dev);
>>  };
>>
>> +struct genpd_power_state {
>> +       char *name;
>
> As stated, suggest to remove "name".
>
>> +       s64 power_off_latency_ns;
>> +       s64 power_on_latency_ns;
>> +};
>> +
>>  struct generic_pm_domain {
>>         struct dev_pm_domain domain;    /* PM domain operations */
>>         struct list_head gpd_list_node; /* Node in the global PM domains list */
>> @@ -66,6 +72,10 @@ struct generic_pm_domain {
>>         void (*detach_dev)(struct generic_pm_domain *domain,
>>                            struct device *dev);
>>         unsigned int flags;             /* Bit field of configs for genpd */
>> +       struct genpd_power_state *states;
>> +       unsigned int state_count; /* number of states */
>> +       unsigned int state_idx; /* state that genpd will go to when off */
>> +
>>  };
>>
>>  static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
>> --
>> 2.1.4
>>
>
> Kind regards
> Uffe

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

* [PATCH RFC 01/27] PM / Domains: core changes for multiple states
@ 2015-12-17 17:58       ` Axel Haslam
  0 siblings, 0 replies; 166+ messages in thread
From: Axel Haslam @ 2015-12-17 17:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 9, 2015 at 2:58 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> From: Axel Haslam <ahaslam+renesas@baylibre.com>
>>
>> From: Axel Haslam <ahaslam@baylibre.com>
>>
>> Add the core changes to be able to declare multiple states.
>> When trying to set a power domain to off, genpd will be able to choose
>> from an array of states declared by the platform. The power on and off
>> latencies are now tied to a state.
>
> I would like to get an answer to *why* we need this.
>
> For example, we should mention that some HWs supports these multiple
> states - at least.
>
>>
>> States should be declared in ascending order from shallowest to deepest,
>
> I guess *should* isn't good enough. Perhaps *shall* is better?
>
>> deepest meaning the state which takes longer to enter and exit.
>>
>> the power_off and power_on function can use the 'state_idx' field of the
>> generic_pm_domain structure, to distinguish between the different states
>> and act accordingly.
>
> This needs some more explanation.
>
> First, please use the wording of "callbacks", like ->power_on() to
> better describe what function you are talking about.
> Second, what is "state_idx"? What's does it really tell the SOC PM
> domain driver here?
>
>>
>> Example:
>>
>> static int pd1_power_on(struct generic_pm_domain *domain)
>> {
>>         /* domain->state_idx = state the domain is coming from */
>> }
>>
>> static int pd1_power_off(struct generic_pm_domain *domain)
>> {
>>         /* domain->state_idx = desired powered off state */
>> }
>>
>> const struct genpd_power_state pd_states[] = {
>>         {
>>                 .name = "RET",
>>                 .power_on_latency_ns = ON_LATENCY_FAST,
>>                 .power_off_latency_ns = OFF_LATENCY_FAST,
>>         },
>>         {
>>                 .name = "DEEP_RET",
>>                 .power_on_latency_ns = ON_LATENCY_MED,
>>                 .power_off_latency_ns = OFF_LATENCY_MED,
>>         },
>>         {
>>                 .name = "OFF",
>>                 .power_on_latency_ns = ON_LATENCY_SLOW,
>>                 .power_off_latency_ns = OFF_LATENCY_SLOW,
>>         }
>> };
>>
>> struct generic_pm_domain pd1 = {
>>         .name = "PD1",
>>         .power_on = pd1_power_on,
>>         .power_off = pd1_power_off,
>>         [...]
>> };
>>
>> int xxx_init_pm_domain(){
>>
>>         pd1->state = copy_of(pd_states);
>>         pd1->state_count = ARRAY_SIZE(pd_states);
>>         pm_genpd_init(pd1, true);
>>
>> }
>
> Well, even if the above describes this quite good, I think it better
> belongs in the Documentation rather than in the change log.
>
> Can we try to the improve the text in the change-log instead?
>
>>
>> Signed-off-by: Axel Haslam <ahaslam+renesas@baylibre.com>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> [Lina: Modified genpd state initialization and remove use of
>> save_state_latency_ns in genpd timing data]
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> ---
>>  drivers/base/power/domain.c          | 136 +++++++++++++++++++++++++++++++++--
>>  drivers/base/power/domain_governor.c |  13 +++-
>>  include/linux/pm_domain.h            |  10 +++
>>  3 files changed, 151 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
>> index e03b1ad..3242854 100644
>> --- a/drivers/base/power/domain.c
>> +++ b/drivers/base/power/domain.c
>> @@ -34,6 +34,12 @@
>>         __ret;                                                  \
>>  })
>>
>> +#define GENPD_MAX_NAME_SIZE 20
>> +
>> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>
> Please avoid forward declarations.
>
> Also, we have just got rid of all *name* based genpd API/functions. I
> don't want us to start adding another.
>
> Or perhaps it's just the name of the function that I don't like!? :-)
>
>> +                                      const struct genpd_power_state *st,
>> +                                      unsigned int st_count);
>> +
>>  static LIST_HEAD(gpd_list);
>>  static DEFINE_MUTEX(gpd_list_lock);
>>
>> @@ -102,6 +108,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
>>
>>  static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>  {
>> +       unsigned int state_idx = genpd->state_idx;
>>         ktime_t time_start;
>>         s64 elapsed_ns;
>>         int ret;
>> @@ -118,10 +125,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>                 return ret;
>>
>>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
>> -       if (elapsed_ns <= genpd->power_on_latency_ns)
>> +       if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
>>                 return ret;
>>
>> -       genpd->power_on_latency_ns = elapsed_ns;
>> +       genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
>>         genpd->max_off_time_changed = true;
>>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>>                  genpd->name, "on", elapsed_ns);
>> @@ -131,6 +138,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
>>
>>  static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>>  {
>> +       unsigned int state_idx = genpd->state_idx;
>>         ktime_t time_start;
>>         s64 elapsed_ns;
>>         int ret;
>> @@ -147,10 +155,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
>>                 return ret;
>>
>>         elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
>> -       if (elapsed_ns <= genpd->power_off_latency_ns)
>> +       if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns)
>>                 return ret;
>>
>> -       genpd->power_off_latency_ns = elapsed_ns;
>> +       genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
>>         genpd->max_off_time_changed = true;
>>         pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
>>                  genpd->name, "off", elapsed_ns);
>> @@ -582,6 +590,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
>>             || atomic_read(&genpd->sd_count) > 0)
>>                 return;
>>
>> +       /* Choose the deepest state when suspending */
>> +       genpd->state_idx = genpd->state_count - 1;
>>         genpd_power_off(genpd, timed);
>>
>>         genpd->status = GPD_STATE_POWER_OFF;
>> @@ -1205,6 +1215,61 @@ static void genpd_free_dev_data(struct device *dev,
>>         dev_pm_put_subsys_data(dev);
>>  }
>>
>> +static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>
> In this patch I would rather just add *one* new "alloc" function and
> name it like below.
>
> static int genpd_alloc_default_state(struct generic_pm_domain *genpd)
>
> I assume the name I suggest for it, indicates what it needs to do and
> *not* needs to do.

Hi Ulf,

Thanks for your thorough review!
i will implement your suggestions for the next spin,

However I have a doubt about this comment, do you mean that i should get rid of
genpd_alloc_states_data completly? i had a static number of states before
but that was droped because o wasted memory if no states were needed.

if you just meant that it should be added in a separate patch, since i
will be sqashing
this patch with "PM / Domains: make governor select deepest state"   can
i keep it here? maybe it should  go with the dt parsing patch from Marc?

Regards
Axel


>
>> +                                  const struct genpd_power_state *st,
>> +                                  unsigned int st_count)
>> +{
>> +       int ret = 0;
>> +       unsigned int i;
>> +
>> +       if (IS_ERR_OR_NULL(genpd)) {
>> +               ret = -EINVAL;
>> +               goto err;
>> +       }
>> +
>> +       if (!st || (st_count < 1)) {
>> +               ret = -EINVAL;
>> +               goto err;
>> +       }
>> +
>> +       /* Allocate the local memory to keep the states for this genpd */
>> +       genpd->states = kcalloc(st_count, sizeof(*st), GFP_KERNEL);
>> +       if (!genpd->states) {
>> +               ret = -ENOMEM;
>> +               goto err;
>> +       }
>> +
>> +       for (i = 0; i < st_count; i++) {
>> +               genpd->states[i].power_on_latency_ns =
>> +                       st[i].power_on_latency_ns;
>> +               genpd->states[i].power_off_latency_ns =
>> +                       st[i].power_off_latency_ns;
>> +       }
>> +
>> +       /*
>> +        * Copy the latency values To keep compatibility with
>> +        * platforms that are not converted to use the multiple states.
>> +        * This will be removed once all platforms are converted to use
>> +        * multiple states. note that non converted platforms will use the
>> +        * default single off state.
>> +        */
>> +       if (genpd->power_on_latency_ns != 0)
>> +               genpd->states[0].power_on_latency_ns =
>> +                               genpd->power_on_latency_ns;
>> +
>> +       if (genpd->power_off_latency_ns != 0)
>> +               genpd->states[0].power_off_latency_ns =
>> +                               genpd->power_off_latency_ns;
>> +
>> +       genpd->state_count = st_count;
>> +
>> +       /* to save memory, Name allocation will happen if debug is enabled */
>
> Urgh. :-)
>
> I instead suggest we skip the entire "name" attribute" and just use
> the state_idx to provide the same information.
>
> For sure at this point, this information won't be interpreted by
> "anybody". Reading an integer value instead of string, shouldn't be
> that difficult to understand.
>
> Future wise, if we see that it could be beneficial to add the "name"
> attribute, we can do that then.
>
> Removing the name attribute will also simplify this patch, quite much.
> Can you please do that.
>
>> +       pm_genpd_alloc_states_names(genpd, st, st_count);
>> +
>> +err:
>> +       return ret;
>> +}
>> +
>>  /**
>>   * __pm_genpd_add_device - Add a device to an I/O PM domain.
>>   * @genpd: PM domain to add the device to.
>> @@ -1459,6 +1524,15 @@ static int pm_genpd_default_restore_state(struct device *dev)
>>  void pm_genpd_init(struct generic_pm_domain *genpd,
>>                    struct dev_power_governor *gov, bool is_off)
>>  {
>> +       int ret;
>> +       static const struct genpd_power_state genpd_default_off[] = {
>> +               {
>> +                       .name = "OFF",
>> +                       .power_off_latency_ns = 0,
>> +                       .power_on_latency_ns = 0,
>> +               },
>> +       };
>
> I suggest you remove this and instead handle that within
> genpd_alloc_default_state().
>
>> +
>>         if (IS_ERR_OR_NULL(genpd))
>>                 return;
>>
>> @@ -1503,6 +1577,19 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
>>                 genpd->dev_ops.start = pm_clk_resume;
>>         }
>>
>> +       /*
>> +        * Allocate the default state if genpd states
>> +        * are not already defined.
>> +        */
>> +       if (!genpd->state_count) {
>> +               ret = genpd_alloc_states_data(genpd, genpd_default_off, 1);
>
> Call the new "genpd_alloc_default_state()" instead.
>
>> +               if (ret)
>> +                       return;
>> +       }
>> +
>> +       /* Assume the deepest state on init*/
>> +       genpd->state_idx = genpd->state_count - 1;
>
> When the PM domain is powered on, in other words the genpd->status ==
> GPD_STATE_ACTIVE, I guess this value doesn't matter much.
>
> Although, what if the PM domain is powered off, don't you need to
> respect the value that might have been assigned by the SoC PM domain
> driver? Else you may at the next power on, indicate that you are
> coming from a state that's not the correct one.
>
> Perhaps, you should only set genpd->state_idx = 0, from
> genpd_alloc_default_state() and in the other case leave the value as
> is?
>
>> +
>>         mutex_lock(&gpd_list_lock);
>>         list_add(&genpd->gpd_list_node, &gpd_list);
>>         mutex_unlock(&gpd_list_lock);
>> @@ -1822,6 +1909,33 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
>>  #include <linux/kobject.h>
>>  static struct dentry *pm_genpd_debugfs_dir;
>>
>> +static int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>> +                                      const struct genpd_power_state *st,
>> +                                      unsigned int st_count)
>> +{
>> +       unsigned int i;
>> +
>> +       if (IS_ERR_OR_NULL(genpd))
>> +               return -EINVAL;
>> +
>> +       if (genpd->state_count != st_count) {
>> +               pr_err("Invalid allocated state count\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       for (i = 0; i < st_count; i++) {
>> +               genpd->states[i].name = kstrndup(st[i].name,
>> +                               GENPD_MAX_NAME_SIZE, GFP_KERNEL);
>> +               if (!genpd->states[i].name) {
>> +                       pr_err("%s Failed to allocate state %d name.\n",
>> +                               genpd->name, i);
>> +                       return -ENOMEM;
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>  /*
>>   * TODO: This function is a slightly modified version of rtpm_status_show
>>   * from sysfs.c, so generalize it.
>> @@ -1855,6 +1969,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
>>                 [GPD_STATE_ACTIVE] = "on",
>>                 [GPD_STATE_POWER_OFF] = "off"
>>         };
>> +       unsigned int state_idx = genpd->state_idx;
>>         struct pm_domain_data *pm_data;
>>         const char *kobj_path;
>>         struct gpd_link *link;
>> @@ -1866,7 +1981,11 @@ static int pm_genpd_summary_one(struct seq_file *s,
>>
>>         if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
>>                 goto exit;
>> -       seq_printf(s, "%-30s  %-15s ", genpd->name, status_lookup[genpd->status]);
>> +
>> +       seq_printf(s, "%-30s  %-15s  ", genpd->name,
>> +                  (genpd->status == GPD_STATE_POWER_OFF) ?
>> +                  genpd->states[state_idx].name :
>> +                  status_lookup[genpd->status]);
>>
>>         /*
>>          * Modifications on the list require holding locks on both
>> @@ -1954,4 +2073,11 @@ static void __exit pm_genpd_debug_exit(void)
>>         debugfs_remove_recursive(pm_genpd_debugfs_dir);
>>  }
>>  __exitcall(pm_genpd_debug_exit);
>> +#else
>> +static inline int pm_genpd_alloc_states_names(struct generic_pm_domain *genpd,
>> +                                       const struct genpd_power_state *st,
>> +                                       unsigned int st_count)
>> +{
>> +       return 0;
>> +}
>>  #endif /* CONFIG_PM_ADVANCED_DEBUG */
>> diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
>> index e60dd12..b4984f5 100644
>> --- a/drivers/base/power/domain_governor.c
>> +++ b/drivers/base/power/domain_governor.c
>> @@ -125,8 +125,12 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>>                 return genpd->cached_power_down_ok;
>>         }
>>
>> -       off_on_time_ns = genpd->power_off_latency_ns +
>> -                               genpd->power_on_latency_ns;
>> +       /*
>> +        * Use the only available state, until multiple state support is added
>> +        * to the governor.
>> +        */
>
> So you want to delay this step into a later patch. I am fine with
> that, but you need to state that in the change-log.
>
> Perhaps it's better to say that we will always try with the
> shallowest/deepest off state, and just ignore the other states in this
> phase?
>
>> +       off_on_time_ns = genpd->states[0].power_off_latency_ns +
>> +                               genpd->states[0].power_on_latency_ns;
>
> If you think my above idea seems reasonable, that should change the above to:
>
> off_on_time_ns = genpd->states[genpd->state_count - 1].power_off_latency_ns +
>      genpd->states[genpd->state_count - 1].power_on_latency_ns;
>
>>
>>         min_off_time_ns = -1;
>>         /*
>> @@ -203,8 +207,11 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
>>          * The difference between the computed minimum subdomain or device off
>>          * time and the time needed to turn the domain on is the maximum
>>          * theoretical time this domain can spend in the "off" state.
>> +        * Use the only available state, until multiple state support is added
>> +        * to the governor.
>>          */
>> -       genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
>> +       genpd->max_off_time_ns = min_off_time_ns -
>> +               genpd->states[0].power_on_latency_ns;
>
> Ditto.
>
>>         return true;
>>  }
>>
>> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
>> index ba4ced3..11763cf 100644
>> --- a/include/linux/pm_domain.h
>> +++ b/include/linux/pm_domain.h
>> @@ -37,6 +37,12 @@ struct gpd_dev_ops {
>>         bool (*active_wakeup)(struct device *dev);
>>  };
>>
>> +struct genpd_power_state {
>> +       char *name;
>
> As stated, suggest to remove "name".
>
>> +       s64 power_off_latency_ns;
>> +       s64 power_on_latency_ns;
>> +};
>> +
>>  struct generic_pm_domain {
>>         struct dev_pm_domain domain;    /* PM domain operations */
>>         struct list_head gpd_list_node; /* Node in the global PM domains list */
>> @@ -66,6 +72,10 @@ struct generic_pm_domain {
>>         void (*detach_dev)(struct generic_pm_domain *domain,
>>                            struct device *dev);
>>         unsigned int flags;             /* Bit field of configs for genpd */
>> +       struct genpd_power_state *states;
>> +       unsigned int state_count; /* number of states */
>> +       unsigned int state_idx; /* state that genpd will go to when off */
>> +
>>  };
>>
>>  static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
>> --
>> 2.1.4
>>
>
> Kind regards
> Uffe

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

* Re: [PATCH RFC 01/27] PM / Domains: core changes for multiple states
  2015-12-17 17:58       ` Axel Haslam
@ 2015-12-17 21:19         ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-17 21:19 UTC (permalink / raw)
  To: Axel Haslam
  Cc: Lina Iyer, Kevin Hilman, linux-pm, linux-arm-kernel,
	Geert Uytterhoeven, Krzysztof Kozłowski, msivasub,
	Andy Gross, Stephen Boyd, linux-arm-msm, Lorenzo Pieralisi,
	Marc Titinger, Axel Haslam

[...]

>>> +static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>>
>> In this patch I would rather just add *one* new "alloc" function and
>> name it like below.
>>
>> static int genpd_alloc_default_state(struct generic_pm_domain *genpd)
>>
>> I assume the name I suggest for it, indicates what it needs to do and
>> *not* needs to do.
>
> Hi Ulf,
>
> Thanks for your thorough review!
> i will implement your suggestions for the next spin,

Great, thanks!

>
> However I have a doubt about this comment, do you mean that i should get rid of
> genpd_alloc_states_data completly? i had a static number of states before

Yes, in this patch - but we still want to alloc the data on the heap.

Just alloc a state struct with size of one array.

> but that was droped because o wasted memory if no states were needed.

There will always be at least *one* state, so we shouldn't waste any
memory following my suggestion above.

>
> if you just meant that it should be added in a separate patch, since i
> will be sqashing

I think you need to go through review comments for each patch
separately. In the end that might very well mean that you should
completely drop some patches, rework some and even create some some
new.

> this patch with "PM / Domains: make governor select deepest state"   can
> i keep it here? maybe it should  go with the dt parsing patch from Marc?

I don't think so.

Try to keep each logical change in a separate patch. That makes it
easier to review and thus also to accept patches.

[...]

Kind regards
Uffe

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

* [PATCH RFC 01/27] PM / Domains: core changes for multiple states
@ 2015-12-17 21:19         ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2015-12-17 21:19 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

>>> +static int genpd_alloc_states_data(struct generic_pm_domain *genpd,
>>
>> In this patch I would rather just add *one* new "alloc" function and
>> name it like below.
>>
>> static int genpd_alloc_default_state(struct generic_pm_domain *genpd)
>>
>> I assume the name I suggest for it, indicates what it needs to do and
>> *not* needs to do.
>
> Hi Ulf,
>
> Thanks for your thorough review!
> i will implement your suggestions for the next spin,

Great, thanks!

>
> However I have a doubt about this comment, do you mean that i should get rid of
> genpd_alloc_states_data completly? i had a static number of states before

Yes, in this patch - but we still want to alloc the data on the heap.

Just alloc a state struct with size of one array.

> but that was droped because o wasted memory if no states were needed.

There will always be at least *one* state, so we shouldn't waste any
memory following my suggestion above.

>
> if you just meant that it should be added in a separate patch, since i
> will be sqashing

I think you need to go through review comments for each patch
separately. In the end that might very well mean that you should
completely drop some patches, rework some and even create some some
new.

> this patch with "PM / Domains: make governor select deepest state"   can
> i keep it here? maybe it should  go with the dt parsing patch from Marc?

I don't think so.

Try to keep each logical change in a separate patch. That makes it
easier to review and thus also to accept patches.

[...]

Kind regards
Uffe

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2015-11-17 22:37   ` Lina Iyer
@ 2016-01-14 14:42     ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-14 14:42 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> Generic Power Domains currently support turning on/off only in process
> context. This prevents the usage of PM domains for domains that could be
> powered on/off in a context where IRQs are disabled. Many such domains
> exist today and do not get powered off, when the IRQ safe devices in
> that domain are powered off, because of this limitation.
>
> However, not all domains can operate in IRQ safe contexts. Genpd
> therefore, has to support both cases where the domain may or may not
> operate in IRQ safe contexts. Configuring genpd to use an appropriate
> lock for that domain, would allow domains that have IRQ safe devices to
> runtime suspend and resume, in atomic context.
>
> To achieve domain specific locking, set the domain's ->flag to
> GENPD_FLAG_IRQ_SAFE while defining the domain. This indicates that genpd
> should use a spinlock instead of a mutex for locking the domain. Locking
> is abstracted through genpd_lock() and genpd_unlock() functions that use
> the flag to determine the appropriate lock to be used for that domain.

Please add a newline here.

> Domains that have lower latency to suspend and resume and can operate

I believe I get the point, as we must not keep IRQs disabled for too
long. Perhaps that can be a bit clarified?

> with IRQs disabled may now be able to save power, when the component
> devices and sub-domains are idle at runtime.
>
> The restriction this imposes on the domain hierarchy is that sub-domains
> and all devices in the IRQ safe domain's hierarchy also have to be IRQ
> safe, so that we dont try to lock a mutex, while holding a spinlock.

Isn't it the opposite as you described here?

So holding a mutex while taking a spinlock should be okay, but not the
other way around.

Regarding power on:
*)
If we get a request to power on the master, its spinlock will be
taken, but its subdomain isn't touched.

**)
If we get a request to power on the subdomain, it will first try to
power its master. That means, first we take the mutex of the
subdomain, then as the master is IRQ safe we will take its spinlock.
We power on the master, releases its spinlock, continues to power on
the subdomain and then releases its mutex.

Regarding power off:
*)
Trying to power off the master will fail unless the atomic "sd_count"
is tested for zero. In that execution path, its subdomain isn't
touched.

**)
Trying to power off a subdomain, thus executing in non-atomic context,
starts by taking its mutex then continue doing the power off things.
When completed, the sd_count for its master will be decreased and then
we schedule a power off work for it, to allow it to be powered off at
some point later. Even if we wouldn't schedule a work, and instead
tried to power off the master within the same context it should be
safe to take a spinlock.

I haven't thought about the IRQ safe devices yet, but I guess similar
applies to them.

> Non-IRQ safe domains may continue to have devices and sub-domains that
> may or may not be IRQ safe.

According the my comments above, no I don't think so. Non-IRQ safe
domains can't have subdomains that is IRQ safe.

Before I continue to review the code, let's align on the above first
as I think it's important we get this right first. :-)

[...]

Kind regards
Uffe

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-14 14:42     ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-14 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
> Generic Power Domains currently support turning on/off only in process
> context. This prevents the usage of PM domains for domains that could be
> powered on/off in a context where IRQs are disabled. Many such domains
> exist today and do not get powered off, when the IRQ safe devices in
> that domain are powered off, because of this limitation.
>
> However, not all domains can operate in IRQ safe contexts. Genpd
> therefore, has to support both cases where the domain may or may not
> operate in IRQ safe contexts. Configuring genpd to use an appropriate
> lock for that domain, would allow domains that have IRQ safe devices to
> runtime suspend and resume, in atomic context.
>
> To achieve domain specific locking, set the domain's ->flag to
> GENPD_FLAG_IRQ_SAFE while defining the domain. This indicates that genpd
> should use a spinlock instead of a mutex for locking the domain. Locking
> is abstracted through genpd_lock() and genpd_unlock() functions that use
> the flag to determine the appropriate lock to be used for that domain.

Please add a newline here.

> Domains that have lower latency to suspend and resume and can operate

I believe I get the point, as we must not keep IRQs disabled for too
long. Perhaps that can be a bit clarified?

> with IRQs disabled may now be able to save power, when the component
> devices and sub-domains are idle at runtime.
>
> The restriction this imposes on the domain hierarchy is that sub-domains
> and all devices in the IRQ safe domain's hierarchy also have to be IRQ
> safe, so that we dont try to lock a mutex, while holding a spinlock.

Isn't it the opposite as you described here?

So holding a mutex while taking a spinlock should be okay, but not the
other way around.

Regarding power on:
*)
If we get a request to power on the master, its spinlock will be
taken, but its subdomain isn't touched.

**)
If we get a request to power on the subdomain, it will first try to
power its master. That means, first we take the mutex of the
subdomain, then as the master is IRQ safe we will take its spinlock.
We power on the master, releases its spinlock, continues to power on
the subdomain and then releases its mutex.

Regarding power off:
*)
Trying to power off the master will fail unless the atomic "sd_count"
is tested for zero. In that execution path, its subdomain isn't
touched.

**)
Trying to power off a subdomain, thus executing in non-atomic context,
starts by taking its mutex then continue doing the power off things.
When completed, the sd_count for its master will be decreased and then
we schedule a power off work for it, to allow it to be powered off at
some point later. Even if we wouldn't schedule a work, and instead
tried to power off the master within the same context it should be
safe to take a spinlock.

I haven't thought about the IRQ safe devices yet, but I guess similar
applies to them.

> Non-IRQ safe domains may continue to have devices and sub-domains that
> may or may not be IRQ safe.

According the my comments above, no I don't think so. Non-IRQ safe
domains can't have subdomains that is IRQ safe.

Before I continue to review the code, let's align on the above first
as I think it's important we get this right first. :-)

[...]

Kind regards
Uffe

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-14 14:42     ` Ulf Hansson
@ 2016-01-14 18:33       ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-14 18:33 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

On Thu, Jan 14 2016 at 07:42 -0700, Ulf Hansson wrote:
>On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> Generic Power Domains currently support turning on/off only in process
>> context. This prevents the usage of PM domains for domains that could be
>> powered on/off in a context where IRQs are disabled. Many such domains
>> exist today and do not get powered off, when the IRQ safe devices in
>> that domain are powered off, because of this limitation.
>>
>> However, not all domains can operate in IRQ safe contexts. Genpd
>> therefore, has to support both cases where the domain may or may not
>> operate in IRQ safe contexts. Configuring genpd to use an appropriate
>> lock for that domain, would allow domains that have IRQ safe devices to
>> runtime suspend and resume, in atomic context.
>>
>> To achieve domain specific locking, set the domain's ->flag to
>> GENPD_FLAG_IRQ_SAFE while defining the domain. This indicates that genpd
>> should use a spinlock instead of a mutex for locking the domain. Locking
>> is abstracted through genpd_lock() and genpd_unlock() functions that use
>> the flag to determine the appropriate lock to be used for that domain.
>
>Please add a newline here.
>
Sure.
>> Domains that have lower latency to suspend and resume and can operate
>
>I believe I get the point, as we must not keep IRQs disabled for too
>long. Perhaps that can be a bit clarified?
>
>> with IRQs disabled may now be able to save power, when the component
>> devices and sub-domains are idle at runtime.
>>
>> The restriction this imposes on the domain hierarchy is that sub-domains
>> and all devices in the IRQ safe domain's hierarchy also have to be IRQ
>> safe, so that we dont try to lock a mutex, while holding a spinlock.
>
>Isn't it the opposite as you described here?
>
>So holding a mutex while taking a spinlock should be okay, but not the
>other way around.
>
That's exactly what I describe. We *dont* try to lock a mutex while
holding a spinlock.

>Regarding power on:
>*)
>If we get a request to power on the master, its spinlock will be
>taken, but its subdomain isn't touched.
>
True. Powering on a domain should not power on its subdomains. So we are
good here.

>**)
>If we get a request to power on the subdomain, it will first try to
>power its master. That means, first we take the mutex of the
>subdomain, then as the master is IRQ safe we will take its spinlock.
>We power on the master, releases its spinlock, continues to power on
>the subdomain and then releases its mutex.
>
The implied assumption in having a subdomain that is IRQ-safe while the
parent domain is non-IRQ-safe is that the parent is never powered on/off
in the context of the subdomain, it is assumed always ON.

>Regarding power off:
>*)
>Trying to power off the master will fail unless the atomic "sd_count"
>is tested for zero. In that execution path, its subdomain isn't
>touched.
>
True for IRQ-safe parents with IRQ-safe subdomains as well as non-IRQ
safe parents with IRQ-safe subdomains.

>**)
>Trying to power off a subdomain, thus executing in non-atomic context,
>starts by taking its mutex then continue doing the power off things.
>When completed, the sd_count for its master will be decreased and then
>we schedule a power off work for it, to allow it to be powered off at
>some point later. Even if we wouldn't schedule a work, and instead
>tried to power off the master within the same context it should be
>safe to take a spinlock.
>
This is true as well for IRQ-safe subdomains that are attached to
IRQ-safe parents. But if the parent is not IRQ-safe then the domains is
left powered ON.

>I haven't thought about the IRQ safe devices yet, but I guess similar
>applies to them.
>
The same rules apply to IRQ safe devices.

Here is an excerpt from pm_genpd_runtime_resume -

/* If power.irq_safe, the PM domain is never powered off. */
if (dev->power.irq_safe) {
        timed = false;
	goto out;
}

>> Non-IRQ safe domains may continue to have devices and sub-domains that
>> may or may not be IRQ safe.
>
>According the my comments above, no I don't think so. Non-IRQ safe
>domains can't have subdomains that is IRQ safe.
>
Here is a summary of the combinations as I understand. Correct me if I
am wrong, please.

*) Non-IRQ safe parent + IRQ-safe subdomain
   Attach subdomain:
   	- parent mutex held and subdomain spinlocked.
   Power-on:
	- subdomain assumes parent is always ON or powered on before the
	subdomain is powered ON.
   Power-off:
   	- parent is not powered off even if the subdomain was the last
	active domain.

**) IRQ-safe parent + IRQ-safe subdomain
    Attach subdomain:
    	- parent spinlock held and subdomain spinlocked.
    Power-on:
	- subdomain may power on the parent.
    Power-off:
    	- last active sub-domain will power off the parent in the same
	  context.

***) IRQ-safe parent + non-IRQ-safe subdomain
    Attach subdomain:
   	- parent spinlock held and subdomain **cannot** be mutex locked.
    Power-on:
	- subdomain may power on the parent.
    Power-off:
    	- last active subdomain will be able to power off the domain

Except for the last case, we can support the others in addition to 
the currently available, with the restriction that 

- IRQ-safe parents can only have IRQ-safe subdomains and devices

- Non-IRQ safe parents may have both IRQ-safe and non-IRQ-safe
  subdomains and devices and the assumption that
	-- IRQ-safe subdomains and devices will not bother to power
	on/off their non-IRQ-safe parent.

>Before I continue to review the code, let's align on the above first
>as I think it's important we get this right first. :-)
>
Absolutely.

Thank you for your review. Was expecting this detail a review of the
concept from you :)

Thanks,
Lina

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-14 18:33       ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-14 18:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 14 2016 at 07:42 -0700, Ulf Hansson wrote:
>On 17 November 2015 at 23:37, Lina Iyer <lina.iyer@linaro.org> wrote:
>> Generic Power Domains currently support turning on/off only in process
>> context. This prevents the usage of PM domains for domains that could be
>> powered on/off in a context where IRQs are disabled. Many such domains
>> exist today and do not get powered off, when the IRQ safe devices in
>> that domain are powered off, because of this limitation.
>>
>> However, not all domains can operate in IRQ safe contexts. Genpd
>> therefore, has to support both cases where the domain may or may not
>> operate in IRQ safe contexts. Configuring genpd to use an appropriate
>> lock for that domain, would allow domains that have IRQ safe devices to
>> runtime suspend and resume, in atomic context.
>>
>> To achieve domain specific locking, set the domain's ->flag to
>> GENPD_FLAG_IRQ_SAFE while defining the domain. This indicates that genpd
>> should use a spinlock instead of a mutex for locking the domain. Locking
>> is abstracted through genpd_lock() and genpd_unlock() functions that use
>> the flag to determine the appropriate lock to be used for that domain.
>
>Please add a newline here.
>
Sure.
>> Domains that have lower latency to suspend and resume and can operate
>
>I believe I get the point, as we must not keep IRQs disabled for too
>long. Perhaps that can be a bit clarified?
>
>> with IRQs disabled may now be able to save power, when the component
>> devices and sub-domains are idle at runtime.
>>
>> The restriction this imposes on the domain hierarchy is that sub-domains
>> and all devices in the IRQ safe domain's hierarchy also have to be IRQ
>> safe, so that we dont try to lock a mutex, while holding a spinlock.
>
>Isn't it the opposite as you described here?
>
>So holding a mutex while taking a spinlock should be okay, but not the
>other way around.
>
That's exactly what I describe. We *dont* try to lock a mutex while
holding a spinlock.

>Regarding power on:
>*)
>If we get a request to power on the master, its spinlock will be
>taken, but its subdomain isn't touched.
>
True. Powering on a domain should not power on its subdomains. So we are
good here.

>**)
>If we get a request to power on the subdomain, it will first try to
>power its master. That means, first we take the mutex of the
>subdomain, then as the master is IRQ safe we will take its spinlock.
>We power on the master, releases its spinlock, continues to power on
>the subdomain and then releases its mutex.
>
The implied assumption in having a subdomain that is IRQ-safe while the
parent domain is non-IRQ-safe is that the parent is never powered on/off
in the context of the subdomain, it is assumed always ON.

>Regarding power off:
>*)
>Trying to power off the master will fail unless the atomic "sd_count"
>is tested for zero. In that execution path, its subdomain isn't
>touched.
>
True for IRQ-safe parents with IRQ-safe subdomains as well as non-IRQ
safe parents with IRQ-safe subdomains.

>**)
>Trying to power off a subdomain, thus executing in non-atomic context,
>starts by taking its mutex then continue doing the power off things.
>When completed, the sd_count for its master will be decreased and then
>we schedule a power off work for it, to allow it to be powered off at
>some point later. Even if we wouldn't schedule a work, and instead
>tried to power off the master within the same context it should be
>safe to take a spinlock.
>
This is true as well for IRQ-safe subdomains that are attached to
IRQ-safe parents. But if the parent is not IRQ-safe then the domains is
left powered ON.

>I haven't thought about the IRQ safe devices yet, but I guess similar
>applies to them.
>
The same rules apply to IRQ safe devices.

Here is an excerpt from pm_genpd_runtime_resume -

/* If power.irq_safe, the PM domain is never powered off. */
if (dev->power.irq_safe) {
        timed = false;
	goto out;
}

>> Non-IRQ safe domains may continue to have devices and sub-domains that
>> may or may not be IRQ safe.
>
>According the my comments above, no I don't think so. Non-IRQ safe
>domains can't have subdomains that is IRQ safe.
>
Here is a summary of the combinations as I understand. Correct me if I
am wrong, please.

*) Non-IRQ safe parent + IRQ-safe subdomain
   Attach subdomain:
   	- parent mutex held and subdomain spinlocked.
   Power-on:
	- subdomain assumes parent is always ON or powered on before the
	subdomain is powered ON.
   Power-off:
   	- parent is not powered off even if the subdomain was the last
	active domain.

**) IRQ-safe parent + IRQ-safe subdomain
    Attach subdomain:
    	- parent spinlock held and subdomain spinlocked.
    Power-on:
	- subdomain may power on the parent.
    Power-off:
    	- last active sub-domain will power off the parent in the same
	  context.

***) IRQ-safe parent + non-IRQ-safe subdomain
    Attach subdomain:
   	- parent spinlock held and subdomain **cannot** be mutex locked.
    Power-on:
	- subdomain may power on the parent.
    Power-off:
    	- last active subdomain will be able to power off the domain

Except for the last case, we can support the others in addition to 
the currently available, with the restriction that 

- IRQ-safe parents can only have IRQ-safe subdomains and devices

- Non-IRQ safe parents may have both IRQ-safe and non-IRQ-safe
  subdomains and devices and the assumption that
	-- IRQ-safe subdomains and devices will not bother to power
	on/off their non-IRQ-safe parent.

>Before I continue to review the code, let's align on the above first
>as I think it's important we get this right first. :-)
>
Absolutely.

Thank you for your review. Was expecting this detail a review of the
concept from you :)

Thanks,
Lina

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-14 18:33       ` Lina Iyer
@ 2016-01-15  8:55         ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-15  8:55 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

[...]

>>>
>>> The restriction this imposes on the domain hierarchy is that sub-domains
>>> and all devices in the IRQ safe domain's hierarchy also have to be IRQ
>>> safe, so that we dont try to lock a mutex, while holding a spinlock.
>>
>>
>> Isn't it the opposite as you described here?
>>
>> So holding a mutex while taking a spinlock should be okay, but not the
>> other way around.
>>
> That's exactly what I describe. We *dont* try to lock a mutex while
> holding a spinlock.

Apologize, I wasn't referring to the mutex/spinlock as that part you
state correctly.

I was reading the change log as: "*if* the parent domain is IRQ safe
everything below it (devices and subdomains) also needs to be IRQ
safe". Which I assume doesn't have to be the case.

Then below I was describing an example of an IRQ safe parent with a
non-IRQ safe subdomain, which I think should be an okay configuration.

>
>> Regarding power on:
>> *)
>> If we get a request to power on the master, its spinlock will be
>> taken, but its subdomain isn't touched.
>>
> True. Powering on a domain should not power on its subdomains. So we are
> good here.
>
>> **)
>> If we get a request to power on the subdomain, it will first try to
>> power its master. That means, first we take the mutex of the
>> subdomain, then as the master is IRQ safe we will take its spinlock.
>> We power on the master, releases its spinlock, continues to power on
>> the subdomain and then releases its mutex.
>>
> The implied assumption in having a subdomain that is IRQ-safe while the
> parent domain is non-IRQ-safe is that the parent is never powered on/off
> in the context of the subdomain, it is assumed always ON.

Yes, that follows how gendp deals with IRQ safe devices. Although, I
consider that as workaround and not a solution.

In the long run, I think IRQ safe devices should belong to IRQ safe domains.

Unless you have a specific need to apply the similar workaround for
parents and subdomains, I am suggesting that genpd shouldn't allow
such configurations.

[...]

>
>>> Non-IRQ safe domains may continue to have devices and sub-domains that
>>> may or may not be IRQ safe.
>>
>>
>> According the my comments above, no I don't think so. Non-IRQ safe
>> domains can't have subdomains that is IRQ safe.
>>
> Here is a summary of the combinations as I understand. Correct me if I
> am wrong, please.

Nice summary, it good that we discuss all possible scenarios!

>
> *) Non-IRQ safe parent + IRQ-safe subdomain

Let's name this case 1.

>   Attach subdomain:
>         - parent mutex held and subdomain spinlocked.
>   Power-on:
>         - subdomain assumes parent is always ON or powered on before the
>         subdomain is powered ON.

As stated above, what do you think of *not* dealing with this case as
I think it's not a solution but a workaround!

>   Power-off:
>         - parent is not powered off even if the subdomain was the last
>         active domain.
>
> **) IRQ-safe parent + IRQ-safe subdomain

Let's name this case 2.

>    Attach subdomain:
>         - parent spinlock held and subdomain spinlocked.
>    Power-on:
>         - subdomain may power on the parent.
>    Power-off:
>         - last active sub-domain will power off the parent in the same
>           context.

>From a genpd locking point of view, there should be no reason to power
off in same context. We should be able to deal with this via a
scheduled work for this case as well, right!?

Although, I realize that it's very useful to power off in the same
context to minimize latencies in the full blown CPU Cluster Power
Management solution.
Perhaps a separate genpd configuration flag could be added to enable
this method, as I imagine that not *all* IRQ safe domains wants to use
it.

What do you think?

>
> ***) IRQ-safe parent + non-IRQ-safe subdomain

Let's name this case 3.

>    Attach subdomain:
>         - parent spinlock held and subdomain **cannot** be mutex locked.

First, attaching shouldn't occur from atomic context.

Second, the important part is that we pick the locks in same order as
elsewhere in genpd, and of course we must not pick a mutex while
holding a spinlock.

In all cases when adding subdomains, we should start by fetching the
subdomains lock *then* the lock for the parent. The current genpd code
doesn't do that and additionally it uses nested locks.
I am going to send a patch the changes this behaviour, as I think it's
wrong and may cause deadlocks!

Following this approach means that case 1 can't be supported, as that
would mean holding a spinlock while fetching a mutex.

>    Power-on:
>         - subdomain may power on the parent.
>    Power-off:
>         - last active subdomain will be able to power off the domain
>
> Except for the last case, we can support the others in addition to the
> currently available, with the restriction that
> - IRQ-safe parents can only have IRQ-safe subdomains and devices
>
> - Non-IRQ safe parents may have both IRQ-safe and non-IRQ-safe
>  subdomains and devices and the assumption that
>         -- IRQ-safe subdomains and devices will not bother to power
>         on/off their non-IRQ-safe parent.
>

I think case 2 and case 3 should be okay to support, but I am really
questioning case 1.

Thoughts?

Kind regards
Uffe

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-15  8:55         ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-15  8:55 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

>>>
>>> The restriction this imposes on the domain hierarchy is that sub-domains
>>> and all devices in the IRQ safe domain's hierarchy also have to be IRQ
>>> safe, so that we dont try to lock a mutex, while holding a spinlock.
>>
>>
>> Isn't it the opposite as you described here?
>>
>> So holding a mutex while taking a spinlock should be okay, but not the
>> other way around.
>>
> That's exactly what I describe. We *dont* try to lock a mutex while
> holding a spinlock.

Apologize, I wasn't referring to the mutex/spinlock as that part you
state correctly.

I was reading the change log as: "*if* the parent domain is IRQ safe
everything below it (devices and subdomains) also needs to be IRQ
safe". Which I assume doesn't have to be the case.

Then below I was describing an example of an IRQ safe parent with a
non-IRQ safe subdomain, which I think should be an okay configuration.

>
>> Regarding power on:
>> *)
>> If we get a request to power on the master, its spinlock will be
>> taken, but its subdomain isn't touched.
>>
> True. Powering on a domain should not power on its subdomains. So we are
> good here.
>
>> **)
>> If we get a request to power on the subdomain, it will first try to
>> power its master. That means, first we take the mutex of the
>> subdomain, then as the master is IRQ safe we will take its spinlock.
>> We power on the master, releases its spinlock, continues to power on
>> the subdomain and then releases its mutex.
>>
> The implied assumption in having a subdomain that is IRQ-safe while the
> parent domain is non-IRQ-safe is that the parent is never powered on/off
> in the context of the subdomain, it is assumed always ON.

Yes, that follows how gendp deals with IRQ safe devices. Although, I
consider that as workaround and not a solution.

In the long run, I think IRQ safe devices should belong to IRQ safe domains.

Unless you have a specific need to apply the similar workaround for
parents and subdomains, I am suggesting that genpd shouldn't allow
such configurations.

[...]

>
>>> Non-IRQ safe domains may continue to have devices and sub-domains that
>>> may or may not be IRQ safe.
>>
>>
>> According the my comments above, no I don't think so. Non-IRQ safe
>> domains can't have subdomains that is IRQ safe.
>>
> Here is a summary of the combinations as I understand. Correct me if I
> am wrong, please.

Nice summary, it good that we discuss all possible scenarios!

>
> *) Non-IRQ safe parent + IRQ-safe subdomain

Let's name this case 1.

>   Attach subdomain:
>         - parent mutex held and subdomain spinlocked.
>   Power-on:
>         - subdomain assumes parent is always ON or powered on before the
>         subdomain is powered ON.

As stated above, what do you think of *not* dealing with this case as
I think it's not a solution but a workaround!

>   Power-off:
>         - parent is not powered off even if the subdomain was the last
>         active domain.
>
> **) IRQ-safe parent + IRQ-safe subdomain

Let's name this case 2.

>    Attach subdomain:
>         - parent spinlock held and subdomain spinlocked.
>    Power-on:
>         - subdomain may power on the parent.
>    Power-off:
>         - last active sub-domain will power off the parent in the same
>           context.

>From a genpd locking point of view, there should be no reason to power
off in same context. We should be able to deal with this via a
scheduled work for this case as well, right!?

Although, I realize that it's very useful to power off in the same
context to minimize latencies in the full blown CPU Cluster Power
Management solution.
Perhaps a separate genpd configuration flag could be added to enable
this method, as I imagine that not *all* IRQ safe domains wants to use
it.

What do you think?

>
> ***) IRQ-safe parent + non-IRQ-safe subdomain

Let's name this case 3.

>    Attach subdomain:
>         - parent spinlock held and subdomain **cannot** be mutex locked.

First, attaching shouldn't occur from atomic context.

Second, the important part is that we pick the locks in same order as
elsewhere in genpd, and of course we must not pick a mutex while
holding a spinlock.

In all cases when adding subdomains, we should start by fetching the
subdomains lock *then* the lock for the parent. The current genpd code
doesn't do that and additionally it uses nested locks.
I am going to send a patch the changes this behaviour, as I think it's
wrong and may cause deadlocks!

Following this approach means that case 1 can't be supported, as that
would mean holding a spinlock while fetching a mutex.

>    Power-on:
>         - subdomain may power on the parent.
>    Power-off:
>         - last active subdomain will be able to power off the domain
>
> Except for the last case, we can support the others in addition to the
> currently available, with the restriction that
> - IRQ-safe parents can only have IRQ-safe subdomains and devices
>
> - Non-IRQ safe parents may have both IRQ-safe and non-IRQ-safe
>  subdomains and devices and the assumption that
>         -- IRQ-safe subdomains and devices will not bother to power
>         on/off their non-IRQ-safe parent.
>

I think case 2 and case 3 should be okay to support, but I am really
questioning case 1.

Thoughts?

Kind regards
Uffe

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-15  8:55         ` Ulf Hansson
@ 2016-01-15 16:57           ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-15 16:57 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

On Fri, Jan 15 2016 at 01:55 -0700, Ulf Hansson wrote:
[...]
>
>> *) Non-IRQ safe parent + IRQ-safe subdomain
>
>Let's name this case 1.
>
>>   Attach subdomain:
>>         - parent mutex held and subdomain spinlocked.
>>   Power-on:
>>         - subdomain assumes parent is always ON or powered on before the
>>         subdomain is powered ON.
>
>As stated above, what do you think of *not* dealing with this case as
>I think it's not a solution but a workaround!
>
>>   Power-off:
>>         - parent is not powered off even if the subdomain was the last
>>         active domain.
>>
>> **) IRQ-safe parent + IRQ-safe subdomain
>
>Let's name this case 2.
>
>>    Attach subdomain:
>>         - parent spinlock held and subdomain spinlocked.
>>    Power-on:
>>         - subdomain may power on the parent.
>>    Power-off:
>>         - last active sub-domain will power off the parent in the same
>>           context.
>
>From a genpd locking point of view, there should be no reason to power
>off in same context. We should be able to deal with this via a
>scheduled work for this case as well, right!?
>
I agree it need not be a requirement. May be we can have an option to
schedule the work. In the case of CPU power management, scheduling a
work is not an option, especially when the domain and the CPUs are
collapsing.

>Although, I realize that it's very useful to power off in the same
>context to minimize latencies in the full blown CPU Cluster Power
>Management solution.
>Perhaps a separate genpd configuration flag could be added to enable
>this method, as I imagine that not *all* IRQ safe domains wants to use
>it.
>
>What do you think?
>
May be we can provide the is_async option as a genpd flag.

>>
>> ***) IRQ-safe parent + non-IRQ-safe subdomain
>
>Let's name this case 3.
>
>>    Attach subdomain:
>>         - parent spinlock held and subdomain **cannot** be mutex locked.
>
>First, attaching shouldn't occur from atomic context.
>
>Second, the important part is that we pick the locks in same order as
>elsewhere in genpd, and of course we must not pick a mutex while
>holding a spinlock.
>
>In all cases when adding subdomains, we should start by fetching the
>subdomains lock *then* the lock for the parent. The current genpd code
>doesn't do that and additionally it uses nested locks.
>I am going to send a patch the changes this behaviour, as I think it's
>wrong and may cause deadlocks!
>
Ah. Makes sense. I wish I had thought of it.

>Following this approach means that case 1 can't be supported, as that
>would mean holding a spinlock while fetching a mutex.
>
>>    Power-on:
>>         - subdomain may power on the parent.
>>    Power-off:
>>         - last active subdomain will be able to power off the domain
>>
>> Except for the last case, we can support the others in addition to the
>> currently available, with the restriction that
>> - IRQ-safe parents can only have IRQ-safe subdomains and devices
>>
>> - Non-IRQ safe parents may have both IRQ-safe and non-IRQ-safe
>>  subdomains and devices and the assumption that
>>         -- IRQ-safe subdomains and devices will not bother to power
>>         on/off their non-IRQ-safe parent.
>>
>
>I think case 2 and case 3 should be okay to support, but I am really
>questioning case 1.
>
With you other patch, it does make sense to have 2 and 3 instead of 1
and 2. 

My only concern is as I view the SoC as a whole, there would be cases
where the parent domain could only be non-IRQ safe (turning off a big
regulator may require some sleep) and the subdomains are quicker and
faster IRQ-safe domains. Putting up this restriction, chops up the
domain hierarchy. Imagine, if you could represent the whole power domain
organization in DT, but because of this restriction, we may not be able
to do that.

Thanks,
Lina

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-15 16:57           ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-15 16:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 15 2016 at 01:55 -0700, Ulf Hansson wrote:
[...]
>
>> *) Non-IRQ safe parent + IRQ-safe subdomain
>
>Let's name this case 1.
>
>>   Attach subdomain:
>>         - parent mutex held and subdomain spinlocked.
>>   Power-on:
>>         - subdomain assumes parent is always ON or powered on before the
>>         subdomain is powered ON.
>
>As stated above, what do you think of *not* dealing with this case as
>I think it's not a solution but a workaround!
>
>>   Power-off:
>>         - parent is not powered off even if the subdomain was the last
>>         active domain.
>>
>> **) IRQ-safe parent + IRQ-safe subdomain
>
>Let's name this case 2.
>
>>    Attach subdomain:
>>         - parent spinlock held and subdomain spinlocked.
>>    Power-on:
>>         - subdomain may power on the parent.
>>    Power-off:
>>         - last active sub-domain will power off the parent in the same
>>           context.
>
>From a genpd locking point of view, there should be no reason to power
>off in same context. We should be able to deal with this via a
>scheduled work for this case as well, right!?
>
I agree it need not be a requirement. May be we can have an option to
schedule the work. In the case of CPU power management, scheduling a
work is not an option, especially when the domain and the CPUs are
collapsing.

>Although, I realize that it's very useful to power off in the same
>context to minimize latencies in the full blown CPU Cluster Power
>Management solution.
>Perhaps a separate genpd configuration flag could be added to enable
>this method, as I imagine that not *all* IRQ safe domains wants to use
>it.
>
>What do you think?
>
May be we can provide the is_async option as a genpd flag.

>>
>> ***) IRQ-safe parent + non-IRQ-safe subdomain
>
>Let's name this case 3.
>
>>    Attach subdomain:
>>         - parent spinlock held and subdomain **cannot** be mutex locked.
>
>First, attaching shouldn't occur from atomic context.
>
>Second, the important part is that we pick the locks in same order as
>elsewhere in genpd, and of course we must not pick a mutex while
>holding a spinlock.
>
>In all cases when adding subdomains, we should start by fetching the
>subdomains lock *then* the lock for the parent. The current genpd code
>doesn't do that and additionally it uses nested locks.
>I am going to send a patch the changes this behaviour, as I think it's
>wrong and may cause deadlocks!
>
Ah. Makes sense. I wish I had thought of it.

>Following this approach means that case 1 can't be supported, as that
>would mean holding a spinlock while fetching a mutex.
>
>>    Power-on:
>>         - subdomain may power on the parent.
>>    Power-off:
>>         - last active subdomain will be able to power off the domain
>>
>> Except for the last case, we can support the others in addition to the
>> currently available, with the restriction that
>> - IRQ-safe parents can only have IRQ-safe subdomains and devices
>>
>> - Non-IRQ safe parents may have both IRQ-safe and non-IRQ-safe
>>  subdomains and devices and the assumption that
>>         -- IRQ-safe subdomains and devices will not bother to power
>>         on/off their non-IRQ-safe parent.
>>
>
>I think case 2 and case 3 should be okay to support, but I am really
>questioning case 1.
>
With you other patch, it does make sense to have 2 and 3 instead of 1
and 2. 

My only concern is as I view the SoC as a whole, there would be cases
where the parent domain could only be non-IRQ safe (turning off a big
regulator may require some sleep) and the subdomains are quicker and
faster IRQ-safe domains. Putting up this restriction, chops up the
domain hierarchy. Imagine, if you could represent the whole power domain
organization in DT, but because of this restriction, we may not be able
to do that.

Thanks,
Lina

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-15 16:57           ` Lina Iyer
@ 2016-01-15 22:08             ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-15 22:08 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

[...]

>> I think case 2 and case 3 should be okay to support, but I am really
>> questioning case 1.
>>
> With you other patch, it does make sense to have 2 and 3 instead of 1
> and 2.

Okay!

> My only concern is as I view the SoC as a whole, there would be cases
> where the parent domain could only be non-IRQ safe (turning off a big
> regulator may require some sleep) and the subdomains are quicker and
> faster IRQ-safe domains. Putting up this restriction, chops up the

Just because they are "quick" (don't sleep) doesn't mean they have to
set the IRQ safe flag for the domain.

Let's compare how pm_runtime_irq_safe() is used for devices in
drivers. Lots of corresponding runtime PM callbacks don't sleep, but
that don't mean that the driver calls pm_runtime_irq_safe().

Drivers that are expecting to invoke pm_runtime_get_sync() (or other
synchronous runtime PM API) from atomic context, requires the
corresponding runtime PM callbacks to be IRQ safe. Only under these
circumstances the pm_runtime_irq_safe() is used.

> domain hierarchy. Imagine, if you could represent the whole power domain
> organization in DT, but because of this restriction, we may not be able
> to do that.

You do have a point. Considering my comment above, do you still think
this may become an issue?

Kind regards
Uffe

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-15 22:08             ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-15 22:08 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

>> I think case 2 and case 3 should be okay to support, but I am really
>> questioning case 1.
>>
> With you other patch, it does make sense to have 2 and 3 instead of 1
> and 2.

Okay!

> My only concern is as I view the SoC as a whole, there would be cases
> where the parent domain could only be non-IRQ safe (turning off a big
> regulator may require some sleep) and the subdomains are quicker and
> faster IRQ-safe domains. Putting up this restriction, chops up the

Just because they are "quick" (don't sleep) doesn't mean they have to
set the IRQ safe flag for the domain.

Let's compare how pm_runtime_irq_safe() is used for devices in
drivers. Lots of corresponding runtime PM callbacks don't sleep, but
that don't mean that the driver calls pm_runtime_irq_safe().

Drivers that are expecting to invoke pm_runtime_get_sync() (or other
synchronous runtime PM API) from atomic context, requires the
corresponding runtime PM callbacks to be IRQ safe. Only under these
circumstances the pm_runtime_irq_safe() is used.

> domain hierarchy. Imagine, if you could represent the whole power domain
> organization in DT, but because of this restriction, we may not be able
> to do that.

You do have a point. Considering my comment above, do you still think
this may become an issue?

Kind regards
Uffe

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-15 22:08             ` Ulf Hansson
@ 2016-01-18 16:58               ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-18 16:58 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

On Fri, Jan 15 2016 at 15:08 -0700, Ulf Hansson wrote:
>[...]
>
>>> I think case 2 and case 3 should be okay to support, but I am really
>>> questioning case 1.
>>>
>> With you other patch, it does make sense to have 2 and 3 instead of 1
>> and 2.
>
>Okay!
>
>> My only concern is as I view the SoC as a whole, there would be cases
>> where the parent domain could only be non-IRQ safe (turning off a big
>> regulator may require some sleep) and the subdomains are quicker and
>> faster IRQ-safe domains. Putting up this restriction, chops up the
>
>Just because they are "quick" (don't sleep) doesn't mean they have to
>set the IRQ safe flag for the domain.
>
>Let's compare how pm_runtime_irq_safe() is used for devices in
>drivers. Lots of corresponding runtime PM callbacks don't sleep, but
>that don't mean that the driver calls pm_runtime_irq_safe().
>
>Drivers that are expecting to invoke pm_runtime_get_sync() (or other
>synchronous runtime PM API) from atomic context, requires the
>corresponding runtime PM callbacks to be IRQ safe. Only under these
>circumstances the pm_runtime_irq_safe() is used.
>
I agree.

The limitation and the interpretation could completely be s/w. There is
nothing preventing that in hardware. So we could have a processor
subsystem domain that can collapse faster and even during cpuidle. We
would define that domain IRQ-safe because of its need to collapse and
resume when IRQs are disabled, but its parent may not have that
restriction, in fact, the parent could have another child that could
only operate as non-IRQ safe.

By imposing the limitation that parents of IRQ-safe domains cannot be 
non-IRQ-safe, we have to chop off that relationship, because of another
non-IRQ-safe sibling.

>> domain hierarchy. Imagine, if you could represent the whole power domain
>> organization in DT, but because of this restriction, we may not be able
>> to do that.
>
>You do have a point. Considering my comment above, do you still think
>this may become an issue?
>
Yes. Pls see my example below.

That said, I probably won't encounter this limitation in my current
series, but its not hard to foresee this corner case.

Thanks,
Lina

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-18 16:58               ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-18 16:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 15 2016 at 15:08 -0700, Ulf Hansson wrote:
>[...]
>
>>> I think case 2 and case 3 should be okay to support, but I am really
>>> questioning case 1.
>>>
>> With you other patch, it does make sense to have 2 and 3 instead of 1
>> and 2.
>
>Okay!
>
>> My only concern is as I view the SoC as a whole, there would be cases
>> where the parent domain could only be non-IRQ safe (turning off a big
>> regulator may require some sleep) and the subdomains are quicker and
>> faster IRQ-safe domains. Putting up this restriction, chops up the
>
>Just because they are "quick" (don't sleep) doesn't mean they have to
>set the IRQ safe flag for the domain.
>
>Let's compare how pm_runtime_irq_safe() is used for devices in
>drivers. Lots of corresponding runtime PM callbacks don't sleep, but
>that don't mean that the driver calls pm_runtime_irq_safe().
>
>Drivers that are expecting to invoke pm_runtime_get_sync() (or other
>synchronous runtime PM API) from atomic context, requires the
>corresponding runtime PM callbacks to be IRQ safe. Only under these
>circumstances the pm_runtime_irq_safe() is used.
>
I agree.

The limitation and the interpretation could completely be s/w. There is
nothing preventing that in hardware. So we could have a processor
subsystem domain that can collapse faster and even during cpuidle. We
would define that domain IRQ-safe because of its need to collapse and
resume when IRQs are disabled, but its parent may not have that
restriction, in fact, the parent could have another child that could
only operate as non-IRQ safe.

By imposing the limitation that parents of IRQ-safe domains cannot be 
non-IRQ-safe, we have to chop off that relationship, because of another
non-IRQ-safe sibling.

>> domain hierarchy. Imagine, if you could represent the whole power domain
>> organization in DT, but because of this restriction, we may not be able
>> to do that.
>
>You do have a point. Considering my comment above, do you still think
>this may become an issue?
>
Yes. Pls see my example below.

That said, I probably won't encounter this limitation in my current
series, but its not hard to foresee this corner case.

Thanks,
Lina

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-18 16:58               ` Lina Iyer
@ 2016-01-18 17:00                 ` Lina Iyer
  -1 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-18 17:00 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

On Mon, Jan 18 2016 at 09:58 -0700, Lina Iyer wrote:
>On Fri, Jan 15 2016 at 15:08 -0700, Ulf Hansson wrote:
>>[...]
>>
>>>>I think case 2 and case 3 should be okay to support, but I am really
>>>>questioning case 1.
>>>>
>>>With you other patch, it does make sense to have 2 and 3 instead of 1
>>>and 2.
>>
>>Okay!
>>
>>>My only concern is as I view the SoC as a whole, there would be cases
>>>where the parent domain could only be non-IRQ safe (turning off a big
>>>regulator may require some sleep) and the subdomains are quicker and
>>>faster IRQ-safe domains. Putting up this restriction, chops up the
>>
>>Just because they are "quick" (don't sleep) doesn't mean they have to
>>set the IRQ safe flag for the domain.
>>
>>Let's compare how pm_runtime_irq_safe() is used for devices in
>>drivers. Lots of corresponding runtime PM callbacks don't sleep, but
>>that don't mean that the driver calls pm_runtime_irq_safe().
>>
>>Drivers that are expecting to invoke pm_runtime_get_sync() (or other
>>synchronous runtime PM API) from atomic context, requires the
>>corresponding runtime PM callbacks to be IRQ safe. Only under these
>>circumstances the pm_runtime_irq_safe() is used.
>>
>I agree.
>
>The limitation and the interpretation could completely be s/w. There is
>nothing preventing that in hardware. So we could have a processor
>subsystem domain that can collapse faster and even during cpuidle. We
>would define that domain IRQ-safe because of its need to collapse and
>resume when IRQs are disabled, but its parent may not have that
>restriction, in fact, the parent could have another child that could
>only operate as non-IRQ safe.
>
>By imposing the limitation that parents of IRQ-safe domains cannot be 
>non-IRQ-safe, we have to chop off that relationship, because of 
>another
>non-IRQ-safe sibling.
>
>>>domain hierarchy. Imagine, if you could represent the whole power domain
>>>organization in DT, but because of this restriction, we may not be able
>>>to do that.
>>
>>You do have a point. Considering my comment above, do you still think
>>this may become an issue?
>>
>Yes. Pls see my example below.
>
Sorry above ;)

>That said, I probably won't encounter this limitation in my current
>series, but its not hard to foresee this corner case.
>
>Thanks,
>Lina

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-18 17:00                 ` Lina Iyer
  0 siblings, 0 replies; 166+ messages in thread
From: Lina Iyer @ 2016-01-18 17:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 18 2016 at 09:58 -0700, Lina Iyer wrote:
>On Fri, Jan 15 2016 at 15:08 -0700, Ulf Hansson wrote:
>>[...]
>>
>>>>I think case 2 and case 3 should be okay to support, but I am really
>>>>questioning case 1.
>>>>
>>>With you other patch, it does make sense to have 2 and 3 instead of 1
>>>and 2.
>>
>>Okay!
>>
>>>My only concern is as I view the SoC as a whole, there would be cases
>>>where the parent domain could only be non-IRQ safe (turning off a big
>>>regulator may require some sleep) and the subdomains are quicker and
>>>faster IRQ-safe domains. Putting up this restriction, chops up the
>>
>>Just because they are "quick" (don't sleep) doesn't mean they have to
>>set the IRQ safe flag for the domain.
>>
>>Let's compare how pm_runtime_irq_safe() is used for devices in
>>drivers. Lots of corresponding runtime PM callbacks don't sleep, but
>>that don't mean that the driver calls pm_runtime_irq_safe().
>>
>>Drivers that are expecting to invoke pm_runtime_get_sync() (or other
>>synchronous runtime PM API) from atomic context, requires the
>>corresponding runtime PM callbacks to be IRQ safe. Only under these
>>circumstances the pm_runtime_irq_safe() is used.
>>
>I agree.
>
>The limitation and the interpretation could completely be s/w. There is
>nothing preventing that in hardware. So we could have a processor
>subsystem domain that can collapse faster and even during cpuidle. We
>would define that domain IRQ-safe because of its need to collapse and
>resume when IRQs are disabled, but its parent may not have that
>restriction, in fact, the parent could have another child that could
>only operate as non-IRQ safe.
>
>By imposing the limitation that parents of IRQ-safe domains cannot be 
>non-IRQ-safe, we have to chop off that relationship, because of 
>another
>non-IRQ-safe sibling.
>
>>>domain hierarchy. Imagine, if you could represent the whole power domain
>>>organization in DT, but because of this restriction, we may not be able
>>>to do that.
>>
>>You do have a point. Considering my comment above, do you still think
>>this may become an issue?
>>
>Yes. Pls see my example below.
>
Sorry above ;)

>That said, I probably won't encounter this limitation in my current
>series, but its not hard to foresee this corner case.
>
>Thanks,
>Lina

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

* Re: [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
  2016-01-18 16:58               ` Lina Iyer
@ 2016-01-19 10:01                 ` Ulf Hansson
  -1 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-19 10:01 UTC (permalink / raw)
  To: Lina Iyer
  Cc: Kevin Hilman, linux-pm, linux-arm-kernel, Geert Uytterhoeven,
	Krzysztof Kozłowski, msivasub, Andy Gross, Stephen Boyd,
	linux-arm-msm, Lorenzo Pieralisi, Axel Haslam, Marc Titinger,
	Rafael J. Wysocki

On 18 January 2016 at 17:58, Lina Iyer <lina.iyer@linaro.org> wrote:
> On Fri, Jan 15 2016 at 15:08 -0700, Ulf Hansson wrote:
>>
>> [...]
>>
>>>> I think case 2 and case 3 should be okay to support, but I am really
>>>> questioning case 1.
>>>>
>>> With you other patch, it does make sense to have 2 and 3 instead of 1
>>> and 2.
>>
>>
>> Okay!
>>
>>> My only concern is as I view the SoC as a whole, there would be cases
>>> where the parent domain could only be non-IRQ safe (turning off a big
>>> regulator may require some sleep) and the subdomains are quicker and
>>> faster IRQ-safe domains. Putting up this restriction, chops up the
>>
>>
>> Just because they are "quick" (don't sleep) doesn't mean they have to
>> set the IRQ safe flag for the domain.
>>
>> Let's compare how pm_runtime_irq_safe() is used for devices in
>> drivers. Lots of corresponding runtime PM callbacks don't sleep, but
>> that don't mean that the driver calls pm_runtime_irq_safe().
>>
>> Drivers that are expecting to invoke pm_runtime_get_sync() (or other
>> synchronous runtime PM API) from atomic context, requires the
>> corresponding runtime PM callbacks to be IRQ safe. Only under these
>> circumstances the pm_runtime_irq_safe() is used.
>>
> I agree.
>
> The limitation and the interpretation could completely be s/w. There is
> nothing preventing that in hardware. So we could have a processor
> subsystem domain that can collapse faster and even during cpuidle. We
> would define that domain IRQ-safe because of its need to collapse and
> resume when IRQs are disabled, but its parent may not have that
> restriction, in fact, the parent could have another child that could
> only operate as non-IRQ safe.
>
> By imposing the limitation that parents of IRQ-safe domains cannot be
> non-IRQ-safe, we have to chop off that relationship, because of another
> non-IRQ-safe sibling.
>
>>> domain hierarchy. Imagine, if you could represent the whole power domain
>>> organization in DT, but because of this restriction, we may not be able
>>> to do that.
>>
>>
>> You do have a point. Considering my comment above, do you still think
>> this may become an issue?
>>
> Yes. Pls see my example below.
>
> That said, I probably won't encounter this limitation in my current
> series, but its not hard to foresee this corner case.

Okay, thanks for sharing your thoughts.

For now, I suggest we leave case 1) as a non-supported option.

When we have a valid use case for case 1), we anyway will have to
think of a better approach than what's suggested in $subject patch,
since keeping the parent domain always powered on isn't good enough.

Kind regards
Uffe

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

* [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains
@ 2016-01-19 10:01                 ` Ulf Hansson
  0 siblings, 0 replies; 166+ messages in thread
From: Ulf Hansson @ 2016-01-19 10:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 18 January 2016 at 17:58, Lina Iyer <lina.iyer@linaro.org> wrote:
> On Fri, Jan 15 2016 at 15:08 -0700, Ulf Hansson wrote:
>>
>> [...]
>>
>>>> I think case 2 and case 3 should be okay to support, but I am really
>>>> questioning case 1.
>>>>
>>> With you other patch, it does make sense to have 2 and 3 instead of 1
>>> and 2.
>>
>>
>> Okay!
>>
>>> My only concern is as I view the SoC as a whole, there would be cases
>>> where the parent domain could only be non-IRQ safe (turning off a big
>>> regulator may require some sleep) and the subdomains are quicker and
>>> faster IRQ-safe domains. Putting up this restriction, chops up the
>>
>>
>> Just because they are "quick" (don't sleep) doesn't mean they have to
>> set the IRQ safe flag for the domain.
>>
>> Let's compare how pm_runtime_irq_safe() is used for devices in
>> drivers. Lots of corresponding runtime PM callbacks don't sleep, but
>> that don't mean that the driver calls pm_runtime_irq_safe().
>>
>> Drivers that are expecting to invoke pm_runtime_get_sync() (or other
>> synchronous runtime PM API) from atomic context, requires the
>> corresponding runtime PM callbacks to be IRQ safe. Only under these
>> circumstances the pm_runtime_irq_safe() is used.
>>
> I agree.
>
> The limitation and the interpretation could completely be s/w. There is
> nothing preventing that in hardware. So we could have a processor
> subsystem domain that can collapse faster and even during cpuidle. We
> would define that domain IRQ-safe because of its need to collapse and
> resume when IRQs are disabled, but its parent may not have that
> restriction, in fact, the parent could have another child that could
> only operate as non-IRQ safe.
>
> By imposing the limitation that parents of IRQ-safe domains cannot be
> non-IRQ-safe, we have to chop off that relationship, because of another
> non-IRQ-safe sibling.
>
>>> domain hierarchy. Imagine, if you could represent the whole power domain
>>> organization in DT, but because of this restriction, we may not be able
>>> to do that.
>>
>>
>> You do have a point. Considering my comment above, do you still think
>> this may become an issue?
>>
> Yes. Pls see my example below.
>
> That said, I probably won't encounter this limitation in my current
> series, but its not hard to foresee this corner case.

Okay, thanks for sharing your thoughts.

For now, I suggest we leave case 1) as a non-supported option.

When we have a valid use case for case 1), we anyway will have to
think of a better approach than what's suggested in $subject patch,
since keeping the parent domain always powered on isn't good enough.

Kind regards
Uffe

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

end of thread, other threads:[~2016-01-19 10:01 UTC | newest]

Thread overview: 166+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-17 22:37 [PATCH RFC 00/27] PM/Domains: Cluster idle support for ARM SoCs Lina Iyer
2015-11-17 22:37 ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 01/27] PM / Domains: core changes for multiple states Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-12-09 13:58   ` Ulf Hansson
2015-12-09 13:58     ` Ulf Hansson
2015-12-17 17:58     ` Axel Haslam
2015-12-17 17:58       ` Axel Haslam
2015-12-17 21:19       ` Ulf Hansson
2015-12-17 21:19         ` Ulf Hansson
2015-11-17 22:37 ` [PATCH RFC 02/27] PM / Domains: Allow domain power states to be read from DT Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-12-10 16:53   ` Ulf Hansson
2015-12-10 16:53     ` Ulf Hansson
2015-12-15 10:07     ` Marc Titinger
2015-12-15 10:07       ` Marc Titinger
2015-12-15 22:14       ` Lina Iyer
2015-12-15 22:14         ` Lina Iyer
2015-12-16 21:36       ` Lina Iyer
2015-12-16 21:36         ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 03/27] PM / Domain: Add additional state specific param Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-19 21:33   ` Kevin Hilman
2015-11-19 21:33     ` Kevin Hilman
2015-11-17 22:37 ` [PATCH RFC 04/27] PM / Domains: make governor select deepest state Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-12-11  9:13   ` Ulf Hansson
2015-12-11  9:13     ` Ulf Hansson
2015-11-17 22:37 ` [PATCH RFC 05/27] PM / Domains: remove old power on/off latencies Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-18 14:57   ` [PATCH] ARM: imx6: pm: declare pm domain latency on power_state struct Lina Iyer
2015-11-18 14:57     ` Lina Iyer
2015-11-23 13:31     ` Lucas Stach
2015-11-23 13:31       ` Lucas Stach
2015-11-23 13:42       ` Lucas Stach
2015-11-23 13:42         ` Lucas Stach
2015-12-04 23:19         ` Lina Iyer
2015-12-04 23:19           ` Lina Iyer
2015-12-11  9:16   ` [PATCH RFC 05/27] PM / Domains: remove old power on/off latencies Ulf Hansson
2015-12-11  9:16     ` Ulf Hansson
2015-11-17 22:37 ` [PATCH RFC 06/27] PM / Domains: add debugfs 'states' and 'timings' seq files Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-12-11 11:46   ` Ulf Hansson
2015-12-11 11:46     ` Ulf Hansson
2015-12-16 11:07     ` Marc Titinger
2015-12-16 11:07       ` Marc Titinger
2015-12-16 12:48       ` Ulf Hansson
2015-12-16 12:48         ` Ulf Hansson
2015-12-16 14:12         ` Marc Titinger
2015-12-16 14:12           ` Marc Titinger
2015-11-17 22:37 ` [PATCH RFC 07/27] PM / Domains: Read domain residency from DT Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-24 20:41   ` Stephen Boyd
2015-11-24 20:41     ` Stephen Boyd
2015-12-11 11:54   ` Ulf Hansson
2015-12-11 11:54     ` Ulf Hansson
2015-11-17 22:37 ` [PATCH RFC 08/27] PM / Domains: Support IRQ safe PM domains Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2016-01-14 14:42   ` Ulf Hansson
2016-01-14 14:42     ` Ulf Hansson
2016-01-14 18:33     ` Lina Iyer
2016-01-14 18:33       ` Lina Iyer
2016-01-15  8:55       ` Ulf Hansson
2016-01-15  8:55         ` Ulf Hansson
2016-01-15 16:57         ` Lina Iyer
2016-01-15 16:57           ` Lina Iyer
2016-01-15 22:08           ` Ulf Hansson
2016-01-15 22:08             ` Ulf Hansson
2016-01-18 16:58             ` Lina Iyer
2016-01-18 16:58               ` Lina Iyer
2016-01-18 17:00               ` Lina Iyer
2016-01-18 17:00                 ` Lina Iyer
2016-01-19 10:01               ` Ulf Hansson
2016-01-19 10:01                 ` Ulf Hansson
2015-11-17 22:37 ` [PATCH RFC 09/27] PM / Domains: Attempt runtime suspend of IRQ safe parent domain Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 10/27] drivers: power: Introduce PM domains for CPUs/clusters Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-24 20:52   ` Stephen Boyd
2015-11-24 20:52     ` Stephen Boyd
2015-11-17 22:37 ` [PATCH RFC 11/27] drivers: cpu: Define CPU devices as IRQ safe Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 12/27] ARM: cpuidle: remove cpu parameter from the cpuidle_ops suspend hook Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 13/27] ARM: cpuidle: Add runtime PM support for CPU idle Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-18  8:50   ` Zhaoyang Huang
2015-11-18  8:50     ` Zhaoyang Huang
2015-11-18 14:17     ` Lina Iyer
2015-11-18 14:17       ` Lina Iyer
2015-11-19 22:10   ` Kevin Hilman
2015-11-19 22:10     ` Kevin Hilman
2015-11-17 22:37 ` [PATCH RFC 14/27] tick: get next wakeup event for the CPU Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 15/27] PM / Domains: Add next_wakeup to device's timing data Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-19 22:19   ` Kevin Hilman
2015-11-19 22:19     ` Kevin Hilman
2015-11-20 15:58     ` Lina Iyer
2015-11-20 15:58       ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 16/27] ARM: cpuidle: Record the next wakeup event of the CPU Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-19 23:35   ` Kevin Hilman
2015-11-19 23:35     ` Kevin Hilman
2015-11-20 16:28     ` Lina Iyer
2015-11-20 16:28       ` Lina Iyer
2015-11-24 18:29       ` Kevin Hilman
2015-11-24 18:29         ` Kevin Hilman
2015-11-17 22:37 ` [PATCH RFC 17/27] drivers: cpu-pd: Record CPUs that are part of the domain Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-24 21:00   ` Stephen Boyd
2015-11-24 21:00     ` Stephen Boyd
2015-11-25 14:13     ` Lina Iyer
2015-11-25 14:13       ` Lina Iyer
2015-11-25 19:12       ` Stephen Boyd
2015-11-25 19:12         ` Stephen Boyd
2015-11-25 20:20         ` Lina Iyer
2015-11-25 20:20           ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 18/27] drivers: cpu-pd: Add PM Domain governor for CPUs Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-18 18:42   ` Lorenzo Pieralisi
2015-11-18 18:42     ` Lorenzo Pieralisi
2015-11-19  8:50     ` Marc Titinger
2015-11-19  8:50       ` Marc Titinger
2015-11-20 17:39       ` Lina Iyer
2015-11-20 17:39         ` Lina Iyer
2015-11-19 23:52     ` Kevin Hilman
2015-11-19 23:52       ` Kevin Hilman
2015-11-20 16:21       ` Lorenzo Pieralisi
2015-11-20 16:21         ` Lorenzo Pieralisi
2015-11-20 16:42         ` Lina Iyer
2015-11-20 16:42           ` Lina Iyer
2015-11-20  0:03   ` Kevin Hilman
2015-11-20  0:03     ` Kevin Hilman
2015-11-17 22:37 ` [PATCH RFC 19/27] drivers: cpu-pd: Invoke CPU PM runtime on hotplug Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 20/27] Documentation: ARM: topology: 'cluster' property for cluster nodes Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 21/27] drivers: cpu-pd: Parse topology to setup CPU PM domains Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-12-07 14:54   ` Lorenzo Pieralisi
2015-12-07 14:54     ` Lorenzo Pieralisi
2015-12-08 18:05     ` Lina Iyer
2015-12-08 18:05       ` Lina Iyer
2015-12-10 18:11       ` Lorenzo Pieralisi
2015-12-10 18:11         ` Lorenzo Pieralisi
2015-12-11  9:04         ` Geert Uytterhoeven
2015-12-11  9:04           ` Geert Uytterhoeven
2015-12-11 20:51           ` Lina Iyer
2015-12-11 20:51             ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 22/27] drivers: firmware: PSCI: Export psci_has_ext_power_state() Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 23/27] ARM64: psci: Support cluster idle states for OS-Initated Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 24/27] arm64: dts: Add Qualcomm MSM8916, MTP8916, APQ8016, SBC8016 ids Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 25/27] devicetree: bindings: Document qcom,msm-id and qcom,board-id Lina Iyer
2015-11-17 22:37   ` [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom, board-id Lina Iyer
2015-11-19 14:36   ` [PATCH RFC 25/27] devicetree: bindings: Document qcom,msm-id and qcom,board-id Rob Herring
2015-11-19 14:36     ` [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id and qcom, board-id Rob Herring
2015-11-19 15:36     ` [PATCH RFC 25/27] devicetree: bindings: Document qcom,msm-id and qcom,board-id Lina Iyer
2015-11-19 15:36       ` [PATCH RFC 25/27] devicetree: bindings: Document qcom, msm-id " Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 26/27] ARM64: dts: Add PSCI cpuidle support for MSM8916 Lina Iyer
2015-11-17 22:37   ` Lina Iyer
2015-11-17 22:37 ` [PATCH RFC 27/27] ARM64: dts: Define CPU power domain " Lina Iyer
2015-11-17 22:37   ` Lina Iyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.