diff options
| -rw-r--r-- | arch/arm/mach-imx/gpc.c | 9 | ||||
| -rw-r--r-- | drivers/base/power/domain.c | 60 | ||||
| -rw-r--r-- | drivers/base/power/domain_governor.c | 64 | ||||
| -rw-r--r-- | drivers/base/power/trace.c | 4 | ||||
| -rw-r--r-- | drivers/cpuidle/governors/menu.c | 47 | ||||
| -rw-r--r-- | include/linux/pm_domain.h | 13 | ||||
| -rw-r--r-- | kernel/power/process.c | 12 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 6 |
8 files changed, 143 insertions, 72 deletions
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index cfc696b972f3..fd8720532471 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c | |||
| @@ -374,8 +374,13 @@ static struct pu_domain imx6q_pu_domain = { | |||
| 374 | .name = "PU", | 374 | .name = "PU", |
| 375 | .power_off = imx6q_pm_pu_power_off, | 375 | .power_off = imx6q_pm_pu_power_off, |
| 376 | .power_on = imx6q_pm_pu_power_on, | 376 | .power_on = imx6q_pm_pu_power_on, |
| 377 | .power_off_latency_ns = 25000, | 377 | .states = { |
| 378 | .power_on_latency_ns = 2000000, | 378 | [0] = { |
| 379 | .power_off_latency_ns = 25000, | ||
| 380 | .power_on_latency_ns = 2000000, | ||
| 381 | }, | ||
| 382 | }, | ||
| 383 | .state_count = 1, | ||
| 379 | }, | 384 | }, |
| 380 | }; | 385 | }; |
| 381 | 386 | ||
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 301b785f9f56..56705b52758e 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
| @@ -104,6 +104,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) | |||
| 104 | 104 | ||
| 105 | static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) | 105 | static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) |
| 106 | { | 106 | { |
| 107 | unsigned int state_idx = genpd->state_idx; | ||
| 107 | ktime_t time_start; | 108 | ktime_t time_start; |
| 108 | s64 elapsed_ns; | 109 | s64 elapsed_ns; |
| 109 | int ret; | 110 | int ret; |
| @@ -120,10 +121,10 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) | |||
| 120 | return ret; | 121 | return ret; |
| 121 | 122 | ||
| 122 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | 123 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); |
| 123 | if (elapsed_ns <= genpd->power_on_latency_ns) | 124 | if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns) |
| 124 | return ret; | 125 | return ret; |
| 125 | 126 | ||
| 126 | genpd->power_on_latency_ns = elapsed_ns; | 127 | genpd->states[state_idx].power_on_latency_ns = elapsed_ns; |
| 127 | genpd->max_off_time_changed = true; | 128 | genpd->max_off_time_changed = true; |
| 128 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", | 129 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
| 129 | genpd->name, "on", elapsed_ns); | 130 | genpd->name, "on", elapsed_ns); |
| @@ -133,6 +134,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) | |||
| 133 | 134 | ||
| 134 | static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) | 135 | static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) |
| 135 | { | 136 | { |
| 137 | unsigned int state_idx = genpd->state_idx; | ||
| 136 | ktime_t time_start; | 138 | ktime_t time_start; |
| 137 | s64 elapsed_ns; | 139 | s64 elapsed_ns; |
| 138 | int ret; | 140 | int ret; |
| @@ -149,10 +151,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) | |||
| 149 | return ret; | 151 | return ret; |
| 150 | 152 | ||
| 151 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | 153 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); |
| 152 | if (elapsed_ns <= genpd->power_off_latency_ns) | 154 | if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns) |
| 153 | return ret; | 155 | return ret; |
| 154 | 156 | ||
| 155 | genpd->power_off_latency_ns = elapsed_ns; | 157 | genpd->states[state_idx].power_off_latency_ns = elapsed_ns; |
| 156 | genpd->max_off_time_changed = true; | 158 | genpd->max_off_time_changed = true; |
| 157 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", | 159 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
| 158 | genpd->name, "off", elapsed_ns); | 160 | genpd->name, "off", elapsed_ns); |
| @@ -485,8 +487,13 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
| 485 | if (timed && runtime_pm) | 487 | if (timed && runtime_pm) |
| 486 | time_start = ktime_get(); | 488 | time_start = ktime_get(); |
| 487 | 489 | ||
| 488 | genpd_start_dev(genpd, dev); | 490 | ret = genpd_start_dev(genpd, dev); |
| 489 | genpd_restore_dev(genpd, dev); | 491 | if (ret) |
| 492 | goto err_poweroff; | ||
| 493 | |||
| 494 | ret = genpd_restore_dev(genpd, dev); | ||
| 495 | if (ret) | ||
| 496 | goto err_stop; | ||
| 490 | 497 | ||
| 491 | /* Update resume latency value if the measured time exceeds it. */ | 498 | /* Update resume latency value if the measured time exceeds it. */ |
| 492 | if (timed && runtime_pm) { | 499 | if (timed && runtime_pm) { |
| @@ -501,6 +508,17 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
| 501 | } | 508 | } |
| 502 | 509 | ||
| 503 | return 0; | 510 | return 0; |
| 511 | |||
| 512 | err_stop: | ||
| 513 | genpd_stop_dev(genpd, dev); | ||
| 514 | err_poweroff: | ||
| 515 | if (!dev->power.irq_safe) { | ||
| 516 | mutex_lock(&genpd->lock); | ||
| 517 | genpd_poweroff(genpd, 0); | ||
| 518 | mutex_unlock(&genpd->lock); | ||
| 519 | } | ||
| 520 | |||
| 521 | return ret; | ||
| 504 | } | 522 | } |
| 505 | 523 | ||
| 506 | static bool pd_ignore_unused; | 524 | static bool pd_ignore_unused; |
| @@ -585,6 +603,8 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd, | |||
| 585 | || atomic_read(&genpd->sd_count) > 0) | 603 | || atomic_read(&genpd->sd_count) > 0) |
| 586 | return; | 604 | return; |
| 587 | 605 | ||
| 606 | /* Choose the deepest state when suspending */ | ||
| 607 | genpd->state_idx = genpd->state_count - 1; | ||
| 588 | genpd_power_off(genpd, timed); | 608 | genpd_power_off(genpd, timed); |
| 589 | 609 | ||
| 590 | genpd->status = GPD_STATE_POWER_OFF; | 610 | genpd->status = GPD_STATE_POWER_OFF; |
| @@ -1378,7 +1398,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | |||
| 1378 | mutex_lock(&subdomain->lock); | 1398 | mutex_lock(&subdomain->lock); |
| 1379 | mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); | 1399 | mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); |
| 1380 | 1400 | ||
| 1381 | if (!list_empty(&subdomain->slave_links) || subdomain->device_count) { | 1401 | if (!list_empty(&subdomain->master_links) || subdomain->device_count) { |
| 1382 | pr_warn("%s: unable to remove subdomain %s\n", genpd->name, | 1402 | pr_warn("%s: unable to remove subdomain %s\n", genpd->name, |
| 1383 | subdomain->name); | 1403 | subdomain->name); |
| 1384 | ret = -EBUSY; | 1404 | ret = -EBUSY; |
| @@ -1508,6 +1528,20 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
| 1508 | genpd->dev_ops.start = pm_clk_resume; | 1528 | genpd->dev_ops.start = pm_clk_resume; |
| 1509 | } | 1529 | } |
| 1510 | 1530 | ||
| 1531 | if (genpd->state_idx >= GENPD_MAX_NUM_STATES) { | ||
| 1532 | pr_warn("Initial state index out of bounds.\n"); | ||
| 1533 | genpd->state_idx = GENPD_MAX_NUM_STATES - 1; | ||
| 1534 | } | ||
| 1535 | |||
| 1536 | if (genpd->state_count > GENPD_MAX_NUM_STATES) { | ||
| 1537 | pr_warn("Limiting states to %d\n", GENPD_MAX_NUM_STATES); | ||
| 1538 | genpd->state_count = GENPD_MAX_NUM_STATES; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /* Use only one "off" state if there were no states declared */ | ||
| 1542 | if (genpd->state_count == 0) | ||
| 1543 | genpd->state_count = 1; | ||
| 1544 | |||
| 1511 | mutex_lock(&gpd_list_lock); | 1545 | mutex_lock(&gpd_list_lock); |
| 1512 | list_add(&genpd->gpd_list_node, &gpd_list); | 1546 | list_add(&genpd->gpd_list_node, &gpd_list); |
| 1513 | mutex_unlock(&gpd_list_lock); | 1547 | mutex_unlock(&gpd_list_lock); |
| @@ -1668,6 +1702,9 @@ struct generic_pm_domain *of_genpd_get_from_provider( | |||
| 1668 | struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); | 1702 | struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); |
| 1669 | struct of_genpd_provider *provider; | 1703 | struct of_genpd_provider *provider; |
| 1670 | 1704 | ||
| 1705 | if (!genpdspec) | ||
| 1706 | return ERR_PTR(-EINVAL); | ||
| 1707 | |||
| 1671 | mutex_lock(&of_genpd_mutex); | 1708 | mutex_lock(&of_genpd_mutex); |
| 1672 | 1709 | ||
| 1673 | /* Check if we have such a provider in our array */ | 1710 | /* Check if we have such a provider in our array */ |
| @@ -1864,6 +1901,7 @@ static int pm_genpd_summary_one(struct seq_file *s, | |||
| 1864 | struct pm_domain_data *pm_data; | 1901 | struct pm_domain_data *pm_data; |
| 1865 | const char *kobj_path; | 1902 | const char *kobj_path; |
| 1866 | struct gpd_link *link; | 1903 | struct gpd_link *link; |
| 1904 | char state[16]; | ||
| 1867 | int ret; | 1905 | int ret; |
| 1868 | 1906 | ||
| 1869 | ret = mutex_lock_interruptible(&genpd->lock); | 1907 | ret = mutex_lock_interruptible(&genpd->lock); |
| @@ -1872,7 +1910,13 @@ static int pm_genpd_summary_one(struct seq_file *s, | |||
| 1872 | 1910 | ||
| 1873 | if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) | 1911 | if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) |
| 1874 | goto exit; | 1912 | goto exit; |
| 1875 | seq_printf(s, "%-30s %-15s ", genpd->name, status_lookup[genpd->status]); | 1913 | if (genpd->status == GPD_STATE_POWER_OFF) |
| 1914 | snprintf(state, sizeof(state), "%s-%u", | ||
| 1915 | status_lookup[genpd->status], genpd->state_idx); | ||
| 1916 | else | ||
| 1917 | snprintf(state, sizeof(state), "%s", | ||
| 1918 | status_lookup[genpd->status]); | ||
| 1919 | seq_printf(s, "%-30s %-15s ", genpd->name, state); | ||
| 1876 | 1920 | ||
| 1877 | /* | 1921 | /* |
| 1878 | * Modifications on the list require holding locks on both | 1922 | * Modifications on the list require holding locks on both |
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 1e937ac5f456..00a5436dd44b 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c | |||
| @@ -98,7 +98,8 @@ static bool default_stop_ok(struct device *dev) | |||
| 98 | * | 98 | * |
| 99 | * This routine must be executed under the PM domain's lock. | 99 | * This routine must be executed under the PM domain's lock. |
| 100 | */ | 100 | */ |
| 101 | static bool default_power_down_ok(struct dev_pm_domain *pd) | 101 | static bool __default_power_down_ok(struct dev_pm_domain *pd, |
| 102 | unsigned int state) | ||
| 102 | { | 103 | { |
| 103 | struct generic_pm_domain *genpd = pd_to_genpd(pd); | 104 | struct generic_pm_domain *genpd = pd_to_genpd(pd); |
| 104 | struct gpd_link *link; | 105 | struct gpd_link *link; |
| @@ -106,27 +107,9 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) | |||
| 106 | s64 min_off_time_ns; | 107 | s64 min_off_time_ns; |
| 107 | s64 off_on_time_ns; | 108 | s64 off_on_time_ns; |
| 108 | 109 | ||
| 109 | if (genpd->max_off_time_changed) { | 110 | off_on_time_ns = genpd->states[state].power_off_latency_ns + |
| 110 | struct gpd_link *link; | 111 | genpd->states[state].power_on_latency_ns; |
| 111 | |||
| 112 | /* | ||
| 113 | * We have to invalidate the cached results for the masters, so | ||
| 114 | * use the observation that default_power_down_ok() is not | ||
| 115 | * going to be called for any master until this instance | ||
| 116 | * returns. | ||
| 117 | */ | ||
| 118 | list_for_each_entry(link, &genpd->slave_links, slave_node) | ||
| 119 | link->master->max_off_time_changed = true; | ||
| 120 | |||
| 121 | genpd->max_off_time_changed = false; | ||
| 122 | genpd->cached_power_down_ok = false; | ||
| 123 | genpd->max_off_time_ns = -1; | ||
| 124 | } else { | ||
| 125 | return genpd->cached_power_down_ok; | ||
| 126 | } | ||
| 127 | 112 | ||
| 128 | off_on_time_ns = genpd->power_off_latency_ns + | ||
| 129 | genpd->power_on_latency_ns; | ||
| 130 | 113 | ||
| 131 | min_off_time_ns = -1; | 114 | min_off_time_ns = -1; |
| 132 | /* | 115 | /* |
| @@ -186,8 +169,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) | |||
| 186 | min_off_time_ns = constraint_ns; | 169 | min_off_time_ns = constraint_ns; |
| 187 | } | 170 | } |
| 188 | 171 | ||
| 189 | genpd->cached_power_down_ok = true; | ||
| 190 | |||
| 191 | /* | 172 | /* |
| 192 | * If the computed minimum device off time is negative, there are no | 173 | * If the computed minimum device off time is negative, there are no |
| 193 | * latency constraints, so the domain can spend arbitrary time in the | 174 | * latency constraints, so the domain can spend arbitrary time in the |
| @@ -201,10 +182,45 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) | |||
| 201 | * time and the time needed to turn the domain on is the maximum | 182 | * time and the time needed to turn the domain on is the maximum |
| 202 | * theoretical time this domain can spend in the "off" state. | 183 | * theoretical time this domain can spend in the "off" state. |
| 203 | */ | 184 | */ |
| 204 | genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns; | 185 | genpd->max_off_time_ns = min_off_time_ns - |
| 186 | genpd->states[state].power_on_latency_ns; | ||
| 205 | return true; | 187 | return true; |
| 206 | } | 188 | } |
| 207 | 189 | ||
| 190 | static bool default_power_down_ok(struct dev_pm_domain *pd) | ||
| 191 | { | ||
| 192 | struct generic_pm_domain *genpd = pd_to_genpd(pd); | ||
| 193 | struct gpd_link *link; | ||
| 194 | |||
| 195 | if (!genpd->max_off_time_changed) | ||
| 196 | return genpd->cached_power_down_ok; | ||
| 197 | |||
| 198 | /* | ||
| 199 | * We have to invalidate the cached results for the masters, so | ||
| 200 | * use the observation that default_power_down_ok() is not | ||
| 201 | * going to be called for any master until this instance | ||
| 202 | * returns. | ||
| 203 | */ | ||
| 204 | list_for_each_entry(link, &genpd->slave_links, slave_node) | ||
| 205 | link->master->max_off_time_changed = true; | ||
| 206 | |||
| 207 | genpd->max_off_time_ns = -1; | ||
| 208 | genpd->max_off_time_changed = false; | ||
| 209 | genpd->cached_power_down_ok = true; | ||
| 210 | genpd->state_idx = genpd->state_count - 1; | ||
| 211 | |||
| 212 | /* Find a state to power down to, starting from the deepest. */ | ||
| 213 | while (!__default_power_down_ok(pd, genpd->state_idx)) { | ||
| 214 | if (genpd->state_idx == 0) { | ||
| 215 | genpd->cached_power_down_ok = false; | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | genpd->state_idx--; | ||
| 219 | } | ||
| 220 | |||
| 221 | return genpd->cached_power_down_ok; | ||
| 222 | } | ||
| 223 | |||
| 208 | static bool always_on_power_down_ok(struct dev_pm_domain *domain) | 224 | static bool always_on_power_down_ok(struct dev_pm_domain *domain) |
| 209 | { | 225 | { |
| 210 | return false; | 226 | return false; |
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index a311cfa4c5bd..a6975795e7f3 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c | |||
| @@ -166,14 +166,14 @@ void generate_pm_trace(const void *tracedata, unsigned int user) | |||
| 166 | } | 166 | } |
| 167 | EXPORT_SYMBOL(generate_pm_trace); | 167 | EXPORT_SYMBOL(generate_pm_trace); |
| 168 | 168 | ||
| 169 | extern char __tracedata_start, __tracedata_end; | 169 | extern char __tracedata_start[], __tracedata_end[]; |
| 170 | static int show_file_hash(unsigned int value) | 170 | static int show_file_hash(unsigned int value) |
| 171 | { | 171 | { |
| 172 | int match; | 172 | int match; |
| 173 | char *tracedata; | 173 | char *tracedata; |
| 174 | 174 | ||
| 175 | match = 0; | 175 | match = 0; |
| 176 | for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; | 176 | for (tracedata = __tracedata_start ; tracedata < __tracedata_end ; |
| 177 | tracedata += 2 + sizeof(unsigned long)) { | 177 | tracedata += 2 + sizeof(unsigned long)) { |
| 178 | unsigned short lineno = *(unsigned short *)tracedata; | 178 | unsigned short lineno = *(unsigned short *)tracedata; |
| 179 | const char *file = *(const char **)(tracedata + 2); | 179 | const char *file = *(const char **)(tracedata + 2); |
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 0742b3296673..27fc733cb5b9 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c | |||
| @@ -199,8 +199,8 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); | |||
| 199 | static void get_typical_interval(struct menu_device *data) | 199 | static void get_typical_interval(struct menu_device *data) |
| 200 | { | 200 | { |
| 201 | int i, divisor; | 201 | int i, divisor; |
| 202 | unsigned int max, thresh; | 202 | unsigned int max, thresh, avg; |
| 203 | uint64_t avg, stddev; | 203 | uint64_t sum, variance; |
| 204 | 204 | ||
| 205 | thresh = UINT_MAX; /* Discard outliers above this value */ | 205 | thresh = UINT_MAX; /* Discard outliers above this value */ |
| 206 | 206 | ||
| @@ -208,52 +208,51 @@ again: | |||
| 208 | 208 | ||
| 209 | /* First calculate the average of past intervals */ | 209 | /* First calculate the average of past intervals */ |
| 210 | max = 0; | 210 | max = 0; |
| 211 | avg = 0; | 211 | sum = 0; |
| 212 | divisor = 0; | 212 | divisor = 0; |
| 213 | for (i = 0; i < INTERVALS; i++) { | 213 | for (i = 0; i < INTERVALS; i++) { |
| 214 | unsigned int value = data->intervals[i]; | 214 | unsigned int value = data->intervals[i]; |
| 215 | if (value <= thresh) { | 215 | if (value <= thresh) { |
| 216 | avg += value; | 216 | sum += value; |
| 217 | divisor++; | 217 | divisor++; |
| 218 | if (value > max) | 218 | if (value > max) |
| 219 | max = value; | 219 | max = value; |
| 220 | } | 220 | } |
| 221 | } | 221 | } |
| 222 | if (divisor == INTERVALS) | 222 | if (divisor == INTERVALS) |
| 223 | avg >>= INTERVAL_SHIFT; | 223 | avg = sum >> INTERVAL_SHIFT; |
| 224 | else | 224 | else |
| 225 | do_div(avg, divisor); | 225 | avg = div_u64(sum, divisor); |
| 226 | 226 | ||
| 227 | /* Then try to determine standard deviation */ | 227 | /* Then try to determine variance */ |
| 228 | stddev = 0; | 228 | variance = 0; |
| 229 | for (i = 0; i < INTERVALS; i++) { | 229 | for (i = 0; i < INTERVALS; i++) { |
| 230 | unsigned int value = data->intervals[i]; | 230 | unsigned int value = data->intervals[i]; |
| 231 | if (value <= thresh) { | 231 | if (value <= thresh) { |
| 232 | int64_t diff = value - avg; | 232 | int64_t diff = (int64_t)value - avg; |
| 233 | stddev += diff * diff; | 233 | variance += diff * diff; |
| 234 | } | 234 | } |
| 235 | } | 235 | } |
| 236 | if (divisor == INTERVALS) | 236 | if (divisor == INTERVALS) |
| 237 | stddev >>= INTERVAL_SHIFT; | 237 | variance >>= INTERVAL_SHIFT; |
| 238 | else | 238 | else |
| 239 | do_div(stddev, divisor); | 239 | do_div(variance, divisor); |
| 240 | 240 | ||
| 241 | /* | 241 | /* |
| 242 | * The typical interval is obtained when standard deviation is small | 242 | * The typical interval is obtained when standard deviation is |
| 243 | * or standard deviation is small compared to the average interval. | 243 | * small (stddev <= 20 us, variance <= 400 us^2) or standard |
| 244 | * | 244 | * deviation is small compared to the average interval (avg > |
| 245 | * int_sqrt() formal parameter type is unsigned long. When the | 245 | * 6*stddev, avg^2 > 36*variance). The average is smaller than |
| 246 | * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor) | 246 | * UINT_MAX aka U32_MAX, so computing its square does not |
| 247 | * the resulting squared standard deviation exceeds the input domain | 247 | * overflow a u64. We simply reject this candidate average if |
| 248 | * of int_sqrt on platforms where unsigned long is 32 bits in size. | 248 | * the standard deviation is greater than 715 s (which is |
| 249 | * In such case reject the candidate average. | 249 | * rather unlikely). |
| 250 | * | 250 | * |
| 251 | * Use this result only if there is no timer to wake us up sooner. | 251 | * Use this result only if there is no timer to wake us up sooner. |
| 252 | */ | 252 | */ |
| 253 | if (likely(stddev <= ULONG_MAX)) { | 253 | if (likely(variance <= U64_MAX/36)) { |
| 254 | stddev = int_sqrt(stddev); | 254 | if ((((u64)avg*avg > variance*36) && (divisor * 4 >= INTERVALS * 3)) |
| 255 | if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) | 255 | || variance <= 400) { |
| 256 | || stddev <= 20) { | ||
| 257 | if (data->next_timer_us > avg) | 256 | if (data->next_timer_us > avg) |
| 258 | data->predicted_us = avg; | 257 | data->predicted_us = avg; |
| 259 | return; | 258 | return; |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index db21d3995f7e..49cd8890b873 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | /* Defines used for the flags field in the struct generic_pm_domain */ | 19 | /* Defines used for the flags field in the struct generic_pm_domain */ |
| 20 | #define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */ | 20 | #define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */ |
| 21 | 21 | ||
| 22 | #define GENPD_MAX_NUM_STATES 8 /* Number of possible low power states */ | ||
| 23 | |||
| 22 | enum gpd_status { | 24 | enum gpd_status { |
| 23 | GPD_STATE_ACTIVE = 0, /* PM domain is active */ | 25 | GPD_STATE_ACTIVE = 0, /* PM domain is active */ |
| 24 | GPD_STATE_POWER_OFF, /* PM domain is off */ | 26 | GPD_STATE_POWER_OFF, /* PM domain is off */ |
| @@ -37,6 +39,11 @@ struct gpd_dev_ops { | |||
| 37 | bool (*active_wakeup)(struct device *dev); | 39 | bool (*active_wakeup)(struct device *dev); |
| 38 | }; | 40 | }; |
| 39 | 41 | ||
| 42 | struct genpd_power_state { | ||
| 43 | s64 power_off_latency_ns; | ||
| 44 | s64 power_on_latency_ns; | ||
| 45 | }; | ||
| 46 | |||
| 40 | struct generic_pm_domain { | 47 | struct generic_pm_domain { |
| 41 | struct dev_pm_domain domain; /* PM domain operations */ | 48 | struct dev_pm_domain domain; /* PM domain operations */ |
| 42 | struct list_head gpd_list_node; /* Node in the global PM domains list */ | 49 | struct list_head gpd_list_node; /* Node in the global PM domains list */ |
| @@ -54,9 +61,7 @@ struct generic_pm_domain { | |||
| 54 | unsigned int prepared_count; /* Suspend counter of prepared devices */ | 61 | unsigned int prepared_count; /* Suspend counter of prepared devices */ |
| 55 | bool suspend_power_off; /* Power status before system suspend */ | 62 | bool suspend_power_off; /* Power status before system suspend */ |
| 56 | int (*power_off)(struct generic_pm_domain *domain); | 63 | int (*power_off)(struct generic_pm_domain *domain); |
| 57 | s64 power_off_latency_ns; | ||
| 58 | int (*power_on)(struct generic_pm_domain *domain); | 64 | int (*power_on)(struct generic_pm_domain *domain); |
| 59 | s64 power_on_latency_ns; | ||
| 60 | struct gpd_dev_ops dev_ops; | 65 | struct gpd_dev_ops dev_ops; |
| 61 | s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ | 66 | s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ |
| 62 | bool max_off_time_changed; | 67 | bool max_off_time_changed; |
| @@ -66,6 +71,10 @@ struct generic_pm_domain { | |||
| 66 | void (*detach_dev)(struct generic_pm_domain *domain, | 71 | void (*detach_dev)(struct generic_pm_domain *domain, |
| 67 | struct device *dev); | 72 | struct device *dev); |
| 68 | unsigned int flags; /* Bit field of configs for genpd */ | 73 | unsigned int flags; /* Bit field of configs for genpd */ |
| 74 | struct genpd_power_state states[GENPD_MAX_NUM_STATES]; | ||
| 75 | unsigned int state_count; /* number of states */ | ||
| 76 | unsigned int state_idx; /* state that genpd will go to when off */ | ||
| 77 | |||
| 69 | }; | 78 | }; |
| 70 | 79 | ||
| 71 | static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) | 80 | static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 564f786df470..df058bed53ce 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
| @@ -30,13 +30,12 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 30 | unsigned long end_time; | 30 | unsigned long end_time; |
| 31 | unsigned int todo; | 31 | unsigned int todo; |
| 32 | bool wq_busy = false; | 32 | bool wq_busy = false; |
| 33 | struct timeval start, end; | 33 | ktime_t start, end, elapsed; |
| 34 | u64 elapsed_msecs64; | ||
| 35 | unsigned int elapsed_msecs; | 34 | unsigned int elapsed_msecs; |
| 36 | bool wakeup = false; | 35 | bool wakeup = false; |
| 37 | int sleep_usecs = USEC_PER_MSEC; | 36 | int sleep_usecs = USEC_PER_MSEC; |
| 38 | 37 | ||
| 39 | do_gettimeofday(&start); | 38 | start = ktime_get_boottime(); |
| 40 | 39 | ||
| 41 | end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs); | 40 | end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs); |
| 42 | 41 | ||
| @@ -78,10 +77,9 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 78 | sleep_usecs *= 2; | 77 | sleep_usecs *= 2; |
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | do_gettimeofday(&end); | 80 | end = ktime_get_boottime(); |
| 82 | elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); | 81 | elapsed = ktime_sub(end, start); |
| 83 | do_div(elapsed_msecs64, NSEC_PER_MSEC); | 82 | elapsed_msecs = ktime_to_ms(elapsed); |
| 84 | elapsed_msecs = elapsed_msecs64; | ||
| 85 | 83 | ||
| 86 | if (todo) { | 84 | if (todo) { |
| 87 | pr_cont("\n"); | 85 | pr_cont("\n"); |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index f9fe133c13e2..230a77225e2e 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
| @@ -248,7 +248,7 @@ static int suspend_test(int level) | |||
| 248 | { | 248 | { |
| 249 | #ifdef CONFIG_PM_DEBUG | 249 | #ifdef CONFIG_PM_DEBUG |
| 250 | if (pm_test_level == level) { | 250 | if (pm_test_level == level) { |
| 251 | printk(KERN_INFO "suspend debug: Waiting for %d second(s).\n", | 251 | pr_info("suspend debug: Waiting for %d second(s).\n", |
| 252 | pm_test_delay); | 252 | pm_test_delay); |
| 253 | mdelay(pm_test_delay * 1000); | 253 | mdelay(pm_test_delay * 1000); |
| 254 | return 1; | 254 | return 1; |
| @@ -320,7 +320,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
| 320 | 320 | ||
| 321 | error = dpm_suspend_late(PMSG_SUSPEND); | 321 | error = dpm_suspend_late(PMSG_SUSPEND); |
| 322 | if (error) { | 322 | if (error) { |
| 323 | printk(KERN_ERR "PM: late suspend of devices failed\n"); | 323 | pr_err("PM: late suspend of devices failed\n"); |
| 324 | goto Platform_finish; | 324 | goto Platform_finish; |
| 325 | } | 325 | } |
| 326 | error = platform_suspend_prepare_late(state); | 326 | error = platform_suspend_prepare_late(state); |
| @@ -329,7 +329,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
| 329 | 329 | ||
| 330 | error = dpm_suspend_noirq(PMSG_SUSPEND); | 330 | error = dpm_suspend_noirq(PMSG_SUSPEND); |
| 331 | if (error) { | 331 | if (error) { |
| 332 | printk(KERN_ERR "PM: noirq suspend of devices failed\n"); | 332 | pr_err("PM: noirq suspend of devices failed\n"); |
| 333 | goto Platform_early_resume; | 333 | goto Platform_early_resume; |
| 334 | } | 334 | } |
| 335 | error = platform_suspend_prepare_noirq(state); | 335 | error = platform_suspend_prepare_noirq(state); |
