diff options
Diffstat (limited to 'kernel/power/main.c')
-rw-r--r-- | kernel/power/main.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c index e1c413120469..72419a3b1beb 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -30,7 +30,7 @@ | |||
30 | DEFINE_MUTEX(pm_mutex); | 30 | DEFINE_MUTEX(pm_mutex); |
31 | 31 | ||
32 | struct pm_ops *pm_ops; | 32 | struct pm_ops *pm_ops; |
33 | suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM; | 33 | suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN; |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * pm_set_ops - Set the global power method table. | 36 | * pm_set_ops - Set the global power method table. |
@@ -41,9 +41,26 @@ void pm_set_ops(struct pm_ops * ops) | |||
41 | { | 41 | { |
42 | mutex_lock(&pm_mutex); | 42 | mutex_lock(&pm_mutex); |
43 | pm_ops = ops; | 43 | pm_ops = ops; |
44 | if (ops && ops->pm_disk_mode != PM_DISK_INVALID) { | ||
45 | pm_disk_mode = ops->pm_disk_mode; | ||
46 | } else | ||
47 | pm_disk_mode = PM_DISK_SHUTDOWN; | ||
44 | mutex_unlock(&pm_mutex); | 48 | mutex_unlock(&pm_mutex); |
45 | } | 49 | } |
46 | 50 | ||
51 | /** | ||
52 | * pm_valid_only_mem - generic memory-only valid callback | ||
53 | * | ||
54 | * pm_ops drivers that implement mem suspend only and only need | ||
55 | * to check for that in their .valid callback can use this instead | ||
56 | * of rolling their own .valid callback. | ||
57 | */ | ||
58 | int pm_valid_only_mem(suspend_state_t state) | ||
59 | { | ||
60 | return state == PM_SUSPEND_MEM; | ||
61 | } | ||
62 | |||
63 | |||
47 | static inline void pm_finish(suspend_state_t state) | 64 | static inline void pm_finish(suspend_state_t state) |
48 | { | 65 | { |
49 | if (pm_ops->finish) | 66 | if (pm_ops->finish) |
@@ -111,13 +128,24 @@ static int suspend_prepare(suspend_state_t state) | |||
111 | return error; | 128 | return error; |
112 | } | 129 | } |
113 | 130 | ||
131 | /* default implementation */ | ||
132 | void __attribute__ ((weak)) arch_suspend_disable_irqs(void) | ||
133 | { | ||
134 | local_irq_disable(); | ||
135 | } | ||
136 | |||
137 | /* default implementation */ | ||
138 | void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | ||
139 | { | ||
140 | local_irq_enable(); | ||
141 | } | ||
114 | 142 | ||
115 | int suspend_enter(suspend_state_t state) | 143 | int suspend_enter(suspend_state_t state) |
116 | { | 144 | { |
117 | int error = 0; | 145 | int error = 0; |
118 | unsigned long flags; | ||
119 | 146 | ||
120 | local_irq_save(flags); | 147 | arch_suspend_disable_irqs(); |
148 | BUG_ON(!irqs_disabled()); | ||
121 | 149 | ||
122 | if ((error = device_power_down(PMSG_SUSPEND))) { | 150 | if ((error = device_power_down(PMSG_SUSPEND))) { |
123 | printk(KERN_ERR "Some devices failed to power down\n"); | 151 | printk(KERN_ERR "Some devices failed to power down\n"); |
@@ -126,7 +154,8 @@ int suspend_enter(suspend_state_t state) | |||
126 | error = pm_ops->enter(state); | 154 | error = pm_ops->enter(state); |
127 | device_power_up(); | 155 | device_power_up(); |
128 | Done: | 156 | Done: |
129 | local_irq_restore(flags); | 157 | arch_suspend_enable_irqs(); |
158 | BUG_ON(irqs_disabled()); | ||
130 | return error; | 159 | return error; |
131 | } | 160 | } |
132 | 161 | ||
@@ -167,7 +196,10 @@ static inline int valid_state(suspend_state_t state) | |||
167 | if (state == PM_SUSPEND_DISK) | 196 | if (state == PM_SUSPEND_DISK) |
168 | return 1; | 197 | return 1; |
169 | 198 | ||
170 | if (pm_ops && pm_ops->valid && !pm_ops->valid(state)) | 199 | /* all other states need lowlevel support and need to be |
200 | * valid to the lowlevel implementation, no valid callback | ||
201 | * implies that none are valid. */ | ||
202 | if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state)) | ||
171 | return 0; | 203 | return 0; |
172 | return 1; | 204 | return 1; |
173 | } | 205 | } |