Hi,
This series contain V3 of both the bindings and the code that implement them. They were sent separately earlier.
Some platforms have the capability to configure the performance state of their power domains. The process of configuring the performance state is pretty much platform dependent and we may need to work with a wide range of configurables. For some platforms, like Qcom, it can be a positive integer value alone, while in other cases it can be voltage levels, etc.
The power-domain framework until now was only designed for the idle state management of the device and this needs to change in order to reuse the power-domain framework for active state management of the devices.
The first 2 patches update the DT bindings of the power-domains and OPP tables. And the other 5 patches implement the details in QoS, genpd and OPP frameworks.
This is tested currently by hacking the kernel a bit with virtual power-domains for the dual A15 exynos platform. The earlier version of patches was also tested by Rajendra Nayak (Qcom) on *real* Qualcomm hardware for which this work is getting done. And so this version should work as well.
Here is sample DT and C code we need to write for platforms:
DT: ---
foo: foo-power-domain@08000000 { compatible = "foo,genpd"; #power-domain-cells = <0>;
performance-states { compatible = "domain-performance-state"; pstate@1 { reg = <1>; domain-microvolt = <970000 975000 985000>; }; pstate@2 { reg = <2>; domain-microvolt = <1000000 1075000 1085000>; }; }; };
cpu0_opp_table: opp_table0 { compatible = "operating-points-v2"; opp-shared;
opp00 { opp-hz = /bits/ 64 <1700000000>; clock-latency-ns = <30>; domain-performance-state = <2>; opp-suspend; }; opp01 { opp-hz = /bits/ 64 <1600000000>; clock-latency-ns = <300>; domain-performance-state = <1>; }; }
Driver code: ------------
static int pd_performance(struct generic_pm_domain *domain, unsigned int state) { int i = state - 1;
pr_info("%d: %d: %u: %u: %u\n", state, states[i].performance_state, states[i].u_volt, states[i].u_volt_min, states[i].u_volt_max); return 0; }
static const struct of_device_id pm_domain_of_match[] __initconst = { { .compatible = "foo,genpd", }, { }, };
static int __init genpd_test_init(void) { struct device *dev = get_cpu_device(0); struct device_node *np; const struct of_device_id *match; int n; int ret;
for_each_matching_node_and_match(np, pm_domain_of_match, &match) { pd.name = kstrdup_const(strrchr(np->full_name, '/') + 1, GFP_KERNEL); if (!pd.name) { of_node_put(np); return -ENOMEM; }
pd.set_performance_state = pd_performance;
pm_genpd_init(&pd, NULL, false); of_genpd_parse_performance_states(np, &states, &n); of_genpd_add_provider_simple(np, &pd); }
ret = dev_pm_domain_attach(dev, false);
return ret; }
V2->V3: - Based over latest pm/linux-next - Bindings and code are merged together - Lots of updates in bindings - the performance-states node is present within the power-domain now, instead of its phandle. - performance-level property is replaced by "reg". - domain-performance-state property of the consumers contain an integer value now instead of phandle. - Lots of updates to the code as well - Patch "PM / QOS: Add default case to the switch" is merged with other patches and the code is changed a bit as well. - Don't pass 'type' to dev_pm_qos_add_notifier(), rather handle all notifiers with a single list. A new patch is added for that. - The OPP framework patch can be applied now and has proper SoB from me. - Dropped "PM / domain: Save/restore performance state at runtime suspend/resume". - Drop all WARN(). - Tested-by Rajendra nayak.
V1->V2: - Based over latest pm/linux-next - It is mostly a resend of what is sent earlier as this series hasn't got any reviews so far and Rafael suggested that its better I resend it. - Only the 4/6 patch got an update, which was shared earlier as reply to V1 as well. It has got several fixes for taking care of power domain hierarchy, etc.
-- viresh
Viresh Kumar (7): PM / Domains: Introduce "performance-states" binding PM / OPP: Introduce "domain-performance-state" binding to OPP nodes PM / QOS: Keep common notifier list for genpd constraints PM / QOS: Add DEV_PM_QOS_PERFORMANCE request PM / domain: Register for PM QOS performance notifier PM / Domains: Allow domain performance states to be read from DT PM / OPP: Add support to parse domain-performance-state
Documentation/devicetree/bindings/opp/opp.txt | 64 +++++++ .../devicetree/bindings/power/power_domain.txt | 67 +++++++ Documentation/power/pm_qos_interface.txt | 2 +- drivers/base/power/domain.c | 204 ++++++++++++++++++++- drivers/base/power/opp/core.c | 73 ++++++++ drivers/base/power/opp/debugfs.c | 4 + drivers/base/power/opp/of.c | 37 ++++ drivers/base/power/opp/opp.h | 12 ++ drivers/base/power/qos.c | 36 ++-- include/linux/pm_domain.h | 19 ++ include/linux/pm_qos.h | 17 ++ kernel/power/qos.c | 2 +- 12 files changed, 517 insertions(+), 20 deletions(-)
Some platforms have the capability to configure the performance state of their power domains. The process of configuring the performance state is pretty much platform dependent and we may need to work with a wide range of configurables. For some platforms, like Qcom, it can be a positive integer value alone, while in other cases it can be voltage levels, etc.
The power-domain framework until now was only designed for the idle state management of the device and this needs to change in order to reuse the power-domain framework for active state management of the devices.
This patch adds DT bindings to describe the performance states of a power domain. The power domain node needs to contain a "performance-states" node, which itself is an array of per-state nodes. Each per-state node represents individual performance state of a device. Individual nodes are identified by their (mandatory) "reg" field. These nodes can also contain an optional "domain-microvolt" property. More properties can be added later on once we have more platforms using it.
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their node directly using the "domain-performance-state" property. Otherwise the consumers can define their requirements with help of other infrastructure, for example the OPP table (added in a later commit).
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- .../devicetree/bindings/power/power_domain.txt | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+)
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 723e1ad937da..9be09e576f68 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -38,6 +38,33 @@ phandle arguments (so called PM domain specifiers) of length specified by the domain's idle states. In the absence of this property, the domain would be considered as capable of being powered-on or powered-off.
+- performance-states : This describes the performance states of a PM domain. + The performance-states node reflects the performance states of this PM domain + and not the performance states of the devices or sub-domains in the PM domain. + Sub domains can have their own performance states. Sub domains without their + own performance states are governed by the performance states of the parent + domain and the "domain-performance-state" properties of their consumers refer + to the "reg" properties of the nodes in the parent domain. + + Required properties of the performance-states node: + - compatible: Allow performance states to express their compatibility. It + should be: "domain-performance-state". + + - nodes: The performance-states node should contain one or + more nodes, each representing a supported performance state. + + Required properties of the performance state nodes: + - reg: A positive integer value representing the performance level + associated with a performance state. The integer value '0' represents the + lowest performance level and the highest value represents the highest + performance level. The exact meaning and performance implications of + individual values is left to be defined by the user platform. + + Optional properties of performance state nodes: + - domain-microvolt: voltage in micro Volts. A single regulator's voltage is + specified with an array of size one or three. Single entry is for target + voltage and three entries are for <target min max> voltages. + Example:
power: power-controller@12340000 { @@ -118,4 +145,44 @@ The node above defines a typical PM domain consumer device, which is located inside a PM domain with index 0 of a power controller represented by a node with the label "power".
+Optional properties: +- domain-performance-state: A positive integer value representing the minimum + performance level (of the parent domain) required by the consumer for its + working. The integer value '0' represents the lowest performance level and the + highest value represents the highest performance level. The value of + domain-performance-state field should match one of the "reg" fields in the + "performance-states" table of the parent power domain. + + +Example: + + parent: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <0>; + + performance-states { + compatible = "domain-performance-state"; + pstate@1 { + reg = <1>; + domain-microvolt = <970000 975000 985000>; + }; + pstate@2 { + reg = <2>; + domain-microvolt = <1000000 1075000 1085000>; + }; + pstate@3 { + reg = <3>; + domain-microvolt = <1100000 1175000 1185000>; + }; + }; + }; + + leaky-device@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 0>; + domain-performance-state = <2>; + }; + [1]. Documentation/devicetree/bindings/power/domain-idle-state.txt
On Fri, Feb 24, 2017 at 02:36:33PM +0530, Viresh Kumar wrote:
Some platforms have the capability to configure the performance state of their power domains. The process of configuring the performance state is pretty much platform dependent and we may need to work with a wide range of configurables. For some platforms, like Qcom, it can be a positive integer value alone, while in other cases it can be voltage levels, etc.
The power-domain framework until now was only designed for the idle state management of the device and this needs to change in order to reuse the power-domain framework for active state management of the devices.
This patch adds DT bindings to describe the performance states of a power domain. The power domain node needs to contain a "performance-states" node, which itself is an array of per-state nodes. Each per-state node represents individual performance state of a device. Individual nodes are identified by their (mandatory) "reg" field. These nodes can also contain an optional "domain-microvolt" property. More properties can be added later on once we have more platforms using it.
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their node directly using the "domain-performance-state" property. Otherwise the consumers can define their requirements with help of other infrastructure, for example the OPP table (added in a later commit).
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org
.../devicetree/bindings/power/power_domain.txt | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+)
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 723e1ad937da..9be09e576f68 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -38,6 +38,33 @@ phandle arguments (so called PM domain specifiers) of length specified by the domain's idle states. In the absence of this property, the domain would be considered as capable of being powered-on or powered-off. +- performance-states : This describes the performance states of a PM domain.
- The performance-states node reflects the performance states of this PM domain
- and not the performance states of the devices or sub-domains in the PM domain.
- Sub domains can have their own performance states. Sub domains without their
- own performance states are governed by the performance states of the parent
- domain and the "domain-performance-state" properties of their consumers refer
- to the "reg" properties of the nodes in the parent domain.
- Required properties of the performance-states node:
- compatible: Allow performance states to express their compatibility. It
- should be: "domain-performance-state".
- nodes: The performance-states node should contain one or
- more nodes, each representing a supported performance state.
- Required properties of the performance state nodes:
- reg: A positive integer value representing the performance level
associated with a performance state. The integer value '0' represents the
lowest performance level and the highest value represents the highest
performance level. The exact meaning and performance implications of
individual values is left to be defined by the user platform.
- Optional properties of performance state nodes:
- domain-microvolt: voltage in micro Volts. A single regulator's voltage is
specified with an array of size one or three. Single entry is for target
voltage and three entries are for <target min max> voltages.
Example: power: power-controller@12340000 { @@ -118,4 +145,44 @@ The node above defines a typical PM domain consumer device, which is located inside a PM domain with index 0 of a power controller represented by a node with the label "power". +Optional properties: +- domain-performance-state: A positive integer value representing the minimum
- performance level (of the parent domain) required by the consumer for its
- working. The integer value '0' represents the lowest performance level and the
- highest value represents the highest performance level. The value of
- domain-performance-state field should match one of the "reg" fields in the
- "performance-states" table of the parent power domain.
+Example:
- parent: power-controller@12340000 {
compatible = "foo,power-controller";
reg = <0x12340000 0x1000>;
#power-domain-cells = <0>;
performance-states {
compatible = "domain-performance-state";
pstate@1 {
reg = <1>;
domain-microvolt = <970000 975000 985000>;
This doesn't look like "<target> <min> <max>".
With that fixed,
Acked-by: Rob Herring robh@kernel.org
};
pstate@2 {
reg = <2>;
domain-microvolt = <1000000 1075000 1085000>;
};
pstate@3 {
reg = <3>;
domain-microvolt = <1100000 1175000 1185000>;
};
};
- };
- leaky-device@12350000 {
compatible = "foo,i-leak-current";
reg = <0x12350000 0x1000>;
power-domains = <&power 0>;
domain-performance-state = <2>;
- };
[1]. Documentation/devicetree/bindings/power/domain-idle-state.txt
2.7.1.410.g6faf27b
On 27-02-17, 18:31, Rob Herring wrote:
On Fri, Feb 24, 2017 at 02:36:33PM +0530, Viresh Kumar wrote:
Some platforms have the capability to configure the performance state of their power domains. The process of configuring the performance state is pretty much platform dependent and we may need to work with a wide range of configurables. For some platforms, like Qcom, it can be a positive integer value alone, while in other cases it can be voltage levels, etc.
The power-domain framework until now was only designed for the idle state management of the device and this needs to change in order to reuse the power-domain framework for active state management of the devices.
This patch adds DT bindings to describe the performance states of a power domain. The power domain node needs to contain a "performance-states" node, which itself is an array of per-state nodes. Each per-state node represents individual performance state of a device. Individual nodes are identified by their (mandatory) "reg" field. These nodes can also contain an optional "domain-microvolt" property. More properties can be added later on once we have more platforms using it.
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their node directly using the "domain-performance-state" property. Otherwise the consumers can define their requirements with help of other infrastructure, for example the OPP table (added in a later commit).
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org
.../devicetree/bindings/power/power_domain.txt | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+)
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 723e1ad937da..9be09e576f68 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -38,6 +38,33 @@ phandle arguments (so called PM domain specifiers) of length specified by the domain's idle states. In the absence of this property, the domain would be considered as capable of being powered-on or powered-off. +- performance-states : This describes the performance states of a PM domain.
- The performance-states node reflects the performance states of this PM domain
- and not the performance states of the devices or sub-domains in the PM domain.
- Sub domains can have their own performance states. Sub domains without their
- own performance states are governed by the performance states of the parent
- domain and the "domain-performance-state" properties of their consumers refer
- to the "reg" properties of the nodes in the parent domain.
- Required properties of the performance-states node:
- compatible: Allow performance states to express their compatibility. It
- should be: "domain-performance-state".
- nodes: The performance-states node should contain one or
- more nodes, each representing a supported performance state.
- Required properties of the performance state nodes:
- reg: A positive integer value representing the performance level
associated with a performance state. The integer value '0' represents the
lowest performance level and the highest value represents the highest
performance level. The exact meaning and performance implications of
individual values is left to be defined by the user platform.
- Optional properties of performance state nodes:
- domain-microvolt: voltage in micro Volts. A single regulator's voltage is
specified with an array of size one or three. Single entry is for target
voltage and three entries are for <target min max> voltages.
Example: power: power-controller@12340000 { @@ -118,4 +145,44 @@ The node above defines a typical PM domain consumer device, which is located inside a PM domain with index 0 of a power controller represented by a node with the label "power". +Optional properties: +- domain-performance-state: A positive integer value representing the minimum
- performance level (of the parent domain) required by the consumer for its
- working. The integer value '0' represents the lowest performance level and the
- highest value represents the highest performance level. The value of
- domain-performance-state field should match one of the "reg" fields in the
- "performance-states" table of the parent power domain.
+Example:
- parent: power-controller@12340000 {
compatible = "foo,power-controller";
reg = <0x12340000 0x1000>;
#power-domain-cells = <0>;
performance-states {
compatible = "domain-performance-state";
pstate@1 {
reg = <1>;
domain-microvolt = <970000 975000 985000>;
This doesn't look like "<target> <min> <max>".
Wow, even the examples in the OPP document have these screwed up :(
With that fixed,
Acked-by: Rob Herring robh@kernel.org
Thanks.
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their nodes directly.
But if the device needs the capability of switching to different domain performance states, as they may need to support different clock rates, then the per OPP node can be used to contain that information.
This patch introduces the domain-performance-state (already defined by Power Domain bindings) to the per OPP node.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- Documentation/devicetree/bindings/opp/opp.txt | 64 +++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 9f5ca4457b5f..7f6bb52521b6 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -154,6 +154,15 @@ properties.
- status: Marks the node enabled/disabled.
+- domain-performance-state: A positive integer value representing the minimum + performance level (of the parent domain) required by the consumer as defined + by ../power/power_domain.txt binding document. The OPP nodes can contain the + "domain-performance-state" property, only if the device node contains a + "power-domains" property. The OPP nodes aren't allowed to contain the + "domain-performance-state" property partially, i.e. Either all OPP nodes in + the OPP table have the "domain-performance-state" property or none of them + have it. + Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together.
/ { @@ -528,3 +537,58 @@ Example 5: opp-supported-hw }; }; }; + +Example 7: domain-Performance-state: +(example: For 1GHz require domain state 1 and for 1.1 & 1.2 GHz require state 2) + +/ { + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp@1000000000 { + opp-hz = /bits/ 64 <1000000000>; + domain-performance-state = <1>; + }; + opp@1100000000 { + opp-hz = /bits/ 64 <1100000000>; + domain-performance-state = <2>; + }; + opp@1200000000 { + opp-hz = /bits/ 64 <1200000000>; + domain-performance-state = <2>; + }; + }; + + foo_domain: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <0>; + + performance-states { + compatible = "domain-performance-state"; + pstate@1 { + reg = <1>; + domain-microvolt = <970000 975000 985000>; + }; + pstate@2 { + reg = <2>; + domain-microvolt = <1000000 1075000 1085000>; + }; + }; + } + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + operating-points-v2 = <&cpu0_opp_table>; + power-domains = <&foo_domain>; + }; + }; +};
On Fri, Feb 24, 2017 at 02:36:34PM +0530, Viresh Kumar wrote:
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their nodes directly.
But if the device needs the capability of switching to different domain performance states, as they may need to support different clock rates, then the per OPP node can be used to contain that information.
This patch introduces the domain-performance-state (already defined by Power Domain bindings) to the per OPP node.
We already have OPP voltages, why are those not sufficient?
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org
Documentation/devicetree/bindings/opp/opp.txt | 64 +++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 9f5ca4457b5f..7f6bb52521b6 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -154,6 +154,15 @@ properties.
- status: Marks the node enabled/disabled.
+- domain-performance-state: A positive integer value representing the minimum
- performance level (of the parent domain) required by the consumer as defined
- by ../power/power_domain.txt binding document. The OPP nodes can contain the
- "domain-performance-state" property, only if the device node contains a
- "power-domains" property. The OPP nodes aren't allowed to contain the
- "domain-performance-state" property partially, i.e. Either all OPP nodes in
- the OPP table have the "domain-performance-state" property or none of them
- have it.
Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. / { @@ -528,3 +537,58 @@ Example 5: opp-supported-hw }; }; };
+Example 7: domain-Performance-state: +(example: For 1GHz require domain state 1 and for 1.1 & 1.2 GHz require state 2)
+/ {
- cpu0_opp_table: opp_table0 {
compatible = "operating-points-v2";
opp-shared;
opp@1000000000 {
opp-hz = /bits/ 64 <1000000000>;
domain-performance-state = <1>;
Thinking about this some more, there's a problem here that you have no link to foo_domain. I guess that resides in the cpu's node?
Perhaps instead of a number, this should be a phandle to pstate@1. Then you just get the parent if you need to know the domain.
};
opp@1100000000 {
opp-hz = /bits/ 64 <1100000000>;
domain-performance-state = <2>;
};
opp@1200000000 {
opp-hz = /bits/ 64 <1200000000>;
domain-performance-state = <2>;
};
- };
- foo_domain: power-controller@12340000 {
compatible = "foo,power-controller";
reg = <0x12340000 0x1000>;
#power-domain-cells = <0>;
performance-states {
compatible = "domain-performance-state";
pstate@1 {
reg = <1>;
domain-microvolt = <970000 975000 985000>;
};
pstate@2 {
reg = <2>;
domain-microvolt = <1000000 1075000 1085000>;
};
};
- }
- cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
clocks = <&clk_controller 0>;
clock-names = "cpu";
operating-points-v2 = <&cpu0_opp_table>;
power-domains = <&foo_domain>;
};
- };
+};
2.7.1.410.g6faf27b
On 27-02-17, 18:39, Rob Herring wrote:
On Fri, Feb 24, 2017 at 02:36:34PM +0530, Viresh Kumar wrote:
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their nodes directly.
But if the device needs the capability of switching to different domain performance states, as they may need to support different clock rates, then the per OPP node can be used to contain that information.
This patch introduces the domain-performance-state (already defined by Power Domain bindings) to the per OPP node.
We already have OPP voltages, why are those not sufficient?
Those are for the regulator that ONLY controls the device, and domain-performance-state belongs to the parent domain which controls many devices.
+Example 7: domain-Performance-state: +(example: For 1GHz require domain state 1 and for 1.1 & 1.2 GHz require state 2)
+/ {
- cpu0_opp_table: opp_table0 {
compatible = "operating-points-v2";
opp-shared;
opp@1000000000 {
opp-hz = /bits/ 64 <1000000000>;
Thinking about this some more, there's a problem here that you have no link to foo_domain. I guess that resides in the cpu's node?
Right, the "cpus" node below demonstrates that.
- cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
clocks = <&clk_controller 0>;
clock-names = "cpu";
operating-points-v2 = <&cpu0_opp_table>;
power-domains = <&foo_domain>;
};
- };
+};
domain-performance-state = <1>;
Perhaps instead of a number, this should be a phandle to pstate@1. Then you just get the parent if you need to know the domain.
That's what I did in V2, but then I turned it down considering the parent/child relationships we may have.
There are multiple cases we can have:
A.) DeviceX ---> Parent-domain-1 (Contains Perfomance states)
B.) DeviceX ---> Parent-domain-1 ---> Parent domain-2 (Contains Perfomance states)
---> Parent domain-2 (Contains Perfomance states) | | C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
The case A.) represents a simple case where the parent domain of the device contains the performance states. The phandle can work pretty well in this case. But the other cases B.) and C.) are a bit complicated as the direct parent domain doesn't allow changing the performance states, but its parents. And so I went ahead with numbers instead of phandles. Yes, we will still be able to get to the performance state node with the help of phandles, but will that be the right thing to do ?
On Tue, Feb 28, 2017 at 12:57 AM, Viresh Kumar viresh.kumar@linaro.org wrote:
On 27-02-17, 18:39, Rob Herring wrote:
On Fri, Feb 24, 2017 at 02:36:34PM +0530, Viresh Kumar wrote:
If the consumers don't need the capability of switching to different domain performance states at runtime, then they can simply define their required domain performance state in their nodes directly.
But if the device needs the capability of switching to different domain performance states, as they may need to support different clock rates, then the per OPP node can be used to contain that information.
This patch introduces the domain-performance-state (already defined by Power Domain bindings) to the per OPP node.
We already have OPP voltages, why are those not sufficient?
Those are for the regulator that ONLY controls the device, and domain-performance-state belongs to the parent domain which controls many devices.
+Example 7: domain-Performance-state: +(example: For 1GHz require domain state 1 and for 1.1 & 1.2 GHz require state 2)
+/ {
- cpu0_opp_table: opp_table0 {
compatible = "operating-points-v2";
opp-shared;
opp@1000000000 {
opp-hz = /bits/ 64 <1000000000>;
Thinking about this some more, there's a problem here that you have no link to foo_domain. I guess that resides in the cpu's node?
Right, the "cpus" node below demonstrates that.
- cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
clocks = <&clk_controller 0>;
clock-names = "cpu";
operating-points-v2 = <&cpu0_opp_table>;
power-domains = <&foo_domain>;
};
- };
+};
domain-performance-state = <1>;
Perhaps instead of a number, this should be a phandle to pstate@1. Then you just get the parent if you need to know the domain.
That's what I did in V2, but then I turned it down considering the parent/child relationships we may have.
There are multiple cases we can have:
A.) DeviceX ---> Parent-domain-1 (Contains Perfomance states)
B.) DeviceX ---> Parent-domain-1 ---> Parent domain-2 (Contains Perfomance states)
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
You have the same problem either way. If I have performance state 2 for the device, that corresponds to domain 2 or 3?
The case A.) represents a simple case where the parent domain of the device contains the performance states. The phandle can work pretty well in this case. But the other cases B.) and C.) are a bit complicated as the direct parent domain doesn't allow changing the performance states, but its parents. And so I went ahead with numbers instead of phandles. Yes, we will still be able to get to the performance state node with the help of phandles, but will that be the right thing to do ?
-- viresh
[...]
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
[...]
Kind regards Uffe
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
[...]
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic. And nesting of power domains is certainly common, but a power domain being contained in 2 different parents? I don't even see how that is possible in the physical design. Now if we're mixing PM and power domains again and the cpu device is pointing to the cpu PM domain which contains 2 power domains, then certainly that is possible.
Rob
Hi Rob,
On Tue, Feb 28, 2017 at 4:52 PM, Rob Herring robh@kernel.org wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
[...]
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic. And nesting of power domains is certainly common, but a power domain being contained in 2 different parents? I don't even see how that is possible in the physical design. Now if we're mixing PM and power domains again and the cpu device is pointing to the cpu PM domain which contains 2 power domains, then certainly that is possible.
One of them could be a power area, the other a clock domain.
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
On 28-02-17, 09:52, Rob Herring wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic.
An important thing here is that PM domain doesn't support such devices. i.e. a device isn't allowed to have multiple PM domains today. So a way to support such devices can be to create a virtual PM domain, that has two parents and device as its child.
On Wed, Mar 1, 2017 at 7:14 AM, Viresh Kumar viresh.kumar@linaro.org wrote:
On 28-02-17, 09:52, Rob Herring wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic.
An important thing here is that PM domain doesn't support such devices. i.e. a device isn't allowed to have multiple PM domains today. So a way to support such devices can be to create a virtual PM domain, that has two parents and device as its child.
As clock domains (and their support code) are fairly orthogonal to power areas, currently our power area controller driver just forwards the clock handling to the clock driver (cfr. rcar-sysc).
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
On 01-03-17, 09:45, Geert Uytterhoeven wrote:
On Wed, Mar 1, 2017 at 7:14 AM, Viresh Kumar viresh.kumar@linaro.org wrote:
On 28-02-17, 09:52, Rob Herring wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic.
An important thing here is that PM domain doesn't support such devices. i.e. a device isn't allowed to have multiple PM domains today. So a way to support such devices can be to create a virtual PM domain, that has two parents and device as its child.
As clock domains (and their support code) are fairly orthogonal to power areas, currently our power area controller driver just forwards the clock handling to the clock driver (cfr. rcar-sysc).
Perhaps Rajendra can explain better but Qcom have a case where they need to program two power domains as well.
On 02/28/2017 09:22 PM, Rob Herring wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
[...]
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic. And nesting of
yet the bindings for power-domains (for consumer devices) only allows for one powerdomain to be associated with a device.
power domains is certainly common, but a power domain being contained in 2 different parents? I don't even see how that is possible in the physical design. Now if we're mixing PM and power domains again and the cpu device is pointing to the cpu PM domain which contains 2 power domains, then certainly that is possible.
Rob
On Wed, Mar 1, 2017 at 12:27 AM, Rajendra Nayak rnayak@codeaurora.org wrote:
On 02/28/2017 09:22 PM, Rob Herring wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
[...]
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic. And nesting of
yet the bindings for power-domains (for consumer devices) only allows for one powerdomain to be associated with a device.
There's nothing in the binding only allowing that. If that was true, then #powerdomain-cells would be pointless as the property size would tell you the number of cells. Now it may be that we simply don't have any cases with more than 1. Hopefully that's not because bindings are working around PM domain limitations/requirements.
Rob
On 03/02/2017 04:43 AM, Rob Herring wrote:
On Wed, Mar 1, 2017 at 12:27 AM, Rajendra Nayak rnayak@codeaurora.org wrote:
On 02/28/2017 09:22 PM, Rob Herring wrote:
On Tue, Feb 28, 2017 at 9:14 AM, Ulf Hansson ulf.hansson@linaro.org wrote:
[...]
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
This comes from the early design of the generic PM domain, thus I assume we have some HW with such complex PM topology. However, I don't know if it is actually being used.
Moreover, the corresponding DT bindings for "power-domains" parents, can easily be extended to cover more than one parent. See more in Documentation/devicetree/bindings/power/power_domain.txt
I could easily see device having 2 power domains. For example a cpu may have separate domains for RAM/caches and logic. And nesting of
yet the bindings for power-domains (for consumer devices) only allows for one powerdomain to be associated with a device.
There's nothing in the binding only allowing that. If that was true, then #powerdomain-cells would be pointless
Is't #powerdomain-cells a powerdomain provider property? and used to specify if a powerdomain provider supports providing 1 or many powerdomains? I was talking about the power domain consumer property. Looking at Documentation/devicetree/bindings/power/power_domain.txt..
==PM domain consumers==
Required properties: - power-domains : A phandle and PM domain specifier as defined by bindings of the power controller specified by phandle.
It clearly says 'A phandle'. If there was a way to specify multiple power-domains for a consumer device should it not be saying a list of phandles? Like we do for clocks and regulators?
as the property size would tell you the number of cells. Now it may be that we simply don't have any cases with more than 1. Hopefully that's not because bindings are working around PM domain limitations/requirements.
Rob
On 28-02-17, 08:10, Rob Herring wrote:
On Tue, Feb 28, 2017 at 12:57 AM, Viresh Kumar viresh.kumar@linaro.org wrote:
That's what I did in V2, but then I turned it down considering the parent/child relationships we may have.
There are multiple cases we can have:
A.) DeviceX ---> Parent-domain-1 (Contains Perfomance states)
B.) DeviceX ---> Parent-domain-1 ---> Parent domain-2 (Contains Perfomance states)
Okay, how about this case first? Should we still use a phandle or an index value?
---> Parent domain-2 (Contains Perfomance states) | |
C.) DeviceX ---> Parent-domain-1 | | | ---> Parent domain-3 (Contains Perfomance states)
I'm a bit confused. How does a domain have 2 parent domains?
The framework supported it and so I thought it should be fairly common. Even in the last version, I coded the notifier to handle cases where we have only one parent domain. But then Kevin pointed out that we shouldn't be doing any such special things. But binding doesn't say anything about it though, and I was just presenting an example.
You have the same problem either way. If I have performance state 2 for the device, that corresponds to domain 2 or 3?
Right now I have used the same performance state for both the domains in the code, as I am not sure if we will have such a case. And probably we can figure this out when we have a case with separate levels for both parents. It would be trivial to extend the bindings to include a list instead of a single value here.
So, to conclude, should I use a phandle here or it is fine the way it is written right now ? With direct numbers, its easy to parse it in the OPP framework for example, as that's the value the QoS framework will use. Else we need to parse the phandle and read the "reg" value from there.
Only the resume_latency constraint uses the notifiers right now. In order to prepare for adding new constraint types with notifiers, move to a common notifier list.
Update pm_qos_update_target() to pass a pointer to the constraint structure to the notifier callbacks. Also update the notifier callbacks as well to error out for unexpected constraints.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- drivers/base/power/domain.c | 26 +++++++++++++++++++------- drivers/base/power/qos.c | 15 ++++----------- include/linux/pm_qos.h | 7 +++++++ kernel/power/qos.c | 2 +- 4 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e697dec9d25b..303490ab5ffd 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -416,14 +416,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) return ret; }
-static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, - unsigned long val, void *ptr) +static int __resume_latency_notifier(struct generic_pm_domain_data *gpd_data, + unsigned long val) { - struct generic_pm_domain_data *gpd_data; - struct device *dev; - - gpd_data = container_of(nb, struct generic_pm_domain_data, nb); - dev = gpd_data->base.dev; + struct device *dev = gpd_data->base.dev;
for (;;) { struct generic_pm_domain *genpd; @@ -456,6 +452,22 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, return NOTIFY_DONE; }
+static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, + unsigned long val, void *ptr) +{ + struct generic_pm_domain_data *gpd_data; + struct device *dev; + + gpd_data = container_of(nb, struct generic_pm_domain_data, nb); + dev = gpd_data->base.dev; + + if (dev_pm_qos_notifier_is_resume_latency(dev, ptr)) + return __resume_latency_notifier(gpd_data, val); + + dev_err(dev, "%s: Unexpected notifier call\n", __func__); + return NOTIFY_BAD; +} + /** * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0. * @work: Work structure used for scheduling the execution of this function. diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 271bec73185e..851fff60319c 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -173,18 +173,12 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) { struct dev_pm_qos *qos; struct pm_qos_constraints *c; - struct blocking_notifier_head *n;
qos = kzalloc(sizeof(*qos), GFP_KERNEL); if (!qos) return -ENOMEM;
- n = kzalloc(sizeof(*n), GFP_KERNEL); - if (!n) { - kfree(qos); - return -ENOMEM; - } - BLOCKING_INIT_NOTIFIER_HEAD(n); + BLOCKING_INIT_NOTIFIER_HEAD(&qos->notifiers);
c = &qos->resume_latency; plist_head_init(&c->list); @@ -192,7 +186,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; c->type = PM_QOS_MIN; - c->notifiers = n; + c->notifiers = &qos->notifiers;
c = &qos->latency_tolerance; plist_head_init(&c->list); @@ -269,7 +263,6 @@ void dev_pm_qos_constraints_destroy(struct device *dev) dev->power.qos = ERR_PTR(-ENODEV); spin_unlock_irq(&dev->power.lock);
- kfree(qos->resume_latency.notifiers); kfree(qos);
out: @@ -488,7 +481,7 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier) ret = dev_pm_qos_constraints_allocate(dev);
if (!ret) - ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers, + ret = blocking_notifier_chain_register(&dev->power.qos->notifiers, notifier);
mutex_unlock(&dev_pm_qos_mtx); @@ -515,7 +508,7 @@ int dev_pm_qos_remove_notifier(struct device *dev,
/* Silently return if the constraints object is not present. */ if (!IS_ERR_OR_NULL(dev->power.qos)) - retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, + retval = blocking_notifier_chain_unregister(&dev->power.qos->notifiers, notifier);
mutex_unlock(&dev_pm_qos_mtx); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 3e2547d6e207..dd02020a02b6 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -100,6 +100,7 @@ struct dev_pm_qos { struct dev_pm_qos_request *resume_latency_req; struct dev_pm_qos_request *latency_tolerance_req; struct dev_pm_qos_request *flags_req; + struct blocking_notifier_head notifiers; /* common for all constraints */ };
/* Action requested to pm_qos_update_target */ @@ -114,6 +115,12 @@ static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req) return req->dev != NULL; }
+static inline bool dev_pm_qos_notifier_is_resume_latency(struct device *dev, + struct pm_qos_constraints *c) +{ + return &dev->power.qos->resume_latency == c; +} + int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, enum pm_qos_req_action action, int value); bool pm_qos_update_flags(struct pm_qos_flags *pqf, diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 97b0df71303e..073324e0c3c8 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -315,7 +315,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, if (c->notifiers) blocking_notifier_call_chain(c->notifiers, (unsigned long)curr_value, - NULL); + c); } else { ret = 0; }
Some platforms have the capability to configure the performance state of their Power Domains. The performance levels are identified by positive integer values, a lower value represents lower performance state. The power domain driver should be able to retrieve all information required to configure the performance state of the power domain, with the help of the performance constraint's target value.
This patch adds a new QOS request type: DEV_PM_QOS_PERFORMANCE to support runtime performance constraints for the devices. Also allow notifiers to be registered against it, which will be used by frameworks like genpd.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- Documentation/power/pm_qos_interface.txt | 2 +- drivers/base/power/qos.c | 21 +++++++++++++++++++++ include/linux/pm_qos.h | 10 ++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt index 21d2d48f87a2..4b7decdebf98 100644 --- a/Documentation/power/pm_qos_interface.txt +++ b/Documentation/power/pm_qos_interface.txt @@ -168,7 +168,7 @@ The per-device PM QoS framework has a per-device notification tree. int dev_pm_qos_add_notifier(device, notifier): Adds a notification callback function for the device. The callback is called when the aggregated value of the device constraints list -is changed (for resume latency device PM QoS only). +is changed (for resume latency and performance device PM QoS only).
int dev_pm_qos_remove_notifier(device, notifier): Removes the notification callback function for the device. diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 851fff60319c..ca93ef6613c9 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -151,6 +151,10 @@ static int apply_constraint(struct dev_pm_qos_request *req, req->dev->power.set_latency_tolerance(req->dev, value); } break; + case DEV_PM_QOS_PERFORMANCE: + ret = pm_qos_update_target(&qos->performance, &req->data.pnode, + action, value); + break; case DEV_PM_QOS_FLAGS: ret = pm_qos_update_flags(&qos->flags, &req->data.flr, action, value); @@ -195,6 +199,14 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; c->type = PM_QOS_MIN;
+ c = &qos->performance; + plist_head_init(&c->list); + c->target_value = PM_QOS_PERFORMANCE_DEFAULT_VALUE; + c->default_value = PM_QOS_PERFORMANCE_DEFAULT_VALUE; + c->no_constraint_value = PM_QOS_PERFORMANCE_DEFAULT_VALUE; + c->type = PM_QOS_MAX; + c->notifiers = &qos->notifiers; + INIT_LIST_HEAD(&qos->flags.list);
spin_lock_irq(&dev->power.lock); @@ -253,6 +265,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev) apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); } + c = &qos->performance; + plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { + apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); + memset(req, 0, sizeof(*req)); + } f = &qos->flags; list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) { apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); @@ -363,6 +380,7 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, switch(req->type) { case DEV_PM_QOS_RESUME_LATENCY: case DEV_PM_QOS_LATENCY_TOLERANCE: + case DEV_PM_QOS_PERFORMANCE: curr_value = req->data.pnode.prio; break; case DEV_PM_QOS_FLAGS: @@ -572,6 +590,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev, req = dev->power.qos->flags_req; dev->power.qos->flags_req = NULL; break; + case DEV_PM_QOS_PERFORMANCE: + dev_err(dev, "Invalid user request (performance)\n"); + return; } __dev_pm_qos_remove_request(req); kfree(req); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index dd02020a02b6..c369286026b5 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -36,6 +36,7 @@ enum pm_qos_flags_status { #define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) +#define PM_QOS_PERFORMANCE_DEFAULT_VALUE 0 #define PM_QOS_LATENCY_ANY ((s32)(~(__u32)0 >> 1))
#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) @@ -55,6 +56,7 @@ struct pm_qos_flags_request { enum dev_pm_qos_req_type { DEV_PM_QOS_RESUME_LATENCY = 1, DEV_PM_QOS_LATENCY_TOLERANCE, + DEV_PM_QOS_PERFORMANCE, DEV_PM_QOS_FLAGS, };
@@ -96,9 +98,11 @@ struct pm_qos_flags { struct dev_pm_qos { struct pm_qos_constraints resume_latency; struct pm_qos_constraints latency_tolerance; + struct pm_qos_constraints performance; struct pm_qos_flags flags; struct dev_pm_qos_request *resume_latency_req; struct dev_pm_qos_request *latency_tolerance_req; + struct dev_pm_qos_request *performance_req; struct dev_pm_qos_request *flags_req; struct blocking_notifier_head notifiers; /* common for all constraints */ }; @@ -121,6 +125,12 @@ static inline bool dev_pm_qos_notifier_is_resume_latency(struct device *dev, return &dev->power.qos->resume_latency == c; }
+static inline bool dev_pm_qos_notifier_is_performance(struct device *dev, + struct pm_qos_constraints *c) +{ + return &dev->power.qos->performance == c; +} + int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, enum pm_qos_req_action action, int value); bool pm_qos_update_flags(struct pm_qos_flags *pqf,
Some platforms have the capability to configure the performance state of their Power Domains. The performance levels are identified by positive integer values, a lower value represents lower performance state. The power domain driver should be able to retrieve all information required to configure the performance state of the power domain, with the help of the performance constraint's target value.
This patch implements performance state management in PM domain core. The performance QOS uses the common QOS notifier list and we call __performance_notifier() if the notifier is issued for performance constraint.
This also allows the power domain drivers to implement a ->set_performance_state() callback, which will be called by the power domain core from within the notifier routine. If a domain doesn't implement ->set_performance_state() callback, then it is assumed that its parents are responsible for performance state configuration. Both devices and sub-domains are accounted for while finding the highest performance state requested.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- drivers/base/power/domain.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 4 +++ 2 files changed, 81 insertions(+)
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 303490ab5ffd..202effbebfd1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -452,6 +452,79 @@ static int __resume_latency_notifier(struct generic_pm_domain_data *gpd_data, return NOTIFY_DONE; }
+static void __update_domain_performance_state(struct generic_pm_domain *genpd, + int depth) +{ + struct generic_pm_domain_data *pd_data; + struct generic_pm_domain *subdomain; + struct pm_domain_data *pdd; + unsigned int state = 0; + struct gpd_link *link; + + /* Traverse all devices within the domain */ + list_for_each_entry(pdd, &genpd->dev_list, list_node) { + pd_data = to_gpd_data(pdd); + + if (pd_data->performance_state > state) + state = pd_data->performance_state; + } + + /* Traverse all subdomains within the domain */ + list_for_each_entry(link, &genpd->master_links, master_node) { + subdomain = link->slave; + + if (subdomain->performance_state > state) + state = subdomain->performance_state; + } + + if (genpd->performance_state == state) + return; + + genpd->performance_state = state; + + if (genpd->set_performance_state) { + genpd->set_performance_state(genpd, state); + return; + } + + /* Propagate to parent power domains */ + list_for_each_entry(link, &genpd->slave_links, slave_node) { + struct generic_pm_domain *master = link->master; + + genpd_lock_nested(master, depth + 1); + __update_domain_performance_state(master, depth + 1); + genpd_unlock(master); + } +} + +static int __performance_notifier(struct generic_pm_domain_data *gpd_data, + unsigned long val) +{ + struct generic_pm_domain *genpd = ERR_PTR(-ENODATA); + struct device *dev = gpd_data->base.dev; + struct pm_domain_data *pdd; + + spin_lock_irq(&dev->power.lock); + + pdd = dev->power.subsys_data ? + dev->power.subsys_data->domain_data : NULL; + + if (pdd && pdd->dev) + genpd = dev_to_genpd(dev); + + spin_unlock_irq(&dev->power.lock); + + if (IS_ERR(genpd)) + return NOTIFY_DONE; + + genpd_lock(genpd); + gpd_data->performance_state = val; + __update_domain_performance_state(genpd, 0); + genpd_unlock(genpd); + + return NOTIFY_DONE; +} + static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, unsigned long val, void *ptr) { @@ -464,6 +537,9 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, if (dev_pm_qos_notifier_is_resume_latency(dev, ptr)) return __resume_latency_notifier(gpd_data, val);
+ if (dev_pm_qos_notifier_is_performance(dev, ptr)) + return __performance_notifier(gpd_data, val); + dev_err(dev, "%s: Unexpected notifier call\n", __func__); return NOTIFY_BAD; } @@ -1157,6 +1233,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, gpd_data->td.constraint_changed = true; gpd_data->td.effective_constraint_ns = -1; gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; + gpd_data->performance_state = 0;
spin_lock_irq(&dev->power.lock);
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 5339ed5bd6f9..83795935709e 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -62,8 +62,11 @@ struct generic_pm_domain { unsigned int device_count; /* Number of devices */ unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ + unsigned int performance_state; /* Max requested performance state */ int (*power_off)(struct generic_pm_domain *domain); int (*power_on)(struct generic_pm_domain *domain); + int (*set_performance_state)(struct generic_pm_domain *domain, + unsigned int state); struct gpd_dev_ops dev_ops; s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ bool max_off_time_changed; @@ -117,6 +120,7 @@ struct generic_pm_domain_data { struct pm_domain_data base; struct gpd_timing_data td; struct notifier_block nb; + unsigned int performance_state; };
#ifdef CONFIG_PM_GENERIC_DOMAINS
This patch allows SoC's to define domains performance states in the DT using the "performance-states" node in the domain provider node.
Add API to read the performance states from DT by the domain specific drivers. Note that this information is only used by the domain specific drivers and the power domain core doesn't need to store it for now.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- drivers/base/power/domain.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 15 +++++++ 2 files changed, 116 insertions(+)
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 202effbebfd1..a7449c492990 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2251,6 +2251,107 @@ int of_genpd_parse_idle_states(struct device_node *dn, } EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
+/* Power domain performance state management helpers */ +static const struct of_device_id performance_state_match[] = { + { .compatible = "domain-performance-state", }, + { } +}; + +static int genpd_parse_performance_state(struct genpd_performance_state *state, + struct device_node *np) +{ + int ret; + + ret = of_property_read_u32(np, "reg", &state->performance_state); + if (ret) { + pr_err(" * %s missing reg property\n", np->full_name); + return ret; + } + + ret = of_property_read_variable_u32_array(np, "domain-microvolt", + &state->u_volt, 1, 3); + if (ret >= 0) + return 0; + + /* Property not found */ + if (ret == -EINVAL) + return 0; + + pr_err(" * %s Invalid domain-microvolt property\n", np->full_name); + return ret; +} + +/** + * of_genpd_parse_performance_states: Return array of performance states for the + * genpd. + * + * @dn: The genpd device node + * @states: The pointer to which the state array will be saved. + * @n: The count of elements in the array returned from this function. + * + * Returns the device performance states parsed from the OF node. The memory for + * the states is allocated by this function and is the responsibility of the + * caller to free the memory after use. + */ +int of_genpd_parse_performance_states(struct device_node *dn, + struct genpd_performance_state **states, int *n) +{ + struct genpd_performance_state *st; + struct device_node *perf_np, *np; + int i = 0, ret, count; + + perf_np = of_get_child_by_name(dn, "performance-states"); + if (!perf_np) { + pr_err("performance-states node not found in %s node\n", + dn->full_name); + return -ENODEV; + } + + if (!of_match_node(performance_state_match, perf_np)) { + pr_err("performance-states node found in %s node isn't compatible\n", + dn->full_name); + ret = -EINVAL; + goto put_node; + } + + count = of_get_child_count(perf_np); + if (count <= 0) { + pr_err("performance-states node found in %s node doesn't have any child nodes\n", + dn->full_name); + ret = -EINVAL; + goto put_node; + } + + st = kcalloc(count, sizeof(*st), GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto put_node; + } + + for_each_available_child_of_node(perf_np, np) { + ret = genpd_parse_performance_state(&st[i++], np); + if (ret) { + pr_err("Parsing of performance state node %s failed with err %d\n", + np->full_name, ret); + goto free_st; + } + } + + of_node_put(perf_np); + *n = count; + *states = st; + + return 0; + +free_st: + kfree(st); +put_node: + of_node_put(perf_np); + + return ret; +} +EXPORT_SYMBOL_GPL(of_genpd_parse_performance_states); + #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 83795935709e..7659ce3968c7 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -44,6 +44,13 @@ struct genpd_power_state { struct fwnode_handle *fwnode; };
+struct genpd_performance_state { + unsigned int performance_state; + unsigned int u_volt; + unsigned int u_volt_min; + unsigned int u_volt_max; +}; + struct genpd_lock_ops;
struct generic_pm_domain { @@ -226,6 +233,8 @@ extern int of_genpd_add_subdomain(struct of_phandle_args *parent, extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); extern int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n); +extern int of_genpd_parse_performance_states(struct device_node *dn, + struct genpd_performance_state **states, int *n);
int genpd_dev_pm_attach(struct device *dev); #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ @@ -261,6 +270,12 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn, return -ENODEV; }
+static inline int of_genpd_parse_performance_states(struct device_node *dn, + struct genpd_performance_state **states, int *n) +{ + return -ENODEV; +} + static inline int genpd_dev_pm_attach(struct device *dev) { return -ENODEV;
This patch allows the OPP core to parse the "domain-performance-state" property in the OPP nodes. The nodes are allowed to have the "domain-performance-state" property, only if the device node contains a "power-domains" property. The OPP nodes aren't allowed to contain the property partially, i.e. Either all OPP nodes in the OPP table have the "domain-performance-state" property or none of them have it.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Tested-by: Rajendra Nayak rnayak@codeaurora.org --- drivers/base/power/opp/core.c | 73 ++++++++++++++++++++++++++++++++++++++++ drivers/base/power/opp/debugfs.c | 4 +++ drivers/base/power/opp/of.c | 37 ++++++++++++++++++++ drivers/base/power/opp/opp.h | 12 +++++++ 4 files changed, 126 insertions(+)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 91ec3232d630..211551f377e9 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -542,6 +542,63 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk, return ret; }
+static int _update_pm_qos_request(struct device *dev, + struct dev_pm_qos_request *req, + unsigned int perf) +{ + int ret; + + if (likely(dev_pm_qos_request_active(req))) + ret = dev_pm_qos_update_request(req, perf); + else + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_PERFORMANCE, + perf); + + if (ret < 0) + return ret; + + return 0; +} + +static int _generic_set_opp_pd(struct device *dev, struct clk *clk, + struct dev_pm_qos_request *req, + unsigned long old_freq, unsigned long freq, + unsigned int old_perf, unsigned int new_perf) +{ + int ret; + + /* Scaling up? Scale voltage before frequency */ + if (freq > old_freq) { + ret = _update_pm_qos_request(dev, req, new_perf); + if (ret) + return ret; + } + + /* Change frequency */ + ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); + if (ret) + goto restore_perf; + + /* Scaling down? Scale voltage after frequency */ + if (freq < old_freq) { + ret = _update_pm_qos_request(dev, req, new_perf); + if (ret) + goto restore_freq; + } + + return 0; + +restore_freq: + if (_generic_set_opp_clk_only(dev, clk, freq, old_freq)) + dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", + __func__, old_freq); +restore_perf: + if (old_perf) + _update_pm_qos_request(dev, req, old_perf); + + return ret; +} + static int _generic_set_opp(struct dev_pm_set_opp_data *data) { struct dev_pm_opp_supply *old_supply = data->old_opp.supplies; @@ -662,6 +719,19 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
regulators = opp_table->regulators;
+ /* Has power domains performance states */ + if (opp_table->has_pd_perf_states) { + unsigned int old_perf = 0, new_perf; + struct dev_pm_qos_request *req = &opp_table->qos_request; + + new_perf = opp->pd_perf_state; + if (!IS_ERR(old_opp)) + old_perf = old_opp->pd_perf_state; + + return _generic_set_opp_pd(dev, clk, req, old_freq, freq, + old_perf, new_perf); + } + /* Only frequency scaling */ if (!regulators) { ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); @@ -807,6 +877,9 @@ static void _opp_table_kref_release(struct kref *kref) struct opp_table *opp_table = container_of(kref, struct opp_table, kref); struct opp_device *opp_dev;
+ if (dev_pm_qos_request_active(&opp_table->qos_request)) + dev_pm_qos_remove_request(&opp_table->qos_request); + /* Release clk */ if (!IS_ERR(opp_table->clk)) clk_put(opp_table->clk); diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c index 95f433db4ac7..264958ab3de9 100644 --- a/drivers/base/power/opp/debugfs.c +++ b/drivers/base/power/opp/debugfs.c @@ -104,6 +104,10 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) return -ENOMEM;
+ if (!debugfs_create_u32("power_domain_perf_state", S_IRUGO, d, + &opp->pd_perf_state)) + return -ENOMEM; + if (!opp_debug_create_supplies(opp, opp_table, d)) return -ENOMEM;
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c index 779428676f63..e3b5f10e7f25 100644 --- a/drivers/base/power/opp/of.c +++ b/drivers/base/power/opp/of.c @@ -311,6 +311,38 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, if (!of_property_read_u32(np, "clock-latency-ns", &val)) new_opp->clock_latency_ns = val;
+ /* + * Make sure that all information is present around domain power states + * and nothing is left out. + */ + if (!of_property_read_u32(np, "domain-performance-state", + &new_opp->pd_perf_state)) { + if (!opp_table->has_pd) { + ret = -EINVAL; + dev_err(dev, "%s: OPP node can't have performance state as device doesn't have power-domain\n", + __func__); + goto free_opp; + } + + if (opp_table->has_pd_perf_states == -1) { + opp_table->has_pd_perf_states = 1; + } else if (!opp_table->has_pd_perf_states) { + ret = -EINVAL; + dev_err(dev, "%s: Not all OPP nodes have performance state\n", + __func__); + goto free_opp; + } + } else { + if (opp_table->has_pd_perf_states == -1) { + opp_table->has_pd_perf_states = 0; + } else if (opp_table->has_pd_perf_states) { + ret = -EINVAL; + dev_err(dev, "%s: Not all OPP nodes have performance state\n", + __func__); + goto free_opp; + } + } + ret = opp_parse_supplies(new_opp, dev, opp_table); if (ret) goto free_opp; @@ -375,6 +407,11 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) if (!opp_table) return -ENOMEM;
+ if (of_find_property(dev->of_node, "power-domains", NULL)) { + opp_table->has_pd = true; + opp_table->has_pd_perf_states = -1; + } + /* We have opp-table node now, iterate over it and add OPPs */ for_each_available_child_of_node(opp_np, np) { count++; diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 166eef990599..41a2c0a67031 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -20,6 +20,7 @@ #include <linux/list.h> #include <linux/limits.h> #include <linux/pm_opp.h> +#include <linux/pm_qos.h> #include <linux/notifier.h>
struct clk; @@ -58,6 +59,7 @@ extern struct list_head opp_tables; * @dynamic: not-created from static DT entries. * @turbo: true if turbo (boost) OPP * @suspend: true if suspend OPP + * @pd_perf_state: Performance state of power domain * @rate: Frequency in hertz * @supplies: Power supplies voltage/current values * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's @@ -76,6 +78,7 @@ struct dev_pm_opp { bool dynamic; bool turbo; bool suspend; + unsigned int pd_perf_state; unsigned long rate;
struct dev_pm_opp_supply *supplies; @@ -137,6 +140,11 @@ enum opp_table_access { * @regulator_count: Number of power supply regulators * @set_opp: Platform specific set_opp callback * @set_opp_data: Data to be passed to set_opp callback + * @has_pd: True if the device node contains power-domain property + * @has_pd_perf_states: Can have value of 0, 1 or -1. -1 means uninitialized + * state, 0 means that OPP nodes don't have perf states and 1 means that OPP + * nodes have perf states. + * @qos_request: Qos request. * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. * @@ -174,6 +182,10 @@ struct opp_table { int (*set_opp)(struct dev_pm_set_opp_data *data); struct dev_pm_set_opp_data *set_opp_data;
+ bool has_pd; + int has_pd_perf_states; + struct dev_pm_qos_request qos_request; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; char dentry_name[NAME_MAX];
Viresh Kumar viresh.kumar@linaro.org writes:
This series contain V3 of both the bindings and the code that implement them. They were sent separately earlier.
Some platforms have the capability to configure the performance state of their power domains. The process of configuring the performance state is pretty much platform dependent and we may need to work with a wide range of configurables. For some platforms, like Qcom, it can be a positive integer value alone, while in other cases it can be voltage levels, etc.
Why limit it to just voltage levels.
As I suggested earlier, I think this should use OPPs. Remember that a PM domain is not limited to a hardware power domain, but is just a grouping mechanism for devices that share some PM properties. As mentioned by Geert, this can also be a clock domain, where frequencies would make sense as well. One can imagine using this type of PM domain to manage an interconnect/bus which has scalable voltage/frequencies as well.
Kevin
On 10-03-17, 12:38, Kevin Hilman wrote:
Why limit it to just voltage levels.
As I suggested earlier, I think this should use OPPs. Remember that a PM domain is not limited to a hardware power domain, but is just a grouping mechanism for devices that share some PM properties. As mentioned by Geert, this can also be a clock domain, where frequencies would make sense as well. One can imagine using this type of PM domain to manage an interconnect/bus which has scalable voltage/frequencies as well.
Okay, I tried to do that change today and am blocked a bit right now.
The OPP core and all of its APIs/interfaces have dependency on the "struct device" for their working. It gets the of_node from it, stores the device pointer to manage cases where multiple devices share OPP table, uses it to get clk and regulators.
But the "genpd" structure doesn't have a 'struct device' associated with it. How should I make both of them work together?
I tried to create separate helpers that don't accept 'dev', but that is also not good. Just too much redundant code everywhere.
Would creating a 'dev' structure within 'generic_pm_domain' be acceptable? Or should we ask the domain-drivers to call something like of_genpd_parse_idle_states(), with a fake 'dev' structure which has its of_node initialized? Or maybe move that hack within the OPP-core API, which can create a dev structure at runtime for the genpd passed to it and get the OPP table out?
On 13 March 2017 at 16:09, Viresh Kumar viresh.kumar@linaro.org wrote:
On 10-03-17, 12:38, Kevin Hilman wrote:
Why limit it to just voltage levels.
As I suggested earlier, I think this should use OPPs. Remember that a PM domain is not limited to a hardware power domain, but is just a grouping mechanism for devices that share some PM properties. As mentioned by Geert, this can also be a clock domain, where frequencies would make sense as well. One can imagine using this type of PM domain to manage an interconnect/bus which has scalable voltage/frequencies as well.
Okay, I tried to do that change today and am blocked a bit right now.
The OPP core and all of its APIs/interfaces have dependency on the "struct device" for their working. It gets the of_node from it, stores the device pointer to manage cases where multiple devices share OPP table, uses it to get clk and regulators.
But the "genpd" structure doesn't have a 'struct device' associated with it. How should I make both of them work together?
I tried to create separate helpers that don't accept 'dev', but that is also not good. Just too much redundant code everywhere.
Would creating a 'dev' structure within 'generic_pm_domain' be acceptable? Or should we ask the domain-drivers to call something like of_genpd_parse_idle_states(), with a fake 'dev' structure which has its of_node initialized? Or maybe move that hack within the OPP-core API, which can create a dev structure at runtime for the genpd passed to it and get the OPP table out?
Ulf/Kevin,
I am currently blocked on this decision. Will it be possible for you guys to suggest something, so that I can send V3 soon ?
The most ideal solution seems to be adding a device structure in genpd structure and add a genpd bus as well probably.
-- viresh
linaro-kernel@lists.linaro.org