Skip to content

Commit f38d1a6

Browse files
Ulf Hanssonrafaeljw
authored andcommitted
PM: domains: Allocate governor data dynamically based on a genpd governor
If a genpd doesn't have an associated governor assigned, several variables in the struct generic_pm_domain becomes superfluous. Rather than wasting memory in allocated genpds, let's move the variables from the struct generic_pm_domain into a new separate struct. In this way, we can instead dynamically decide when we need to allocate the corresponding data for it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent ba43d6d commit f38d1a6

3 files changed

Lines changed: 70 additions & 41 deletions

File tree

drivers/base/power/domain.c

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
527527
goto out;
528528

529529
genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
530-
genpd->max_off_time_changed = true;
530+
if (genpd->gd)
531+
genpd->gd->max_off_time_changed = true;
531532
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
532533
genpd->name, "on", elapsed_ns);
533534

@@ -576,7 +577,8 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
576577
goto out;
577578

578579
genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
579-
genpd->max_off_time_changed = true;
580+
if (genpd->gd)
581+
genpd->gd->max_off_time_changed = true;
580582
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
581583
genpd->name, "off", elapsed_ns);
582584

@@ -772,7 +774,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
772774
dev = gpd_data->base.dev;
773775

774776
for (;;) {
775-
struct generic_pm_domain *genpd;
777+
struct generic_pm_domain *genpd = ERR_PTR(-ENODATA);
776778
struct pm_domain_data *pdd;
777779
struct gpd_timing_data *td;
778780

@@ -782,18 +784,17 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
782784
dev->power.subsys_data->domain_data : NULL;
783785
if (pdd) {
784786
td = to_gpd_data(pdd)->td;
785-
if (td)
787+
if (td) {
786788
td->constraint_changed = true;
787-
genpd = dev_to_genpd(dev);
788-
} else {
789-
genpd = ERR_PTR(-ENODATA);
789+
genpd = dev_to_genpd(dev);
790+
}
790791
}
791792

792793
spin_unlock_irq(&dev->power.lock);
793794

794795
if (!IS_ERR(genpd)) {
795796
genpd_lock(genpd);
796-
genpd->max_off_time_changed = true;
797+
genpd->gd->max_off_time_changed = true;
797798
genpd_unlock(genpd);
798799
}
799800

@@ -922,7 +923,7 @@ static int genpd_runtime_suspend(struct device *dev)
922923
td->suspend_latency_ns = elapsed_ns;
923924
dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
924925
elapsed_ns);
925-
genpd->max_off_time_changed = true;
926+
genpd->gd->max_off_time_changed = true;
926927
td->constraint_changed = true;
927928
}
928929
}
@@ -1002,7 +1003,7 @@ static int genpd_runtime_resume(struct device *dev)
10021003
td->resume_latency_ns = elapsed_ns;
10031004
dev_dbg(dev, "resume latency exceeded, %lld ns\n",
10041005
elapsed_ns);
1005-
genpd->max_off_time_changed = true;
1006+
genpd->gd->max_off_time_changed = true;
10061007
td->constraint_changed = true;
10071008
}
10081009
}
@@ -1617,6 +1618,7 @@ static int genpd_get_cpu(struct generic_pm_domain *genpd, struct device *dev)
16171618
static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
16181619
struct device *base_dev)
16191620
{
1621+
struct genpd_governor_data *gd = genpd->gd;
16201622
struct generic_pm_domain_data *gpd_data;
16211623
int ret;
16221624

@@ -1625,7 +1627,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
16251627
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
16261628
return -EINVAL;
16271629

1628-
gpd_data = genpd_alloc_dev_data(dev, genpd->gov);
1630+
gpd_data = genpd_alloc_dev_data(dev, gd);
16291631
if (IS_ERR(gpd_data))
16301632
return PTR_ERR(gpd_data);
16311633

@@ -1641,7 +1643,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
16411643
dev_pm_domain_set(dev, &genpd->domain);
16421644

16431645
genpd->device_count++;
1644-
genpd->max_off_time_changed = true;
1646+
if (gd)
1647+
gd->max_off_time_changed = true;
16451648

16461649
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
16471650

@@ -1695,7 +1698,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
16951698
}
16961699

16971700
genpd->device_count--;
1698-
genpd->max_off_time_changed = true;
1701+
if (genpd->gd)
1702+
genpd->gd->max_off_time_changed = true;
16991703

17001704
genpd_clear_cpumask(genpd, gpd_data->cpu);
17011705
dev_pm_domain_set(dev, NULL);
@@ -1970,24 +1974,39 @@ static int genpd_set_default_power_state(struct generic_pm_domain *genpd)
19701974

