aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/domain.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/domain.c')
-rw-r--r--drivers/base/power/domain.c113
1 files changed, 70 insertions, 43 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index fb83d4acd400..5d7b7548873a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -12,6 +12,7 @@
12#include <linux/pm_runtime.h> 12#include <linux/pm_runtime.h>
13#include <linux/pm_domain.h> 13#include <linux/pm_domain.h>
14#include <linux/pm_qos.h> 14#include <linux/pm_qos.h>
15#include <linux/pm_clock.h>
15#include <linux/slab.h> 16#include <linux/slab.h>
16#include <linux/err.h> 17#include <linux/err.h>
17#include <linux/sched.h> 18#include <linux/sched.h>
@@ -151,6 +152,59 @@ static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
151 genpd->cpuidle_data->idle_state->exit_latency = usecs64; 152 genpd->cpuidle_data->idle_state->exit_latency = usecs64;
152} 153}
153 154
155static int genpd_power_on(struct generic_pm_domain *genpd)
156{
157 ktime_t time_start;
158 s64 elapsed_ns;
159 int ret;
160
161 if (!genpd->power_on)
162 return 0;
163
164 time_start = ktime_get();
165 ret = genpd->power_on(genpd);
166 if (ret)
167 return ret;
168
169 elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
170 if (elapsed_ns <= genpd->power_on_latency_ns)
171 return ret;
172
173 genpd->power_on_latency_ns = elapsed_ns;
174 genpd->max_off_time_changed = true;
175 genpd_recalc_cpu_exit_latency(genpd);
176 pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
177 genpd->name, "on", elapsed_ns);
178
179 return ret;
180}
181
182static int genpd_power_off(struct generic_pm_domain *genpd)
183{
184 ktime_t time_start;
185 s64 elapsed_ns;
186 int ret;
187
188 if (!genpd->power_off)
189 return 0;
190
191 time_start = ktime_get();
192 ret = genpd->power_off(genpd);
193 if (ret == -EBUSY)
194 return ret;
195
196 elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
197 if (elapsed_ns <= genpd->power_off_latency_ns)
198 return ret;
199
200 genpd->power_off_latency_ns = elapsed_ns;
201 genpd->max_off_time_changed = true;
202 pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
203 genpd->name, "off", elapsed_ns);
204
205 return ret;
206}
207
154/** 208/**
155 * __pm_genpd_poweron - Restore power to a given PM domain and its masters. 209 * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
156 * @genpd: PM domain to power up. 210 * @genpd: PM domain to power up.
@@ -222,25 +276,9 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
222 } 276 }
223 } 277 }
224 278
225 if (genpd->power_on) { 279 ret = genpd_power_on(genpd);
226 ktime_t time_start = ktime_get(); 280 if (ret)
227 s64 elapsed_ns; 281 goto err;
228
229 ret = genpd->power_on(genpd);
230 if (ret)
231 goto err;
232
233 elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
234 if (elapsed_ns > genpd->power_on_latency_ns) {
235 genpd->power_on_latency_ns = elapsed_ns;
236 genpd->max_off_time_changed = true;
237 genpd_recalc_cpu_exit_latency(genpd);
238 if (genpd->name)
239 pr_warning("%s: Power-on latency exceeded, "
240 "new value %lld ns\n", genpd->name,
241 elapsed_ns);
242 }
243 }
244 282
245 out: 283 out:
246 genpd_set_active(genpd); 284 genpd_set_active(genpd);
@@ -544,16 +582,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
544 } 582 }
545 583
546 if (genpd->power_off) { 584 if (genpd->power_off) {
547 ktime_t time_start;
548 s64 elapsed_ns;
549
550 if (atomic_read(&genpd->sd_count) > 0) { 585 if (atomic_read(&genpd->sd_count) > 0) {
551 ret = -EBUSY; 586 ret = -EBUSY;
552 goto out; 587 goto out;
553 } 588 }
554 589
555 time_start = ktime_get();
556
557 /* 590 /*
558 * If sd_count > 0 at this point, one of the subdomains hasn't 591 * If sd_count > 0 at this point, one of the subdomains hasn't
559 * managed to call pm_genpd_poweron() for the master yet after 592 * managed to call pm_genpd_poweron() for the master yet after
@@ -562,21 +595,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
562 * the pm_genpd_poweron() restore power for us (this shouldn't 595 * the pm_genpd_poweron() restore power for us (this shouldn't
563 * happen very often). 596 * happen very often).
564 */ 597 */
565 ret = genpd->power_off(genpd); 598 ret = genpd_power_off(genpd);
566 if (ret == -EBUSY) { 599 if (ret == -EBUSY) {
567 genpd_set_active(genpd); 600 genpd_set_active(genpd);
568 goto out; 601 goto out;
569 } 602 }
570
571 elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
572 if (elapsed_ns > genpd->power_off_latency_ns) {
573 genpd->power_off_latency_ns = elapsed_ns;
574 genpd->max_off_time_changed = true;
575 if (genpd->name)
576 pr_warning("%s: Power-off latency exceeded, "
577 "new value %lld ns\n", genpd->name,
578 elapsed_ns);
579 }
580 } 603 }
581 604
582 genpd->status = GPD_STATE_POWER_OFF; 605 genpd->status = GPD_STATE_POWER_OFF;
@@ -779,9 +802,9 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {}
779 * pm_genpd_present - Check if the given PM domain has been initialized. 802 * pm_genpd_present - Check if the given PM domain has been initialized.
780 * @genpd: PM domain to check. 803 * @genpd: PM domain to check.
781 */ 804 */
782static bool pm_genpd_present(struct generic_pm_domain *genpd) 805static bool pm_genpd_present(const struct generic_pm_domain *genpd)
783{ 806{
784 struct generic_pm_domain *gpd; 807 const struct generic_pm_domain *gpd;
785 808
786 if (IS_ERR_OR_NULL(genpd)) 809 if (IS_ERR_OR_NULL(genpd))
787 return false; 810 return false;
@@ -822,8 +845,7 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
822 || atomic_read(&genpd->sd_count) > 0) 845 || atomic_read(&genpd->sd_count) > 0)
823 return; 846 return;
824 847
825 if (genpd->power_off) 848 genpd_power_off(genpd);
826 genpd->power_off(genpd);
827 849
828 genpd->status = GPD_STATE_POWER_OFF; 850 genpd->status = GPD_STATE_POWER_OFF;
829 851
@@ -854,8 +876,7 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
854 genpd_sd_counter_inc(link->master); 876 genpd_sd_counter_inc(link->master);
855 } 877 }
856 878
857 if (genpd->power_on) 879 genpd_power_on(genpd);
858 genpd->power_on(genpd);
859 880
860 genpd->status = GPD_STATE_ACTIVE; 881 genpd->status = GPD_STATE_ACTIVE;
861} 882}
@@ -1277,8 +1298,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
1277 * If the domain was off before the hibernation, make 1298 * If the domain was off before the hibernation, make
1278 * sure it will be off going forward. 1299 * sure it will be off going forward.
1279 */ 1300 */
1280 if (genpd->power_off) 1301 genpd_power_off(genpd);
1281 genpd->power_off(genpd);
1282 1302
1283 return 0; 1303 return 0;
1284 } 1304 }
@@ -1929,6 +1949,12 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
1929 genpd->domain.ops.complete = pm_genpd_complete; 1949 genpd->domain.ops.complete = pm_genpd_complete;
1930 genpd->dev_ops.save_state = pm_genpd_default_save_state; 1950 genpd->dev_ops.save_state = pm_genpd_default_save_state;
1931 genpd->dev_ops.restore_state = pm_genpd_default_restore_state; 1951 genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
1952
1953 if (genpd->flags & GENPD_FLAG_PM_CLK) {
1954 genpd->dev_ops.stop = pm_clk_suspend;
1955 genpd->dev_ops.start = pm_clk_resume;
1956 }
1957
1932 mutex_lock(&gpd_list_lock); 1958 mutex_lock(&gpd_list_lock);
1933 list_add(&genpd->gpd_list_node, &gpd_list); 1959 list_add(&genpd->gpd_list_node, &gpd_list);
1934 mutex_unlock(&gpd_list_lock); 1960 mutex_unlock(&gpd_list_lock);
@@ -2216,6 +2242,7 @@ int genpd_dev_pm_attach(struct device *dev)
2216 } 2242 }
2217 2243
2218 dev->pm_domain->detach = genpd_dev_pm_detach; 2244 dev->pm_domain->detach = genpd_dev_pm_detach;
2245 pm_genpd_poweron(pd);
2219 2246
2220 return 0; 2247 return 0;
2221} 2248}