Skip to content

Commit 66d29d8

Browse files
Ulf Hanssonrafaeljw
authored andcommitted
PM: domains: Allocate gpd_timing_data dynamically based on governor
If a genpd doesn't have an associated governor assigned, there's really no point to allocate the per device gpd_timing_data, as the data isn't being used by a governor anyway. To avoid wasting memory, let's therefore convert the corresponding td variable in the struct generic_pm_domain_data into a pointer and manage the allocation of its data dynamically. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent bcc19f6 commit 66d29d8

3 files changed

Lines changed: 40 additions & 19 deletions

File tree

drivers/base/power/domain.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -773,13 +773,16 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
773773
for (;;) {
774774
struct generic_pm_domain *genpd;
775775
struct pm_domain_data *pdd;
776+
struct gpd_timing_data *td;
776777

777778
spin_lock_irq(&dev->power.lock);
778779

779780
pdd = dev->power.subsys_data ?
780781
dev->power.subsys_data->domain_data : NULL;
781782
if (pdd) {
782-
to_gpd_data(pdd)->td.constraint_changed = true;
783+
td = to_gpd_data(pdd)->td;
784+
if (td)
785+
td->constraint_changed = true;
783786
genpd = dev_to_genpd(dev);
784787
} else {
785788
genpd = ERR_PTR(-ENODATA);
@@ -875,7 +878,7 @@ static int genpd_runtime_suspend(struct device *dev)
875878
struct generic_pm_domain *genpd;
876879
bool (*suspend_ok)(struct device *__dev);
877880
struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
878-
struct gpd_timing_data *td = &gpd_data->td;
881+
struct gpd_timing_data *td = gpd_data->td;
879882
bool runtime_pm = pm_runtime_enabled(dev);
880883
ktime_t time_start;
881884
s64 elapsed_ns;
@@ -915,7 +918,7 @@ static int genpd_runtime_suspend(struct device *dev)
915918
/* Update suspend latency value if the measured time exceeds it. */
916919
if (runtime_pm) {
917920
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
918-
if (elapsed_ns > td->suspend_latency_ns) {
921+
if (td && (elapsed_ns > td->suspend_latency_ns)) {
919922
td->suspend_latency_ns = elapsed_ns;
920923
dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
921924
elapsed_ns);
@@ -951,7 +954,7 @@ static int genpd_runtime_resume(struct device *dev)
951954
{
952955
struct generic_pm_domain *genpd;
953956
struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
954-
struct gpd_timing_data *td = &gpd_data->td;
957+
struct gpd_timing_data *td = gpd_data->td;
955958
bool runtime_pm = pm_runtime_enabled(dev);
956959
ktime_t time_start;
957960
s64 elapsed_ns;
@@ -999,7 +1002,7 @@ static int genpd_runtime_resume(struct device *dev)
9991002
/* Update resume latency value if the measured time exceeds it. */
10001003
if (timed && runtime_pm) {
10011004
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
1002-
if (elapsed_ns > td->resume_latency_ns) {
1005+
if (td && (elapsed_ns > td->resume_latency_ns)) {
10031006
td->resume_latency_ns = elapsed_ns;
10041007
dev_dbg(dev, "resume latency exceeded, %lld ns\n",
10051008
elapsed_ns);
@@ -1496,9 +1499,11 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_resume);
14961499

14971500
#endif /* CONFIG_PM_SLEEP */
14981501

1499-
static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
1502+
static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
1503+
bool has_governor)
15001504
{
15011505
struct generic_pm_domain_data *gpd_data;
1506+
struct gpd_timing_data *td;
15021507
int ret;
15031508

15041509
ret = dev_pm_get_subsys_data(dev);
@@ -1512,26 +1517,38 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev)
15121517
}
15131518

15141519
gpd_data->base.dev = dev;
1515-
gpd_data->td.constraint_changed = true;
1516-
gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
15171520
gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
15181521
gpd_data->next_wakeup = KTIME_MAX;
15191522

1520-
spin_lock_irq(&dev->power.lock);
1523+
/* Allocate data used by a governor. */
1524+
if (has_governor) {
1525+
td = kzalloc(sizeof(*td), GFP_KERNEL);
1526+
if (!td) {
1527+
ret = -ENOMEM;
1528+
goto err_free;
1529+
}
15211530

1522-
if (dev->power.subsys_data->domain_data) {
1523-
ret = -EINVAL;
1524-
goto err_free;
1531+
td->constraint_changed = true;
1532+
td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
1533+
gpd_data->td = td;
15251534
}
15261535

1527-
dev->power.subsys_data->domain_data = &gpd_data->base;
1536+
spin_lock_irq(&dev->power.lock);
1537+
1538+
if (dev->power.subsys_data->domain_data)
1539+
ret = -EINVAL;
1540+
else
1541+
dev->power.subsys_data->domain_data = &gpd_data->base;
15281542

15291543
spin_unlock_irq(&dev->power.lock);
15301544

1545+
if (ret)
1546+
goto err_free;
1547+
15311548
return gpd_data;
15321549

15331550
err_free:
1534-
spin_unlock_irq(&dev->power.lock);
1551+
kfree(gpd_data->td);
15351552
kfree(gpd_data);
15361553
err_put:
15371554
dev_pm_put_subsys_data(dev);
@@ -1547,6 +1564,7 @@ static void genpd_free_dev_data(struct device *dev,
15471564

15481565
spin_unlock_irq(&dev->power.lock);
15491566

1567+
kfree(gpd_data->td);
15501568
kfree(gpd_data);
15511569
dev_pm_put_subsys_data(dev);
15521570
}
@@ -1611,7 +1629,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
16111629
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
16121630
return -EINVAL;
16131631

1614-
gpd_data = genpd_alloc_dev_data(dev);
1632+
gpd_data = genpd_alloc_dev_data(dev, genpd->gov);
16151633
if (IS_ERR(gpd_data))
16161634
return PTR_ERR(gpd_data);
16171635

drivers/base/power/domain_governor.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
1818
s64 constraint_ns;
1919

2020
if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
21+
struct gpd_timing_data *td = dev_gpd_data(dev)->td;
22+
2123
/*
2224
* Only take suspend-time QoS constraints of devices into
2325
* account, because constraints updated after the device has
2426
* been suspended are not guaranteed to be taken into account
2527
* anyway. In order for them to take effect, the device has to
2628
* be resumed and suspended again.
2729
*/
28-
constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
30+
constraint_ns = td ? td->effective_constraint_ns :
31+
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
2932
} else {
3033
/*
3134
* The child is not in a domain and there's no info on its
@@ -49,7 +52,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
4952
*/
5053
static bool default_suspend_ok(struct device *dev)
5154
{
52-
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
55+
struct gpd_timing_data *td = dev_gpd_data(dev)->td;
5356
unsigned long flags;
5457
s64 constraint_ns;
5558

@@ -215,7 +218,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
215218
* domain to turn off and on (that's how much time it will
216219
* have to wait worst case).
217220
*/
218-
td = &to_gpd_data(pdd)->td;
221+
td = to_gpd_data(pdd)->td;
219222
constraint_ns = td->effective_constraint_ns;
220223
/*
221224
* Zero means "no suspend at all" and this runs only when all

include/linux/pm_domain.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ struct pm_domain_data {
193193

194194
struct generic_pm_domain_data {
195195
struct pm_domain_data base;
196-
struct gpd_timing_data td;
196+
struct gpd_timing_data *td;
197197
struct notifier_block nb;
198198
struct notifier_block *power_nb;
199199
int cpu;

0 commit comments

Comments
 (0)