19711975
static int genpd_alloc_data(struct generic_pm_domain *genpd)
19721976
{
1977+
struct genpd_governor_data *gd = NULL;
19731978
int ret;
19741979

19751980
if (genpd_is_cpu_domain(genpd) &&
19761981
!zalloc_cpumask_var(&genpd->cpus, GFP_KERNEL))
19771982
return -ENOMEM;
19781983

1984+
if (genpd->gov) {
1985+
gd = kzalloc(sizeof(*gd), GFP_KERNEL);
1986+
if (!gd) {
1987+
ret = -ENOMEM;
1988+
goto free;
1989+
}
1990+
1991+
gd->max_off_time_ns = -1;
1992+
gd->max_off_time_changed = true;
1993+
gd->next_wakeup = KTIME_MAX;
1994+
}
1995+
19791996
/* Use only one "off" state if there were no states declared */
19801997
if (genpd->state_count == 0) {
19811998
ret = genpd_set_default_power_state(genpd);
19821999
if (ret)
19832000
goto free;
19842001
}
19852002

2003+
genpd->gd = gd;
19862004
return 0;
19872005

19882006
free:
19892007
if (genpd_is_cpu_domain(genpd))
19902008
free_cpumask_var(genpd->cpus);
2009+
kfree(gd);
19912010
return ret;
19922011
}
19932012

@@ -1997,6 +2016,7 @@ static void genpd_free_data(struct generic_pm_domain *genpd)
19972016
free_cpumask_var(genpd->cpus);
19982017
if (genpd->free_states)
19992018
genpd->free_states(genpd->states, genpd->state_count);
2019+
kfree(genpd->gd);
20002020
}
20012021

20022022
static void genpd_lock_init(struct generic_pm_domain *genpd)
@@ -2036,9 +2056,6 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
20362056
atomic_set(&genpd->sd_count, 0);
20372057
genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
20382058
genpd->device_count = 0;
2039-
genpd->max_off_time_ns = -1;
2040-
genpd->max_off_time_changed = true;
2041-
genpd->next_wakeup = KTIME_MAX;
20422059
genpd->provider = NULL;
20432060
genpd->has_provider = false;
20442061
genpd->accounting_time = ktime_get_mono_fast_ns();

drivers/base/power/domain_governor.c

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -146,19 +146,21 @@ static void update_domain_next_wakeup(struct generic_pm_domain *genpd, ktime_t n
146146
}
147147

148148
list_for_each_entry(link, &genpd->parent_links, parent_node) {
149-
next_wakeup = link->child->next_wakeup;
149+
struct genpd_governor_data *cgd = link->child->gd;
150+
151+
next_wakeup = cgd ? cgd->next_wakeup : KTIME_MAX;
150152
if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now))
151153
if (ktime_before(next_wakeup, domain_wakeup))
152154
domain_wakeup = next_wakeup;
153155
}
154156

155-
genpd->next_wakeup = domain_wakeup;
157+
genpd->gd->next_wakeup = domain_wakeup;
156158
}
157159

