aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-26 07:40:53 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-26 07:40:53 -0400
commit43e8317b0bba1d6eb85f38a4a233d82d7c20d732 (patch)
tree9598176b6c0c0660df93541b1bd5f4ccc5ad450c /kernel
parent27ddcc6596e50cb8f03d2e83248897667811d8f6 (diff)
PM / sleep: Use valid_state() for platform-dependent sleep states only
Use the observation that, for platform-dependent sleep states (PM_SUSPEND_STANDBY, PM_SUSPEND_MEM), a given state is either always supported or always unsupported and store that information in pm_states[] instead of calling valid_state() every time we need to check it. Also do not use valid_state() for PM_SUSPEND_FREEZE, which is always valid, and move the pm_test_level validity check for PM_SUSPEND_FREEZE directly into enter_state(). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/main.c9
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/suspend.c60
-rw-r--r--kernel/power/suspend_test.c2
4 files changed, 36 insertions, 37 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 8e818432253c..9f51f0ab3d86 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -296,7 +296,7 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
296 suspend_state_t i; 296 suspend_state_t i;
297 297
298 for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 298 for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
299 if (valid_state(i)) 299 if (pm_states[i].state)
300 s += sprintf(s,"%s ", pm_states[i].label); 300 s += sprintf(s,"%s ", pm_states[i].label);
301 301
302#endif 302#endif
@@ -328,8 +328,9 @@ static suspend_state_t decode_state(const char *buf, size_t n)
328 328
329#ifdef CONFIG_SUSPEND 329#ifdef CONFIG_SUSPEND
330 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) 330 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
331 if (len == strlen(s->label) && !strncmp(buf, s->label, len)) 331 if (s->state && len == strlen(s->label)
332 return state; 332 && !strncmp(buf, s->label, len))
333 return s->state;
333#endif 334#endif
334 335
335 return PM_SUSPEND_ON; 336 return PM_SUSPEND_ON;
@@ -447,7 +448,7 @@ static ssize_t autosleep_show(struct kobject *kobj,
447 448
448#ifdef CONFIG_SUSPEND 449#ifdef CONFIG_SUSPEND
449 if (state < PM_SUSPEND_MAX) 450 if (state < PM_SUSPEND_MAX)
450 return sprintf(buf, "%s\n", valid_state(state) ? 451 return sprintf(buf, "%s\n", pm_states[state].state ?
451 pm_states[state].label : "error"); 452 pm_states[state].label : "error");
452#endif 453#endif
453#ifdef CONFIG_HIBERNATION 454#ifdef CONFIG_HIBERNATION
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 99539c5da844..c60f13b5270a 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -186,14 +186,12 @@ struct pm_sleep_state {
186/* kernel/power/suspend.c */ 186/* kernel/power/suspend.c */
187extern struct pm_sleep_state pm_states[]; 187extern struct pm_sleep_state pm_states[];
188 188
189extern bool valid_state(suspend_state_t state);
190extern int suspend_devices_and_enter(suspend_state_t state); 189extern int suspend_devices_and_enter(suspend_state_t state);
191#else /* !CONFIG_SUSPEND */ 190#else /* !CONFIG_SUSPEND */
192static inline int suspend_devices_and_enter(suspend_state_t state) 191static inline int suspend_devices_and_enter(suspend_state_t state)
193{ 192{
194 return -ENOSYS; 193 return -ENOSYS;
195} 194}
196static inline bool valid_state(suspend_state_t state) { return false; }
197#endif /* !CONFIG_SUSPEND */ 195#endif /* !CONFIG_SUSPEND */
198 196
199#ifdef CONFIG_PM_TEST_SUSPEND 197#ifdef CONFIG_PM_TEST_SUSPEND
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 5d93b138a2d4..00aca60904b0 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -32,9 +32,9 @@
32#include "power.h" 32#include "power.h"
33 33
34struct pm_sleep_state pm_states[PM_SUSPEND_MAX] = { 34struct pm_sleep_state pm_states[PM_SUSPEND_MAX] = {
35 [PM_SUSPEND_FREEZE] = { "freeze", PM_SUSPEND_FREEZE }, 35 [PM_SUSPEND_FREEZE] = { .label = "freeze", .state = PM_SUSPEND_FREEZE },
36 [PM_SUSPEND_STANDBY] = { "standby", PM_SUSPEND_STANDBY }, 36 [PM_SUSPEND_STANDBY] = { .label = "standby", },
37 [PM_SUSPEND_MEM] = { "mem", PM_SUSPEND_MEM }, 37 [PM_SUSPEND_MEM] = { .label = "mem", },
38}; 38};
39 39
40static const struct platform_suspend_ops *suspend_ops; 40static const struct platform_suspend_ops *suspend_ops;
@@ -68,42 +68,34 @@ void freeze_wake(void)
68} 68}
69EXPORT_SYMBOL_GPL(freeze_wake); 69EXPORT_SYMBOL_GPL(freeze_wake);
70 70
71static bool valid_state(suspend_state_t state)
72{
73 /*
74 * PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level
75 * support and need to be valid to the low level
76 * implementation, no valid callback implies that none are valid.
77 */
78 return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
79}
80
71/** 81/**
72 * suspend_set_ops - Set the global suspend method table. 82 * suspend_set_ops - Set the global suspend method table.
73 * @ops: Suspend operations to use. 83 * @ops: Suspend operations to use.
74 */ 84 */
75void suspend_set_ops(const struct platform_suspend_ops *ops) 85void suspend_set_ops(const struct platform_suspend_ops *ops)
76{ 86{
87 suspend_state_t i;
88
77 lock_system_sleep(); 89 lock_system_sleep();
90
78 suspend_ops = ops; 91 suspend_ops = ops;
92 for (i = PM_SUSPEND_STANDBY; i <= PM_SUSPEND_MEM; i++)
93 pm_states[i].state = valid_state(i) ? i : 0;
94
79 unlock_system_sleep(); 95 unlock_system_sleep();
80} 96}
81EXPORT_SYMBOL_GPL(suspend_set_ops); 97EXPORT_SYMBOL_GPL(suspend_set_ops);
82 98
83bool valid_state(suspend_state_t state)
84{
85 if (state == PM_SUSPEND_FREEZE) {
86#ifdef CONFIG_PM_DEBUG
87 if (pm_test_level != TEST_NONE &&
88 pm_test_level != TEST_FREEZER &&
89 pm_test_level != TEST_DEVICES &&
90 pm_test_level != TEST_PLATFORM) {
91 printk(KERN_WARNING "Unsupported pm_test mode for "
92 "freeze state, please choose "
93 "none/freezer/devices/platform.\n");
94 return false;
95 }
96#endif
97 return true;
98 }
99 /*
100 * PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel
101 * support and need to be valid to the lowlevel
102 * implementation, no valid callback implies that none are valid.
103 */
104 return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
105}
106
107/** 99/**
108 * suspend_valid_only_mem - Generic memory-only valid callback. 100 * suspend_valid_only_mem - Generic memory-only valid callback.
109 * 101 *
@@ -330,9 +322,17 @@ static int enter_state(suspend_state_t state)
330{ 322{
331 int error; 323 int error;
332 324
333 if (!valid_state(state)) 325 if (state == PM_SUSPEND_FREEZE) {
334 return -ENODEV; 326#ifdef CONFIG_PM_DEBUG
335 327 if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
328 pr_warning("PM: Unsupported test mode for freeze state,"
329 "please choose none/freezer/devices/platform.\n");
330 return -EAGAIN;
331 }
332#endif
333 } else if (!valid_state(state)) {
334 return -EINVAL;
335 }
336 if (!mutex_trylock(&pm_mutex)) 336 if (!mutex_trylock(&pm_mutex))
337 return -EBUSY; 337 return -EBUSY;
338 338
diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c
index d4e3ab167a73..269b097e78ea 100644
--- a/kernel/power/suspend_test.c
+++ b/kernel/power/suspend_test.c
@@ -162,7 +162,7 @@ static int __init test_suspend(void)
162 /* PM is initialized by now; is that state testable? */ 162 /* PM is initialized by now; is that state testable? */
163 if (test_state == PM_SUSPEND_ON) 163 if (test_state == PM_SUSPEND_ON)
164 goto done; 164 goto done;
165 if (!valid_state(test_state)) { 165 if (!pm_states[test_state].state) {
166 printk(warn_bad_state, pm_states[test_state].label); 166 printk(warn_bad_state, pm_states[test_state].label);
167 goto done; 167 goto done;
168 } 168 }