diff options
-rw-r--r-- | drivers/base/power/domain.c | 99 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 6 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 6 |
3 files changed, 55 insertions, 56 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a1c3ec4cc4fb..a7dfdf9f15ba 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -34,22 +34,6 @@ | |||
34 | __ret; \ | 34 | __ret; \ |
35 | }) | 35 | }) |
36 | 36 | ||
37 | #define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name) \ | ||
38 | ({ \ | ||
39 | ktime_t __start = ktime_get(); \ | ||
40 | type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \ | ||
41 | s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \ | ||
42 | struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \ | ||
43 | if (!__retval && __elapsed > __td->field) { \ | ||
44 | __td->field = __elapsed; \ | ||
45 | dev_dbg(dev, name " latency exceeded, new value %lld ns\n", \ | ||
46 | __elapsed); \ | ||
47 | genpd->max_off_time_changed = true; \ | ||
48 | __td->constraint_changed = true; \ | ||
49 | } \ | ||
50 | __retval; \ | ||
51 | }) | ||
52 | |||
53 | static LIST_HEAD(gpd_list); | 37 | static LIST_HEAD(gpd_list); |
54 | static DEFINE_MUTEX(gpd_list_lock); | 38 | static DEFINE_MUTEX(gpd_list_lock); |
55 | 39 | ||
@@ -90,24 +74,14 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev) | |||
90 | return pd_to_genpd(dev->pm_domain); | 74 | return pd_to_genpd(dev->pm_domain); |
91 | } | 75 | } |
92 | 76 | ||
93 | static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev, | 77 | static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev) |
94 | bool timed) | ||
95 | { | 78 | { |
96 | if (!timed) | 79 | return GENPD_DEV_CALLBACK(genpd, int, stop, dev); |
97 | return GENPD_DEV_CALLBACK(genpd, int, stop, dev); | ||
98 | |||
99 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev, | ||
100 | stop_latency_ns, "stop"); | ||
101 | } | 80 | } |
102 | 81 | ||
103 | static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev, | 82 | static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) |
104 | bool timed) | ||
105 | { | 83 | { |
106 | if (!timed) | 84 | return GENPD_DEV_CALLBACK(genpd, int, start, dev); |
107 | return GENPD_DEV_CALLBACK(genpd, int, start, dev); | ||
108 | |||
109 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev, | ||
110 | start_latency_ns, "start"); | ||
111 | } | 85 | } |
112 | 86 | ||
113 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) | 87 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) |
@@ -263,19 +237,13 @@ static int genpd_poweron(struct generic_pm_domain *genpd) | |||
263 | 237 | ||
264 | static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) | 238 | static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) |
265 | { | 239 | { |
266 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, | 240 | return GENPD_DEV_CALLBACK(genpd, int, save_state, dev); |
267 | save_state_latency_ns, "state save"); | ||
268 | } | 241 | } |
269 | 242 | ||
270 | static int genpd_restore_dev(struct generic_pm_domain *genpd, | 243 | static int genpd_restore_dev(struct generic_pm_domain *genpd, |
271 | struct device *dev, bool timed) | 244 | struct device *dev) |
272 | { | 245 | { |
273 | if (!timed) | 246 | return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev); |
274 | return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev); | ||
275 | |||
276 | return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev, | ||
277 | restore_state_latency_ns, | ||
278 | "state restore"); | ||
279 | } | 247 | } |
280 | 248 | ||
281 | static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, | 249 | static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, |
@@ -422,6 +390,9 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
422 | { | 390 | { |
423 | struct generic_pm_domain *genpd; | 391 | struct generic_pm_domain *genpd; |
424 | bool (*stop_ok)(struct device *__dev); | 392 | bool (*stop_ok)(struct device *__dev); |
393 | struct gpd_timing_data *td = &dev_gpd_data(dev)->td; | ||
394 | ktime_t time_start; | ||
395 | s64 elapsed_ns; | ||
425 | int ret; | 396 | int ret; |
426 | 397 | ||
427 | dev_dbg(dev, "%s()\n", __func__); | 398 | dev_dbg(dev, "%s()\n", __func__); |
@@ -434,16 +405,29 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
434 | if (stop_ok && !stop_ok(dev)) | 405 | if (stop_ok && !stop_ok(dev)) |
435 | return -EBUSY; | 406 | return -EBUSY; |
436 | 407 | ||
408 | /* Measure suspend latency. */ | ||
409 | time_start = ktime_get(); | ||
410 | |||
437 | ret = genpd_save_dev(genpd, dev); | 411 | ret = genpd_save_dev(genpd, dev); |
438 | if (ret) | 412 | if (ret) |
439 | return ret; | 413 | return ret; |
440 | 414 | ||
441 | ret = genpd_stop_dev(genpd, dev, true); | 415 | ret = genpd_stop_dev(genpd, dev); |
442 | if (ret) { | 416 | if (ret) { |
443 | genpd_restore_dev(genpd, dev, true); | 417 | genpd_restore_dev(genpd, dev); |
444 | return ret; | 418 | return ret; |
445 | } | 419 | } |
446 | 420 | ||
421 | /* Update suspend latency value if the measured time exceeds it. */ | ||
422 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
423 | if (elapsed_ns > td->suspend_latency_ns) { | ||
424 | td->suspend_latency_ns = elapsed_ns; | ||
425 | dev_dbg(dev, "suspend latency exceeded, %lld ns\n", | ||
426 | elapsed_ns); | ||
427 | genpd->max_off_time_changed = true; | ||
428 | td->constraint_changed = true; | ||
429 | } | ||
430 | |||
447 | /* | 431 | /* |
448 | * If power.irq_safe is set, this routine will be run with interrupts | 432 | * If power.irq_safe is set, this routine will be run with interrupts |
449 | * off, so it can't use mutexes. | 433 | * off, so it can't use mutexes. |
@@ -469,6 +453,9 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
469 | static int pm_genpd_runtime_resume(struct device *dev) | 453 | static int pm_genpd_runtime_resume(struct device *dev) |
470 | { | 454 | { |
471 | struct generic_pm_domain *genpd; | 455 | struct generic_pm_domain *genpd; |
456 | struct gpd_timing_data *td = &dev_gpd_data(dev)->td; | ||
457 | ktime_t time_start; | ||
458 | s64 elapsed_ns; | ||
472 | int ret; | 459 | int ret; |
473 | bool timed = true; | 460 | bool timed = true; |
474 | 461 | ||
@@ -492,8 +479,24 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
492 | return ret; | 479 | return ret; |
493 | 480 | ||
494 | out: | 481 | out: |
495 | genpd_start_dev(genpd, dev, timed); | 482 | /* Measure resume latency. */ |
496 | genpd_restore_dev(genpd, dev, timed); | 483 | if (timed) |
484 | time_start = ktime_get(); | ||
485 | |||
486 | genpd_start_dev(genpd, dev); | ||
487 | genpd_restore_dev(genpd, dev); | ||
488 | |||
489 | /* Update resume latency value if the measured time exceeds it. */ | ||
490 | if (timed) { | ||
491 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
492 | if (elapsed_ns > td->resume_latency_ns) { | ||
493 | td->resume_latency_ns = elapsed_ns; | ||
494 | dev_dbg(dev, "resume latency exceeded, %lld ns\n", | ||
495 | elapsed_ns); | ||
496 | genpd->max_off_time_changed = true; | ||
497 | td->constraint_changed = true; | ||
498 | } | ||
499 | } | ||
497 | 500 | ||
498 | return 0; | 501 | return 0; |
499 | } | 502 | } |
@@ -783,7 +786,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
783 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 786 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
784 | return 0; | 787 | return 0; |
785 | 788 | ||
786 | genpd_stop_dev(genpd, dev, false); | 789 | genpd_stop_dev(genpd, dev); |
787 | 790 | ||
788 | /* | 791 | /* |
789 | * Since all of the "noirq" callbacks are executed sequentially, it is | 792 | * Since all of the "noirq" callbacks are executed sequentially, it is |
@@ -824,7 +827,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
824 | pm_genpd_sync_poweron(genpd, true); | 827 | pm_genpd_sync_poweron(genpd, true); |
825 | genpd->suspended_count--; | 828 | genpd->suspended_count--; |
826 | 829 | ||
827 | return genpd_start_dev(genpd, dev, false); | 830 | return genpd_start_dev(genpd, dev); |
828 | } | 831 | } |
829 | 832 | ||
830 | /** | 833 | /** |
@@ -932,7 +935,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
932 | if (IS_ERR(genpd)) | 935 | if (IS_ERR(genpd)) |
933 | return -EINVAL; | 936 | return -EINVAL; |
934 | 937 | ||
935 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev, false); | 938 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); |
936 | } | 939 | } |
937 | 940 | ||
938 | /** | 941 | /** |
@@ -953,7 +956,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
953 | return -EINVAL; | 956 | return -EINVAL; |
954 | 957 | ||
955 | return genpd->suspend_power_off ? | 958 | return genpd->suspend_power_off ? |
956 | 0 : genpd_start_dev(genpd, dev, false); | 959 | 0 : genpd_start_dev(genpd, dev); |
957 | } | 960 | } |
958 | 961 | ||
959 | /** | 962 | /** |
@@ -1047,7 +1050,7 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1047 | 1050 | ||
1048 | pm_genpd_sync_poweron(genpd, true); | 1051 | pm_genpd_sync_poweron(genpd, true); |
1049 | 1052 | ||
1050 | return genpd_start_dev(genpd, dev, false); | 1053 | return genpd_start_dev(genpd, dev); |
1051 | } | 1054 | } |
1052 | 1055 | ||
1053 | /** | 1056 | /** |
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 85e17bacc834..e60dd12e23aa 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c | |||
@@ -77,10 +77,8 @@ static bool default_stop_ok(struct device *dev) | |||
77 | dev_update_qos_constraint); | 77 | dev_update_qos_constraint); |
78 | 78 | ||
79 | if (constraint_ns > 0) { | 79 | if (constraint_ns > 0) { |
80 | constraint_ns -= td->save_state_latency_ns + | 80 | constraint_ns -= td->suspend_latency_ns + |
81 | td->stop_latency_ns + | 81 | td->resume_latency_ns; |
82 | td->start_latency_ns + | ||
83 | td->restore_state_latency_ns; | ||
84 | if (constraint_ns == 0) | 82 | if (constraint_ns == 0) |
85 | return false; | 83 | return false; |
86 | } | 84 | } |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index f4dd8105b024..ba4ced38efae 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
@@ -81,10 +81,8 @@ struct gpd_link { | |||
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct gpd_timing_data { | 83 | struct gpd_timing_data { |
84 | s64 stop_latency_ns; | 84 | s64 suspend_latency_ns; |
85 | s64 start_latency_ns; | 85 | s64 resume_latency_ns; |
86 | s64 save_state_latency_ns; | ||
87 | s64 restore_state_latency_ns; | ||
88 | s64 effective_constraint_ns; | 86 | s64 effective_constraint_ns; |
89 | bool constraint_changed; | 87 | bool constraint_changed; |
90 | bool cached_stop_ok; | 88 | bool cached_stop_ok; |