[1/8] PM / Domains: Make genpd state allocation dynamic

Message ID 1475699519-109623-2-git-send-email-lina.iyer@linaro.org
State New
Headers show

Commit Message

Lina Iyer Oct. 5, 2016, 8:31 p.m.
Allow PM Domain states to be defined dynamically by the drivers. This
removes the limitation on the maximum number of states possible for a
domain.

Cc: Axel Haslam <ahaslam+renesas@baylibre.com>
Suggested-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>

---
 arch/arm/mach-imx/gpc.c     | 17 ++++++++++-------
 drivers/base/power/domain.c | 10 ----------
 include/linux/pm_domain.h   |  4 +---
 3 files changed, 11 insertions(+), 20 deletions(-)

-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Lina Iyer Oct. 6, 2016, 3:40 p.m. | #1
On Thu, Oct 06 2016 at 02:37 -0600, Ulf Hansson wrote:
>On 5 October 2016 at 22:31, Lina Iyer <lina.iyer@linaro.org> wrote:

>> Allow PM Domain states to be defined dynamically by the drivers. This

>> removes the limitation on the maximum number of states possible for a

>> domain.

>>

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

>> Suggested-by: Ulf Hansson <ulf.hansson@linaro.org>

>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>

<...>
>> -#define GENPD_MAX_NUM_STATES   8 /* Number of possible low power states */

>> -

