aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/domain.c99
-rw-r--r--drivers/base/power/domain_governor.c6
-rw-r--r--include/linux/pm_domain.h6
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
53static LIST_HEAD(gpd_list); 37static LIST_HEAD(gpd_list);
54static DEFINE_MUTEX(gpd_list_lock); 38static 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
93static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev, 77static 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
103static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev, 82static 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
113static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) 87static 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
264static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) 238static 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
270static int genpd_restore_dev(struct generic_pm_domain *genpd, 243static 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
281static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, 249static 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)
469static int pm_genpd_runtime_resume(struct device *dev) 453static 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
83struct gpd_timing_data { 83struct 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;