aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/main.c3
-rw-r--r--drivers/cpufreq/cpufreq.c46
-rw-r--r--drivers/cpuidle/cpuidle.c2
-rw-r--r--drivers/idle/intel_idle.c4
-rw-r--r--drivers/pnp/driver.c12
-rw-r--r--drivers/powercap/powercap_sys.c7
-rw-r--r--fs/eventpoll.c3
-rw-r--r--include/linux/cpufreq.h8
-rw-r--r--include/uapi/linux/eventpoll.h13
9 files changed, 87 insertions, 11 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);
47static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 48static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
48#endif 49#endif
49 50
51/* Flag to suspend/resume CPUFreq governors */
52static bool cpufreq_suspended;
53
50static inline bool has_target(void) 54static 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
1469void 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
1486void 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 */
401void cpuidle_unregister_device(struct cpuidle_device *dev) 401void 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};
332static struct cpuidle_state avn_cstates[CPUIDLE_STATE_MAX] = { 332static 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
200static int pnp_bus_poweroff(struct device *dev)
201{
202 return __pnp_bus_suspend(dev, PMSG_HIBERNATE);
203}
204
200static int pnp_bus_resume(struct device *dev) 205static 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
236static const struct dev_pm_ops pnp_bus_dev_pm_ops = { 241static 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
242struct bus_type pnp_bus_type = { 252struct 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/fs/eventpoll.c b/fs/eventpoll.c
index 79b65c3b9e87..8b5e2584c840 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1852,8 +1852,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
1852 goto error_tgt_fput; 1852 goto error_tgt_fput;
1853 1853
1854 /* Check if EPOLLWAKEUP is allowed */ 1854 /* Check if EPOLLWAKEUP is allowed */
1855 if ((epds.events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND)) 1855 ep_take_care_of_epollwakeup(&epds);
1856 epds.events &= ~EPOLLWAKEUP;
1857 1856
1858 /* 1857 /*
1859 * We have to check that the file structure underneath the file descriptor 1858 * We have to check that the file structure underneath the file descriptor
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
284void cpufreq_suspend(void);
285void cpufreq_resume(void);
286#else
287static inline void cpufreq_suspend(void) {}
288static inline void cpufreq_resume(void) {}
289#endif
290
283/********************************************************************* 291/*********************************************************************
284 * CPUFREQ NOTIFIER INTERFACE * 292 * CPUFREQ NOTIFIER INTERFACE *
285 *********************************************************************/ 293 *********************************************************************/
diff --git a/include/uapi/linux/eventpoll.h b/include/uapi/linux/eventpoll.h
index 2c267bcbb85c..bc81fb2e1f0e 100644
--- a/include/uapi/linux/eventpoll.h
+++ b/include/uapi/linux/eventpoll.h
@@ -61,5 +61,16 @@ struct epoll_event {
61 __u64 data; 61 __u64 data;
62} EPOLL_PACKED; 62} EPOLL_PACKED;
63 63
64 64#ifdef CONFIG_PM_SLEEP
65static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
66{
67 if ((epev->events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
68 epev->events &= ~EPOLLWAKEUP;
69}
70#else
71static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
72{
73 epev->events &= ~EPOLLWAKEUP;
74}
75#endif
65#endif /* _UAPI_LINUX_EVENTPOLL_H */ 76#endif /* _UAPI_LINUX_EVENTPOLL_H */