diff options
| -rw-r--r-- | drivers/base/power/main.c | 3 | ||||
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 46 | ||||
| -rw-r--r-- | drivers/cpuidle/cpuidle.c | 2 | ||||
| -rw-r--r-- | drivers/idle/intel_idle.c | 4 | ||||
| -rw-r--r-- | drivers/pnp/driver.c | 12 | ||||
| -rw-r--r-- | drivers/powercap/powercap_sys.c | 7 | ||||
| -rw-r--r-- | include/linux/cpufreq.h | 8 |
7 files changed, 74 insertions, 8 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca3d65a..e3219dfd736c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/async.h> | 29 | #include <linux/async.h> |
| 30 | #include <linux/suspend.h> | 30 | #include <linux/suspend.h> |
| 31 | #include <trace/events/power.h> | 31 | #include <trace/events/power.h> |
| 32 | #include <linux/cpufreq.h> | ||
| 32 | #include <linux/cpuidle.h> | 33 | #include <linux/cpuidle.h> |
| 33 | #include <linux/timer.h> | 34 | #include <linux/timer.h> |
| 34 | 35 | ||
| @@ -540,6 +541,7 @@ static void dpm_resume_noirq(pm_message_t state) | |||
| 540 | dpm_show_time(starttime, state, "noirq"); | 541 | dpm_show_time(starttime, state, "noirq"); |
| 541 | resume_device_irqs(); | 542 | resume_device_irqs(); |
| 542 | cpuidle_resume(); | 543 | cpuidle_resume(); |
| 544 | cpufreq_resume(); | ||
| 543 | } | 545 | } |
| 544 | 546 | ||
| 545 | /** | 547 | /** |
| @@ -955,6 +957,7 @@ static int dpm_suspend_noirq(pm_message_t state) | |||
| 955 | ktime_t starttime = ktime_get(); | 957 | ktime_t starttime = ktime_get(); |
| 956 | int error = 0; | 958 | int error = 0; |
| 957 | 959 | ||
| 960 | cpufreq_suspend(); | ||
| 958 | cpuidle_pause(); | 961 | cpuidle_pause(); |
| 959 | suspend_device_irqs(); | 962 | suspend_device_irqs(); |
| 960 | mutex_lock(&dpm_list_mtx); | 963 | mutex_lock(&dpm_list_mtx); |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 02d534da22dd..81e9d4412db8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
| 28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 29 | #include <linux/suspend.h> | ||
| 29 | #include <linux/syscore_ops.h> | 30 | #include <linux/syscore_ops.h> |
| 30 | #include <linux/tick.h> | 31 | #include <linux/tick.h> |
| 31 | #include <trace/events/power.h> | 32 | #include <trace/events/power.h> |
| @@ -47,6 +48,9 @@ static LIST_HEAD(cpufreq_policy_list); | |||
| 47 | static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); | 48 | static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); |
| 48 | #endif | 49 | #endif |
| 49 | 50 | ||
| 51 | /* Flag to suspend/resume CPUFreq governors */ | ||
| 52 | static bool cpufreq_suspended; | ||
| 53 | |||
| 50 | static inline bool has_target(void) | 54 | static inline bool has_target(void) |
| 51 | { | 55 | { |
| 52 | return cpufreq_driver->target_index || cpufreq_driver->target; | 56 | return cpufreq_driver->target_index || cpufreq_driver->target; |
| @@ -1462,6 +1466,41 @@ static struct subsys_interface cpufreq_interface = { | |||
| 1462 | .remove_dev = cpufreq_remove_dev, | 1466 | .remove_dev = cpufreq_remove_dev, |
| 1463 | }; | 1467 | }; |
| 1464 | 1468 | ||
| 1469 | void cpufreq_suspend(void) | ||
| 1470 | { | ||
| 1471 | struct cpufreq_policy *policy; | ||
| 1472 | |||
| 1473 | if (!has_target()) | ||
| 1474 | return; | ||
| 1475 | |||
| 1476 | pr_debug("%s: Suspending Governors\n", __func__); | ||
| 1477 | |||
| 1478 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) | ||
| 1479 | if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) | ||
| 1480 | pr_err("%s: Failed to stop governor for policy: %p\n", | ||
| 1481 | __func__, policy); | ||
| 1482 | |||
| 1483 | cpufreq_suspended = true; | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | void cpufreq_resume(void) | ||
| 1487 | { | ||
| 1488 | struct cpufreq_policy *policy; | ||
| 1489 | |||
| 1490 | if (!has_target()) | ||
| 1491 | return; | ||
| 1492 | |||
| 1493 | pr_debug("%s: Resuming Governors\n", __func__); | ||
| 1494 | |||
| 1495 | cpufreq_suspended = false; | ||
| 1496 | |||
| 1497 | list_for_each_entry(policy, &cpufreq_policy_list, policy_list) | ||
| 1498 | if (__cpufreq_governor(policy, CPUFREQ_GOV_START) | ||
| 1499 | || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS)) | ||
| 1500 | pr_err("%s: Failed to start governor for policy: %p\n", | ||
| 1501 | __func__, policy); | ||
| 1502 | } | ||
| 1503 | |||
| 1465 | /** | 1504 | /** |
| 1466 | * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. | 1505 | * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. |
| 1467 | * | 1506 | * |
| @@ -1764,6 +1803,10 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, | |||
| 1764 | struct cpufreq_governor *gov = NULL; | 1803 | struct cpufreq_governor *gov = NULL; |
| 1765 | #endif | 1804 | #endif |
| 1766 | 1805 | ||
| 1806 | /* Don't start any governor operations if we are entering suspend */ | ||
| 1807 | if (cpufreq_suspended) | ||
| 1808 | return 0; | ||
| 1809 | |||
| 1767 | if (policy->governor->max_transition_latency && | 1810 | if (policy->governor->max_transition_latency && |
| 1768 | policy->cpuinfo.transition_latency > | 1811 | policy->cpuinfo.transition_latency > |
| 1769 | policy->governor->max_transition_latency) { | 1812 | policy->governor->max_transition_latency) { |
| @@ -2076,9 +2119,6 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, | |||
| 2076 | dev = get_cpu_device(cpu); | 2119 | dev = get_cpu_device(cpu); |
| 2077 | if (dev) { | 2120 | if (dev) { |
| 2078 | 2121 | ||
| 2079 | if (action & CPU_TASKS_FROZEN) | ||
| 2080 | frozen = true; | ||
| 2081 | |||
| 2082 | switch (action & ~CPU_TASKS_FROZEN) { | 2122 | switch (action & ~CPU_TASKS_FROZEN) { |
| 2083 | case CPU_ONLINE: | 2123 | case CPU_ONLINE: |
| 2084 | __cpufreq_add_dev(dev, NULL, frozen); | 2124 | __cpufreq_add_dev(dev, NULL, frozen); |
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 2a991e468f78..a55e68f2cfc8 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
| @@ -400,7 +400,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device); | |||
| 400 | */ | 400 | */ |
| 401 | void cpuidle_unregister_device(struct cpuidle_device *dev) | 401 | void cpuidle_unregister_device(struct cpuidle_device *dev) |
| 402 | { | 402 | { |
| 403 | if (dev->registered == 0) | 403 | if (!dev || dev->registered == 0) |
| 404 | return; | 404 | return; |
| 405 | 405 | ||
| 406 | cpuidle_pause_and_lock(); | 406 | cpuidle_pause_and_lock(); |
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index cbd4e9abc47e..92d1206482a6 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
| @@ -329,7 +329,7 @@ static struct cpuidle_state atom_cstates[] __initdata = { | |||
| 329 | { | 329 | { |
| 330 | .enter = NULL } | 330 | .enter = NULL } |
| 331 | }; | 331 | }; |
| 332 | static struct cpuidle_state avn_cstates[CPUIDLE_STATE_MAX] = { | 332 | static struct cpuidle_state avn_cstates[] __initdata = { |
| 333 | { | 333 | { |
| 334 | .name = "C1-AVN", | 334 | .name = "C1-AVN", |
| 335 | .desc = "MWAIT 0x00", | 335 | .desc = "MWAIT 0x00", |
| @@ -340,7 +340,7 @@ static struct cpuidle_state avn_cstates[CPUIDLE_STATE_MAX] = { | |||
| 340 | { | 340 | { |
| 341 | .name = "C6-AVN", | 341 | .name = "C6-AVN", |
| 342 | .desc = "MWAIT 0x51", | 342 | .desc = "MWAIT 0x51", |
| 343 | .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | 343 | .flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
| 344 | .exit_latency = 15, | 344 | .exit_latency = 15, |
| 345 | .target_residency = 45, | 345 | .target_residency = 45, |
| 346 | .enter = &intel_idle }, | 346 | .enter = &intel_idle }, |
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 6936e0acedcd..f748cc8cbb03 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c | |||
| @@ -197,6 +197,11 @@ static int pnp_bus_freeze(struct device *dev) | |||
| 197 | return __pnp_bus_suspend(dev, PMSG_FREEZE); | 197 | return __pnp_bus_suspend(dev, PMSG_FREEZE); |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | static int pnp_bus_poweroff(struct device *dev) | ||
| 201 | { | ||
| 202 | return __pnp_bus_suspend(dev, PMSG_HIBERNATE); | ||
| 203 | } | ||
| 204 | |||
| 200 | static int pnp_bus_resume(struct device *dev) | 205 | static int pnp_bus_resume(struct device *dev) |
| 201 | { | 206 | { |
| 202 | struct pnp_dev *pnp_dev = to_pnp_dev(dev); | 207 | struct pnp_dev *pnp_dev = to_pnp_dev(dev); |
| @@ -234,9 +239,14 @@ static int pnp_bus_resume(struct device *dev) | |||
| 234 | } | 239 | } |
| 235 | 240 | ||
| 236 | static const struct dev_pm_ops pnp_bus_dev_pm_ops = { | 241 | static const struct dev_pm_ops pnp_bus_dev_pm_ops = { |
| 242 | /* Suspend callbacks */ | ||
| 237 | .suspend = pnp_bus_suspend, | 243 | .suspend = pnp_bus_suspend, |
| 238 | .freeze = pnp_bus_freeze, | ||
| 239 | .resume = pnp_bus_resume, | 244 | .resume = pnp_bus_resume, |
| 245 | /* Hibernate callbacks */ | ||
| 246 | .freeze = pnp_bus_freeze, | ||
| 247 | .thaw = pnp_bus_resume, | ||
| 248 | .poweroff = pnp_bus_poweroff, | ||
| 249 | .restore = pnp_bus_resume, | ||
| 240 | }; | 250 | }; |
| 241 | 251 | ||
| 242 | struct bus_type pnp_bus_type = { | 252 | struct bus_type pnp_bus_type = { |
diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 8d0fe431dbdd..84419af16f77 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c | |||
| @@ -377,9 +377,14 @@ static void create_power_zone_common_attributes( | |||
| 377 | if (power_zone->ops->get_max_energy_range_uj) | 377 | if (power_zone->ops->get_max_energy_range_uj) |
| 378 | power_zone->zone_dev_attrs[count++] = | 378 | power_zone->zone_dev_attrs[count++] = |
| 379 | &dev_attr_max_energy_range_uj.attr; | 379 | &dev_attr_max_energy_range_uj.attr; |
| 380 | if (power_zone->ops->get_energy_uj) | 380 | if (power_zone->ops->get_energy_uj) { |
| 381 | if (power_zone->ops->reset_energy_uj) | ||
| 382 | dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUGO; | ||
| 383 | else | ||
| 384 | dev_attr_energy_uj.attr.mode = S_IRUGO; | ||
| 381 | power_zone->zone_dev_attrs[count++] = | 385 | power_zone->zone_dev_attrs[count++] = |
| 382 | &dev_attr_energy_uj.attr; | 386 | &dev_attr_energy_uj.attr; |
| 387 | } | ||
| 383 | if (power_zone->ops->get_power_uw) | 388 | if (power_zone->ops->get_power_uw) |
| 384 | power_zone->zone_dev_attrs[count++] = | 389 | power_zone->zone_dev_attrs[count++] = |
| 385 | &dev_attr_power_uw.attr; | 390 | &dev_attr_power_uw.attr; |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index dc196bbcf227..ee5fe9d77ae8 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
| @@ -280,6 +280,14 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy) | |||
| 280 | policy->cpuinfo.max_freq); | 280 | policy->cpuinfo.max_freq); |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | #ifdef CONFIG_CPU_FREQ | ||
| 284 | void cpufreq_suspend(void); | ||
| 285 | void cpufreq_resume(void); | ||
| 286 | #else | ||
| 287 | static inline void cpufreq_suspend(void) {} | ||
| 288 | static inline void cpufreq_resume(void) {} | ||
| 289 | #endif | ||
| 290 | |||
| 283 | /********************************************************************* | 291 | /********************************************************************* |
| 284 | * CPUFREQ NOTIFIER INTERFACE * | 292 | * CPUFREQ NOTIFIER INTERFACE * |
| 285 | *********************************************************************/ | 293 | *********************************************************************/ |
