diff mbox

[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. UTC
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(-)

Comments

Ulf Hansson Oct. 6, 2016, 8:36 a.m. UTC | #1
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>
> ---
>  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(-)
>
> 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 */
>
> --
> 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.

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!?

Kind regards
Uffe
Lina Iyer Oct. 6, 2016, 3:40 p.m. UTC | #2
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
Ulf Hansson Oct. 6, 2016, 7:45 p.m. UTC | #3
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.

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?

Kind regards
Uffe
Lina Iyer Oct. 6, 2016, 8:57 p.m. UTC | #4
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
Ulf Hansson Oct. 7, 2016, 8:39 a.m. UTC | #5
On 6 October 2016 at 22:57, Lina Iyer <lina.iyer@linaro.org> wrote:
> 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.

I thought about this, but I think it could be a bit messy as well.
Better to do an allocation when needed.

>
> 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.

Both ii) and iii) works for me!

Kind regards
Uffe

>
> Thanks,
> Lina
>
diff mbox

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 */