158160
static bool next_wakeup_allows_state(struct generic_pm_domain *genpd,
159161
unsigned int state, ktime_t now)
160162
{
161-
ktime_t domain_wakeup = genpd->next_wakeup;
163+
ktime_t domain_wakeup = genpd->gd->next_wakeup;
162164
s64 idle_time_ns, min_sleep_ns;
163165

164166
min_sleep_ns = genpd->states[state].power_off_latency_ns +
@@ -188,8 +190,9 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
188190
* All subdomains have been powered off already at this point.
189191
*/
190192
list_for_each_entry(link, &genpd->parent_links, parent_node) {
191-
struct generic_pm_domain *sd = link->child;
192-
s64 sd_max_off_ns = sd->max_off_time_ns;
193+
struct genpd_governor_data *cgd = link->child->gd;
194+
195+
s64 sd_max_off_ns = cgd ? cgd->max_off_time_ns : -1;
193196

194197
if (sd_max_off_ns < 0)
195198
continue;
@@ -247,7 +250,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
247250
* time and the time needed to turn the domain on is the maximum
248251
* theoretical time this domain can spend in the "off" state.
249252
*/
250-
genpd->max_off_time_ns = min_off_time_ns -
253+
genpd->gd->max_off_time_ns = min_off_time_ns -
251254
genpd->states[state].power_on_latency_ns;
252255
return true;
253256
}
@@ -262,6 +265,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
262265
static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
263266
{
264267
struct generic_pm_domain *genpd = pd_to_genpd(pd);
268+
struct genpd_governor_data *gd = genpd->gd;
265269
int state_idx = genpd->state_count - 1;
266270
struct gpd_link *link;
267271

@@ -272,26 +276,26 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
272276
* cannot be met.
273277
*/
274278
update_domain_next_wakeup(genpd, now);
275-
if ((genpd->flags & GENPD_FLAG_MIN_RESIDENCY) && (genpd->next_wakeup != KTIME_MAX)) {
279+
if ((genpd->flags & GENPD_FLAG_MIN_RESIDENCY) && (gd->next_wakeup != KTIME_MAX)) {
276280
/* Let's find out the deepest domain idle state, the devices prefer */
277281
while (state_idx >= 0) {
278282
if (next_wakeup_allows_state(genpd, state_idx, now)) {
279-
genpd->max_off_time_changed = true;
283+
gd->max_off_time_changed = true;
280284
break;
281285
}
282286
state_idx--;
283287
}
284288

285289
if (state_idx < 0) {
286290
state_idx = 0;
287-
genpd->cached_power_down_ok = false;
291+
gd->cached_power_down_ok = false;
288292
goto done;
289293
}
290294
}
291295

292-
if (!genpd->max_off_time_changed) {
293-
genpd->state_idx = genpd->cached_power_down_state_idx;
294-
return genpd->cached_power_down_ok;
296+
if (!gd->max_off_time_changed) {
297+
genpd->state_idx = gd->cached_power_down_state_idx;
298+
return gd->cached_power_down_ok;
295299
}
296300

297301
/*
@@ -300,29 +304,33 @@ static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
300304
* going to be called for any parent until this instance
301305
* returns.
302306
*/
303-
list_for_each_entry(link, &genpd->child_links, child_node)
304-
link->parent->max_off_time_changed = true;
307+
list_for_each_entry(link, &genpd->child_links, child_node) {
308+
struct genpd_governor_data *pgd = link->parent->gd;
309+
310+
if (pgd)
311+
pgd->max_off_time_changed = true;
312+
}
305313

306-
genpd->max_off_time_ns = -1;
307-
genpd->max_off_time_changed = false;
308-
genpd->cached_power_down_ok = true;
314+
gd->max_off_time_ns = -1;
315+
gd->max_off_time_changed = false;
316+
gd->cached_power_down_ok = true;
309317

310318
/*
311319
* Find a state to power down to, starting from the state
312320
* determined by the next wakeup.
313321
*/
314322
while (!__default_power_down_ok(pd, state_idx)) {
315323
if (state_idx == 0) {
316-
genpd->cached_power_down_ok = false;
324+
gd->cached_power_down_ok = false;
317325
break;
318326
}
319327
state_idx--;
320328
}
321329

322330
done:
323331
genpd->state_idx = state_idx;
324-
genpd->cached_power_down_state_idx = genpd->state_idx;
325-
return genpd->cached_power_down_ok;
332+
gd->cached_power_down_state_idx = genpd->state_idx;
333+
return gd->cached_power_down_ok;
326334
}
327335

328336
static bool default_power_down_ok(struct dev_pm_domain *pd)

include/linux/pm_domain.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ struct gpd_dev_ops {
9191
int (*stop)(struct device *dev);
9292
};
9393

94+
struct genpd_governor_data {
95+
s64 max_off_time_ns;
96+
bool max_off_time_changed;
97+
ktime_t next_wakeup;
98+
bool cached_power_down_ok;
99+
bool cached_power_down_state_idx;
100+
};
101+
94102
struct genpd_power_state {
95103
s64 power_off_latency_ns;
96104
s64 power_on_latency_ns;
@@ -114,6 +122,7 @@ struct generic_pm_domain {
114122
struct list_head child_links; /* Links with PM domain as a child */
115123
struct list_head dev_list; /* List of devices */
116124
struct dev_power_governor *gov;
125+
struct genpd_governor_data *gd; /* Data used by a genpd governor. */
117126
struct work_struct power_off_work;
118127
struct fwnode_handle *provider; /* Identity of the domain provider */
119128
bool has_provider;
@@ -134,11 +143,6 @@ struct generic_pm_domain {
134143
int (*set_performance_state)(struct generic_pm_domain *genpd,
135144
unsigned int state);
136145
struct gpd_dev_ops dev_ops;
137-
s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
138-
ktime_t next_wakeup; /* Maintained by the domain governor */
139-
bool max_off_time_changed;
140-
bool cached_power_down_ok;
141-
bool cached_power_down_state_idx;
142146
int (*attach_dev)(struct generic_pm_domain *domain,
143147
struct device *dev);
144148
void (*detach_dev)(struct generic_pm_domain *domain,

0 commit comments

Comments
 (0)