diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-03 23:15:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-03 23:15:57 -0400 |
commit | 4d578573b8328ce5aa6500b955444b89afa3c72c (patch) | |
tree | 13b839d10dfc7e886515e2ef9e91fe7881700545 | |
parent | 68e3e92620c323703bc7db75c2ba15239ee85c39 (diff) | |
parent | dbe9a2edd17d843d80faf2b99f20a691c1853418 (diff) |
Merge branch 'pm-acpi' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull some left-over PM patches from Rafael J. Wysocki.
* 'pm-acpi' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
ACPI / PM: Make acpi_pm_device_sleep_state() follow the specification
ACPI / PM: Make __acpi_bus_get_power() cover D3cold correctly
ACPI / PM: Fix error messages in drivers/acpi/bus.c
rtc-cmos / PM: report wakeup event on ACPI RTC alarm
ACPI / PM: Generate wakeup events on fixed power button
-rw-r--r-- | drivers/acpi/bus.c | 88 | ||||
-rw-r--r-- | drivers/acpi/power.c | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 1 | ||||
-rw-r--r-- | drivers/acpi/sleep.c | 49 | ||||
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 9 |
5 files changed, 110 insertions, 39 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 3188da3df8da..adceafda9c17 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -182,41 +182,66 @@ EXPORT_SYMBOL(acpi_bus_get_private_data); | |||
182 | Power Management | 182 | Power Management |
183 | -------------------------------------------------------------------------- */ | 183 | -------------------------------------------------------------------------- */ |
184 | 184 | ||
185 | static const char *state_string(int state) | ||
186 | { | ||
187 | switch (state) { | ||
188 | case ACPI_STATE_D0: | ||
189 | return "D0"; | ||
190 | case ACPI_STATE_D1: | ||
191 | return "D1"; | ||
192 | case ACPI_STATE_D2: | ||
193 | return "D2"; | ||
194 | case ACPI_STATE_D3_HOT: | ||
195 | return "D3hot"; | ||
196 | case ACPI_STATE_D3_COLD: | ||
197 | return "D3"; | ||
198 | default: | ||
199 | return "(unknown)"; | ||
200 | } | ||
201 | } | ||
202 | |||
185 | static int __acpi_bus_get_power(struct acpi_device *device, int *state) | 203 | static int __acpi_bus_get_power(struct acpi_device *device, int *state) |
186 | { | 204 | { |
187 | int result = 0; | 205 | int result = ACPI_STATE_UNKNOWN; |
188 | acpi_status status = 0; | ||
189 | unsigned long long psc = 0; | ||
190 | 206 | ||
191 | if (!device || !state) | 207 | if (!device || !state) |
192 | return -EINVAL; | 208 | return -EINVAL; |
193 | 209 | ||
194 | *state = ACPI_STATE_UNKNOWN; | 210 | if (!device->flags.power_manageable) { |
195 | |||
196 | if (device->flags.power_manageable) { | ||
197 | /* | ||
198 | * Get the device's power state either directly (via _PSC) or | ||
199 | * indirectly (via power resources). | ||
200 | */ | ||
201 | if (device->power.flags.power_resources) { | ||
202 | result = acpi_power_get_inferred_state(device, state); | ||
203 | if (result) | ||
204 | return result; | ||
205 | } else if (device->power.flags.explicit_get) { | ||
206 | status = acpi_evaluate_integer(device->handle, "_PSC", | ||
207 | NULL, &psc); | ||
208 | if (ACPI_FAILURE(status)) | ||
209 | return -ENODEV; | ||
210 | *state = (int)psc; | ||
211 | } | ||
212 | } else { | ||
213 | /* TBD: Non-recursive algorithm for walking up hierarchy. */ | 211 | /* TBD: Non-recursive algorithm for walking up hierarchy. */ |
214 | *state = device->parent ? | 212 | *state = device->parent ? |
215 | device->parent->power.state : ACPI_STATE_D0; | 213 | device->parent->power.state : ACPI_STATE_D0; |
214 | goto out; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Get the device's power state either directly (via _PSC) or | ||
219 | * indirectly (via power resources). | ||
220 | */ | ||
221 | if (device->power.flags.explicit_get) { | ||
222 | unsigned long long psc; | ||
223 | acpi_status status = acpi_evaluate_integer(device->handle, | ||
224 | "_PSC", NULL, &psc); | ||
225 | if (ACPI_FAILURE(status)) | ||
226 | return -ENODEV; | ||
227 | |||
228 | result = psc; | ||
229 | } | ||
230 | /* The test below covers ACPI_STATE_UNKNOWN too. */ | ||
231 | if (result <= ACPI_STATE_D2) { | ||
232 | ; /* Do nothing. */ | ||
233 | } else if (device->power.flags.power_resources) { | ||
234 | int error = acpi_power_get_inferred_state(device, &result); | ||
235 | if (error) | ||
236 | return error; | ||
237 | } else if (result == ACPI_STATE_D3_HOT) { | ||
238 | result = ACPI_STATE_D3; | ||
216 | } | 239 | } |
240 | *state = result; | ||
217 | 241 | ||
218 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", | 242 | out: |
219 | device->pnp.bus_id, *state)); | 243 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", |
244 | device->pnp.bus_id, state_string(*state))); | ||
220 | 245 | ||
221 | return 0; | 246 | return 0; |
222 | } | 247 | } |
@@ -234,13 +259,14 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) | |||
234 | /* Make sure this is a valid target state */ | 259 | /* Make sure this is a valid target state */ |
235 | 260 | ||
236 | if (state == device->power.state) { | 261 | if (state == device->power.state) { |
237 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", | 262 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", |
238 | state)); | 263 | state_string(state))); |
239 | return 0; | 264 | return 0; |
240 | } | 265 | } |
241 | 266 | ||
242 | if (!device->power.states[state].flags.valid) { | 267 | if (!device->power.states[state].flags.valid) { |
243 | printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); | 268 | printk(KERN_WARNING PREFIX "Device does not support %s\n", |
269 | state_string(state)); | ||
244 | return -ENODEV; | 270 | return -ENODEV; |
245 | } | 271 | } |
246 | if (device->parent && (state < device->parent->power.state)) { | 272 | if (device->parent && (state < device->parent->power.state)) { |
@@ -294,13 +320,13 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) | |||
294 | end: | 320 | end: |
295 | if (result) | 321 | if (result) |
296 | printk(KERN_WARNING PREFIX | 322 | printk(KERN_WARNING PREFIX |
297 | "Device [%s] failed to transition to D%d\n", | 323 | "Device [%s] failed to transition to %s\n", |
298 | device->pnp.bus_id, state); | 324 | device->pnp.bus_id, state_string(state)); |
299 | else { | 325 | else { |
300 | device->power.state = state; | 326 | device->power.state = state; |
301 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 327 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
302 | "Device [%s] transitioned to D%d\n", | 328 | "Device [%s] transitioned to %s\n", |
303 | device->pnp.bus_id, state)); | 329 | device->pnp.bus_id, state_string(state))); |
304 | } | 330 | } |
305 | 331 | ||
306 | return result; | 332 | return result; |
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0500f719f63e..dd6d6a3c6780 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -631,7 +631,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state) | |||
631 | * We know a device's inferred power state when all the resources | 631 | * We know a device's inferred power state when all the resources |
632 | * required for a given D-state are 'on'. | 632 | * required for a given D-state are 'on'. |
633 | */ | 633 | */ |
634 | for (i = ACPI_STATE_D0; i < ACPI_STATE_D3_HOT; i++) { | 634 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { |
635 | list = &device->power.states[i].resources; | 635 | list = &device->power.states[i].resources; |
636 | if (list->count < 1) | 636 | if (list->count < 1) |
637 | continue; | 637 | continue; |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 85cbfdccc97c..c8a1f3b68110 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1567,6 +1567,7 @@ static int acpi_bus_scan_fixed(void) | |||
1567 | ACPI_BUS_TYPE_POWER_BUTTON, | 1567 | ACPI_BUS_TYPE_POWER_BUTTON, |
1568 | ACPI_STA_DEFAULT, | 1568 | ACPI_STA_DEFAULT, |
1569 | &ops); | 1569 | &ops); |
1570 | device_init_wakeup(&device->dev, true); | ||
1570 | } | 1571 | } |
1571 | 1572 | ||
1572 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { | 1573 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { |
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 74ee4ab577b6..88561029cca8 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -57,6 +57,7 @@ MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); | |||
57 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); | 57 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); |
58 | 58 | ||
59 | static u8 sleep_states[ACPI_S_STATE_COUNT]; | 59 | static u8 sleep_states[ACPI_S_STATE_COUNT]; |
60 | static bool pwr_btn_event_pending; | ||
60 | 61 | ||
61 | static void acpi_sleep_tts_switch(u32 acpi_state) | 62 | static void acpi_sleep_tts_switch(u32 acpi_state) |
62 | { | 63 | { |
@@ -184,6 +185,14 @@ static int acpi_pm_prepare(void) | |||
184 | return error; | 185 | return error; |
185 | } | 186 | } |
186 | 187 | ||
188 | static int find_powerf_dev(struct device *dev, void *data) | ||
189 | { | ||
190 | struct acpi_device *device = to_acpi_device(dev); | ||
191 | const char *hid = acpi_device_hid(device); | ||
192 | |||
193 | return !strcmp(hid, ACPI_BUTTON_HID_POWERF); | ||
194 | } | ||
195 | |||
187 | /** | 196 | /** |
188 | * acpi_pm_finish - Instruct the platform to leave a sleep state. | 197 | * acpi_pm_finish - Instruct the platform to leave a sleep state. |
189 | * | 198 | * |
@@ -192,6 +201,7 @@ static int acpi_pm_prepare(void) | |||
192 | */ | 201 | */ |
193 | static void acpi_pm_finish(void) | 202 | static void acpi_pm_finish(void) |
194 | { | 203 | { |
204 | struct device *pwr_btn_dev; | ||
195 | u32 acpi_state = acpi_target_sleep_state; | 205 | u32 acpi_state = acpi_target_sleep_state; |
196 | 206 | ||
197 | acpi_ec_unblock_transactions(); | 207 | acpi_ec_unblock_transactions(); |
@@ -209,6 +219,23 @@ static void acpi_pm_finish(void) | |||
209 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 219 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
210 | 220 | ||
211 | acpi_target_sleep_state = ACPI_STATE_S0; | 221 | acpi_target_sleep_state = ACPI_STATE_S0; |
222 | |||
223 | /* If we were woken with the fixed power button, provide a small | ||
224 | * hint to userspace in the form of a wakeup event on the fixed power | ||
225 | * button device (if it can be found). | ||
226 | * | ||
227 | * We delay the event generation til now, as the PM layer requires | ||
228 | * timekeeping to be running before we generate events. */ | ||
229 | if (!pwr_btn_event_pending) | ||
230 | return; | ||
231 | |||
232 | pwr_btn_event_pending = false; | ||
233 | pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL, | ||
234 | find_powerf_dev); | ||
235 | if (pwr_btn_dev) { | ||
236 | pm_wakeup_event(pwr_btn_dev, 0); | ||
237 | put_device(pwr_btn_dev); | ||
238 | } | ||
212 | } | 239 | } |
213 | 240 | ||
214 | /** | 241 | /** |
@@ -298,9 +325,23 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
298 | /* ACPI 3.0 specs (P62) says that it's the responsibility | 325 | /* ACPI 3.0 specs (P62) says that it's the responsibility |
299 | * of the OSPM to clear the status bit [ implying that the | 326 | * of the OSPM to clear the status bit [ implying that the |
300 | * POWER_BUTTON event should not reach userspace ] | 327 | * POWER_BUTTON event should not reach userspace ] |
328 | * | ||
329 | * However, we do generate a small hint for userspace in the form of | ||
330 | * a wakeup event. We flag this condition for now and generate the | ||
331 | * event later, as we're currently too early in resume to be able to | ||
332 | * generate wakeup events. | ||
301 | */ | 333 | */ |
302 | if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) | 334 | if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) { |
303 | acpi_clear_event(ACPI_EVENT_POWER_BUTTON); | 335 | acpi_event_status pwr_btn_status; |
336 | |||
337 | acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); | ||
338 | |||
339 | if (pwr_btn_status & ACPI_EVENT_FLAG_SET) { | ||
340 | acpi_clear_event(ACPI_EVENT_POWER_BUTTON); | ||
341 | /* Flag for later */ | ||
342 | pwr_btn_event_pending = true; | ||
343 | } | ||
344 | } | ||
304 | 345 | ||
305 | /* | 346 | /* |
306 | * Disable and clear GPE status before interrupt is enabled. Some GPEs | 347 | * Disable and clear GPE status before interrupt is enabled. Some GPEs |
@@ -730,8 +771,8 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
730 | * can wake the system. _S0W may be valid, too. | 771 | * can wake the system. _S0W may be valid, too. |
731 | */ | 772 | */ |
732 | if (acpi_target_sleep_state == ACPI_STATE_S0 || | 773 | if (acpi_target_sleep_state == ACPI_STATE_S0 || |
733 | (device_may_wakeup(dev) && | 774 | (device_may_wakeup(dev) && adev->wakeup.flags.valid && |
734 | adev->wakeup.sleep_state <= acpi_target_sleep_state)) { | 775 | adev->wakeup.sleep_state >= acpi_target_sleep_state)) { |
735 | acpi_status status; | 776 | acpi_status status; |
736 | 777 | ||
737 | acpi_method[3] = 'W'; | 778 | acpi_method[3] = 'W'; |
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 7d5f56edb8ef..4267789ca995 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -910,14 +910,17 @@ static inline int cmos_poweroff(struct device *dev) | |||
910 | 910 | ||
911 | static u32 rtc_handler(void *context) | 911 | static u32 rtc_handler(void *context) |
912 | { | 912 | { |
913 | struct device *dev = context; | ||
914 | |||
915 | pm_wakeup_event(dev, 0); | ||
913 | acpi_clear_event(ACPI_EVENT_RTC); | 916 | acpi_clear_event(ACPI_EVENT_RTC); |
914 | acpi_disable_event(ACPI_EVENT_RTC, 0); | 917 | acpi_disable_event(ACPI_EVENT_RTC, 0); |
915 | return ACPI_INTERRUPT_HANDLED; | 918 | return ACPI_INTERRUPT_HANDLED; |
916 | } | 919 | } |
917 | 920 | ||
918 | static inline void rtc_wake_setup(void) | 921 | static inline void rtc_wake_setup(struct device *dev) |
919 | { | 922 | { |
920 | acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); | 923 | acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, dev); |
921 | /* | 924 | /* |
922 | * After the RTC handler is installed, the Fixed_RTC event should | 925 | * After the RTC handler is installed, the Fixed_RTC event should |
923 | * be disabled. Only when the RTC alarm is set will it be enabled. | 926 | * be disabled. Only when the RTC alarm is set will it be enabled. |
@@ -950,7 +953,7 @@ cmos_wake_setup(struct device *dev) | |||
950 | if (acpi_disabled) | 953 | if (acpi_disabled) |
951 | return; | 954 | return; |
952 | 955 | ||
953 | rtc_wake_setup(); | 956 | rtc_wake_setup(dev); |
954 | acpi_rtc_info.wake_on = rtc_wake_on; | 957 | acpi_rtc_info.wake_on = rtc_wake_on; |
955 | acpi_rtc_info.wake_off = rtc_wake_off; | 958 | acpi_rtc_info.wake_off = rtc_wake_off; |
956 | 959 | ||