>>  enum gpd_status {

>>         GPD_STATE_ACTIVE = 0,   /* PM domain is active */

>>         GPD_STATE_POWER_OFF,    /* PM domain is off */

>> @@ -70,7 +68,7 @@ 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[GENPD_MAX_NUM_STATES];

>> +       struct genpd_power_state *states;

>>         unsigned int state_count; /* number of states */

>>         unsigned int state_idx; /* state that genpd will go to when off */

>>

>> --

>> 2.7.4

>>

>

>In general I like the improvement, but..

>

>This change implies that ->states may very well be NULL. This isn't

>validated by genpd's internal logic when power off/on the domain

>(genpd_power_on|off(), __default_power_down_ok()). You need to fix

>this, somehow.

>

Good point.

>Perhaps the easiest solutions is, when pm_genpd_init() finds that

>->state is NULL, that we allocate a struct genpd_power_state with

>array size of 1 and assign it to ->states. Although, doing this also

>means you need to track that genpd was responsible for the the

>allocation, so it must also free the data from within genpd_remove().

>

>Unless you have other ideas!?

>

I can think of some hacks, but they are uglier than the problem we are
trying to solve. We could drop this patch. Real world situations would
not have more than 8 states and if there is one, we can think about it
then.

Thanks,
Lina
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lina Iyer Oct. 6, 2016, 8:57 p.m. | #2
On Thu, Oct 06 2016 at 13:45 -0600, Ulf Hansson wrote:
>On 6 October 2016 at 17:40, Lina Iyer <lina.iyer@linaro.org> wrote:

>> On Thu, Oct 06 2016 at 02:37 -0600, Ulf Hansson wrote:

>>>

>>> On 5 October 2016 at 22:31, Lina Iyer <lina.iyer@linaro.org> wrote:

>>>>

>>>> Allow PM Domain states to be defined dynamically by the drivers. This

>>>> removes the limitation on the maximum number of states possible for a

>>>> domain.

>>>>

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

>>>> Suggested-by: Ulf Hansson <ulf.hansson@linaro.org>

>>>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>

>>

>> <...>

>>>>

>>>> -#define GENPD_MAX_NUM_STATES   8 /* Number of possible low power states

>>>> */

>>>> -

>>>>  enum gpd_status {

>>>>         GPD_STATE_ACTIVE = 0,   /* PM domain is active */

>>>>         GPD_STATE_POWER_OFF,    /* PM domain is off */

>>>> @@ -70,7 +68,7 @@ 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[GENPD_MAX_NUM_STATES];

>>>> +       struct genpd_power_state *states;

>>>>         unsigned int state_count; /* number of states */

>>>>         unsigned int state_idx; /* state that genpd will go to when off

>>>> */

>>>>

>>>> --

>>>> 2.7.4

>>>>

>>>

>>> In general I like the improvement, but..

>>>

>>> This change implies that ->states may very well be NULL. This isn't

>>> validated by genpd's internal logic when power off/on the domain

>>> (genpd_power_on|off(), __default_power_down_ok()). You need to fix

>>> this, somehow.

>>>

>> Good point.

>>

>>> Perhaps the easiest solutions is, when pm_genpd_init() finds that

>>> ->state is NULL, that we allocate a struct genpd_power_state with

>>> array size of 1 and assign it to ->states. Although, doing this also

>>> means you need to track that genpd was responsible for the the

>>> allocation, so it must also free the data from within genpd_remove().

>>>

>>> Unless you have other ideas!?

>>>

>> I can think of some hacks, but they are uglier than the problem we are

>> trying to solve. We could drop this patch. Real world situations would

>> not have more than 8 states and if there is one, we can think about it

>> then.

>

>The problem with the current approach is that we waste some memory as

>we always have an array of 8 states per genpd. In the worst case,

>which currently is the most common case, only 1 out of 8 states is

>being used.

>

>So, let's not be lazy here and instead take the opportunity to fix

>this, and especially I think this makes sense, before we go on and add

>the DT parsing of the domain-idle-states.

>

Hmm.. We are not wasting much memory in comparison, but if you insist,
sure.

>The more sophisticated method would probably be to use kobject/kref,

>but let's not go there for now. Instead let's try an easy method of

>just tracking whether the allocations had been made internally by

>genpd, via adding a "bool state_allocated to the struct

>generic_pm_domain. Would that work?

>

It would work.

i.
How about an additional static state by default in the domain structure,
if the platform does not provide a state then the default structure is
used. That way we dont have to track it. But it does waste memory
eqivalent to a state, when there are states provided by the platform.

ii.
I could add a void *free to the domain structure and save the memory
allocated by default in the *free. At domain remove, we just do a kfree
on free.

iii.
Use a boolean flag.

Thanks,
Lina

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 0df062d..b92dad5 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -380,13 +380,6 @@  static struct pu_domain imx6q_pu_domain = {
 		.name = "PU",
 		.power_off = imx6q_pm_pu_power_off,
 		.power_on = imx6q_pm_pu_power_on,
-		.states = {
-			[0] = {
-				.power_off_latency_ns = 25000,
-				.power_on_latency_ns = 2000000,
-			},
-		},
-		.state_count = 1,
 	},
 };
 
@@ -430,6 +423,16 @@  static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
 	if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
 		return 0;
 
+	imx6q_pu_domain.base.states = devm_kzalloc(dev,
+					sizeof(*imx6q_pu_domain.base.states),
+					GFP_KERNEL);
+	if (!imx6q_pu_domain.base.states)
+		return -ENOMEM;
+
+	imx6q_pu_domain.base.states[0].power_off_latency_ns = 25000;
+	imx6q_pu_domain.base.states[0].power_on_latency_ns = 2000000;
+	mx6q_pu_domain.base.state_count = 1,
+
 	pm_genpd_init(&imx6q_pu_domain.base, NULL, false);
 	return of_genpd_add_provider_onecell(dev->of_node,
 					     &imx_gpc_onecell_data);
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index e023066..740afa9 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1325,16 +1325,6 @@  int pm_genpd_init(struct generic_pm_domain *genpd,
 		genpd->dev_ops.start = pm_clk_resume;
 	}
 
-	if (genpd->state_idx >= GENPD_MAX_NUM_STATES) {
-		pr_warn("Initial state index out of bounds.\n");
-		genpd->state_idx = GENPD_MAX_NUM_STATES - 1;
-	}
-
-	if (genpd->state_count > GENPD_MAX_NUM_STATES) {
-		pr_warn("Limiting states to  %d\n", GENPD_MAX_NUM_STATES);
-		genpd->state_count = GENPD_MAX_NUM_STATES;
-	}
-
 	/* Use only one "off" state if there were no states declared */
 	if (genpd->state_count == 0)
 		genpd->state_count = 1;
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index a09fe5c..bd1ffb9 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -19,8 +19,6 @@ 
 /* 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_MAX_NUM_STATES	8 /* Number of possible low power states */
-
 enum gpd_status {
 	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
 	GPD_STATE_POWER_OFF,	/* PM domain is off */
@@ -70,7 +68,7 @@  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[GENPD_MAX_NUM_STATES];
+	struct genpd_power_state *states;
 	unsigned int state_count; /* number of states */
 	unsigned int state_idx; /* state that genpd will go to when off */