diff options
-rw-r--r-- | drivers/acpi/battery.c | 2 | ||||
-rw-r--r-- | drivers/acpi/button.c | 5 | ||||
-rw-r--r-- | drivers/acpi/device_pm.c | 3 | ||||
-rw-r--r-- | drivers/acpi/sleep.c | 28 | ||||
-rw-r--r-- | drivers/base/power/main.c | 5 | ||||
-rw-r--r-- | drivers/base/power/wakeup.c | 18 | ||||
-rw-r--r-- | include/linux/suspend.h | 7 | ||||
-rw-r--r-- | kernel/power/process.c | 2 | ||||
-rw-r--r-- | kernel/power/suspend.c | 29 |
9 files changed, 77 insertions, 22 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 4ef1e4624b2b..83ab17e4a795 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -776,7 +776,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume) | |||
776 | if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || | 776 | if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || |
777 | (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && | 777 | (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && |
778 | (battery->capacity_now <= battery->alarm))) | 778 | (battery->capacity_now <= battery->alarm))) |
779 | pm_wakeup_event(&battery->device->dev, 0); | 779 | pm_wakeup_hard_event(&battery->device->dev); |
780 | 780 | ||
781 | return result; | 781 | return result; |
782 | } | 782 | } |
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 668137e4a069..b7c2a06963d6 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
@@ -216,7 +216,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) | |||
216 | } | 216 | } |
217 | 217 | ||
218 | if (state) | 218 | if (state) |
219 | pm_wakeup_event(&device->dev, 0); | 219 | pm_wakeup_hard_event(&device->dev); |
220 | 220 | ||
221 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); | 221 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); |
222 | if (ret == NOTIFY_DONE) | 222 | if (ret == NOTIFY_DONE) |
@@ -398,7 +398,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) | |||
398 | } else { | 398 | } else { |
399 | int keycode; | 399 | int keycode; |
400 | 400 | ||
401 | pm_wakeup_event(&device->dev, 0); | 401 | pm_wakeup_hard_event(&device->dev); |
402 | if (button->suspended) | 402 | if (button->suspended) |
403 | break; | 403 | break; |
404 | 404 | ||
@@ -530,6 +530,7 @@ static int acpi_button_add(struct acpi_device *device) | |||
530 | lid_device = device; | 530 | lid_device = device; |
531 | } | 531 | } |
532 | 532 | ||
533 | device_init_wakeup(&device->dev, true); | ||
533 | printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); | 534 | printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); |
534 | return 0; | 535 | return 0; |
535 | 536 | ||
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 993fd31394c8..798d5003a039 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/pm_qos.h> | 24 | #include <linux/pm_qos.h> |
25 | #include <linux/pm_domain.h> | 25 | #include <linux/pm_domain.h> |
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/suspend.h> | ||
27 | 28 | ||
28 | #include "internal.h" | 29 | #include "internal.h" |
29 | 30 | ||
@@ -399,7 +400,7 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) | |||
399 | mutex_lock(&acpi_pm_notifier_lock); | 400 | mutex_lock(&acpi_pm_notifier_lock); |
400 | 401 | ||
401 | if (adev->wakeup.flags.notifier_present) { | 402 | if (adev->wakeup.flags.notifier_present) { |
402 | __pm_wakeup_event(adev->wakeup.ws, 0); | 403 | pm_wakeup_ws_event(adev->wakeup.ws, 0, true); |
403 | if (adev->wakeup.context.work.func) | 404 | if (adev->wakeup.context.work.func) |
404 | queue_pm_work(&adev->wakeup.context.work); | 405 | queue_pm_work(&adev->wakeup.context.work); |
405 | } | 406 | } |
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a4327af676fe..e84005d642e6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -662,14 +662,40 @@ static int acpi_freeze_prepare(void) | |||
662 | acpi_os_wait_events_complete(); | 662 | acpi_os_wait_events_complete(); |
663 | if (acpi_sci_irq_valid()) | 663 | if (acpi_sci_irq_valid()) |
664 | enable_irq_wake(acpi_sci_irq); | 664 | enable_irq_wake(acpi_sci_irq); |
665 | |||
665 | return 0; | 666 | return 0; |
666 | } | 667 | } |
667 | 668 | ||
669 | static void acpi_freeze_wake(void) | ||
670 | { | ||
671 | /* | ||
672 | * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means | ||
673 | * that the SCI has triggered while suspended, so cancel the wakeup in | ||
674 | * case it has not been a wakeup event (the GPEs will be checked later). | ||
675 | */ | ||
676 | if (acpi_sci_irq_valid() && | ||
677 | !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) | ||
678 | pm_system_cancel_wakeup(); | ||
679 | } | ||
680 | |||
681 | static void acpi_freeze_sync(void) | ||
682 | { | ||
683 | /* | ||
684 | * Process all pending events in case there are any wakeup ones. | ||
685 | * | ||
686 | * The EC driver uses the system workqueue, so that one needs to be | ||
687 | * flushed too. | ||
688 | */ | ||
689 | acpi_os_wait_events_complete(); | ||
690 | flush_scheduled_work(); | ||
691 | } | ||
692 | |||
668 | static void acpi_freeze_restore(void) | 693 | static void acpi_freeze_restore(void) |
669 | { | 694 | { |
670 | acpi_disable_wakeup_devices(ACPI_STATE_S0); | 695 | acpi_disable_wakeup_devices(ACPI_STATE_S0); |
671 | if (acpi_sci_irq_valid()) | 696 | if (acpi_sci_irq_valid()) |
672 | disable_irq_wake(acpi_sci_irq); | 697 | disable_irq_wake(acpi_sci_irq); |
698 | |||
673 | acpi_enable_all_runtime_gpes(); | 699 | acpi_enable_all_runtime_gpes(); |
674 | } | 700 | } |
675 | 701 | ||
@@ -681,6 +707,8 @@ static void acpi_freeze_end(void) | |||
681 | static const struct platform_freeze_ops acpi_freeze_ops = { | 707 | static const struct platform_freeze_ops acpi_freeze_ops = { |
682 | .begin = acpi_freeze_begin, | 708 | .begin = acpi_freeze_begin, |
683 | .prepare = acpi_freeze_prepare, | 709 | .prepare = acpi_freeze_prepare, |
710 | .wake = acpi_freeze_wake, | ||
711 | .sync = acpi_freeze_sync, | ||
684 | .restore = acpi_freeze_restore, | 712 | .restore = acpi_freeze_restore, |
685 | .end = acpi_freeze_end, | 713 | .end = acpi_freeze_end, |
686 | }; | 714 | }; |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9faee1c893e5..e987a6f55d36 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -1091,11 +1091,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a | |||
1091 | if (async_error) | 1091 | if (async_error) |
1092 | goto Complete; | 1092 | goto Complete; |
1093 | 1093 | ||
1094 | if (pm_wakeup_pending()) { | ||
1095 | async_error = -EBUSY; | ||
1096 | goto Complete; | ||
1097 | } | ||
1098 | |||
1099 | if (dev->power.syscore || dev->power.direct_complete) | 1094 | if (dev->power.syscore || dev->power.direct_complete) |
1100 | goto Complete; | 1095 | goto Complete; |
1101 | 1096 | ||
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 84c41c98d6fc..f62082fdd670 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c | |||
@@ -28,8 +28,8 @@ bool events_check_enabled __read_mostly; | |||
28 | /* First wakeup IRQ seen by the kernel in the last cycle. */ | 28 | /* First wakeup IRQ seen by the kernel in the last cycle. */ |
29 | unsigned int pm_wakeup_irq __read_mostly; | 29 | unsigned int pm_wakeup_irq __read_mostly; |
30 | 30 | ||
31 | /* If set and the system is suspending, terminate the suspend. */ | 31 | /* If greater than 0 and the system is suspending, terminate the suspend. */ |
32 | static bool pm_abort_suspend __read_mostly; | 32 | static atomic_t pm_abort_suspend __read_mostly; |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Combined counters of registered wakeup events and wakeup events in progress. | 35 | * Combined counters of registered wakeup events and wakeup events in progress. |
@@ -856,20 +856,26 @@ bool pm_wakeup_pending(void) | |||
856 | pm_print_active_wakeup_sources(); | 856 | pm_print_active_wakeup_sources(); |
857 | } | 857 | } |
858 | 858 | ||
859 | return ret || pm_abort_suspend; | 859 | return ret || atomic_read(&pm_abort_suspend) > 0; |
860 | } | 860 | } |
861 | 861 | ||
862 | void pm_system_wakeup(void) | 862 | void pm_system_wakeup(void) |
863 | { | 863 | { |
864 | pm_abort_suspend = true; | 864 | atomic_inc(&pm_abort_suspend); |
865 | freeze_wake(); | 865 | freeze_wake(); |
866 | } | 866 | } |
867 | EXPORT_SYMBOL_GPL(pm_system_wakeup); | 867 | EXPORT_SYMBOL_GPL(pm_system_wakeup); |
868 | 868 | ||
869 | void pm_wakeup_clear(void) | 869 | void pm_system_cancel_wakeup(void) |
870 | { | ||
871 | atomic_dec(&pm_abort_suspend); | ||
872 | } | ||
873 | |||
874 | void pm_wakeup_clear(bool reset) | ||
870 | { | 875 | { |
871 | pm_abort_suspend = false; | ||
872 | pm_wakeup_irq = 0; | 876 | pm_wakeup_irq = 0; |
877 | if (reset) | ||
878 | atomic_set(&pm_abort_suspend, 0); | ||
873 | } | 879 | } |
874 | 880 | ||
875 | void pm_system_irq_wakeup(unsigned int irq_number) | 881 | void pm_system_irq_wakeup(unsigned int irq_number) |
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d9718378a8be..0b1cf32edfd7 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
@@ -189,6 +189,8 @@ struct platform_suspend_ops { | |||
189 | struct platform_freeze_ops { | 189 | struct platform_freeze_ops { |
190 | int (*begin)(void); | 190 | int (*begin)(void); |
191 | int (*prepare)(void); | 191 | int (*prepare)(void); |
192 | void (*wake)(void); | ||
193 | void (*sync)(void); | ||
192 | void (*restore)(void); | 194 | void (*restore)(void); |
193 | void (*end)(void); | 195 | void (*end)(void); |
194 | }; | 196 | }; |
@@ -428,7 +430,8 @@ extern unsigned int pm_wakeup_irq; | |||
428 | 430 | ||
429 | extern bool pm_wakeup_pending(void); | 431 | extern bool pm_wakeup_pending(void); |
430 | extern void pm_system_wakeup(void); | 432 | extern void pm_system_wakeup(void); |
431 | extern void pm_wakeup_clear(void); | 433 | extern void pm_system_cancel_wakeup(void); |
434 | extern void pm_wakeup_clear(bool reset); | ||
432 | extern void pm_system_irq_wakeup(unsigned int irq_number); | 435 | extern void pm_system_irq_wakeup(unsigned int irq_number); |
433 | extern bool pm_get_wakeup_count(unsigned int *count, bool block); | 436 | extern bool pm_get_wakeup_count(unsigned int *count, bool block); |
434 | extern bool pm_save_wakeup_count(unsigned int count); | 437 | extern bool pm_save_wakeup_count(unsigned int count); |
@@ -478,7 +481,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) | |||
478 | 481 | ||
479 | static inline bool pm_wakeup_pending(void) { return false; } | 482 | static inline bool pm_wakeup_pending(void) { return false; } |
480 | static inline void pm_system_wakeup(void) {} | 483 | static inline void pm_system_wakeup(void) {} |
481 | static inline void pm_wakeup_clear(void) {} | 484 | static inline void pm_wakeup_clear(bool reset) {} |
482 | static inline void pm_system_irq_wakeup(unsigned int irq_number) {} | 485 | static inline void pm_system_irq_wakeup(unsigned int irq_number) {} |
483 | 486 | ||
484 | static inline void lock_system_sleep(void) {} | 487 | static inline void lock_system_sleep(void) {} |
diff --git a/kernel/power/process.c b/kernel/power/process.c index c7209f060eeb..78672d324a6e 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -132,7 +132,7 @@ int freeze_processes(void) | |||
132 | if (!pm_freezing) | 132 | if (!pm_freezing) |
133 | atomic_inc(&system_freezing_cnt); | 133 | atomic_inc(&system_freezing_cnt); |
134 | 134 | ||
135 | pm_wakeup_clear(); | 135 | pm_wakeup_clear(true); |
136 | pr_info("Freezing user space processes ... "); | 136 | pr_info("Freezing user space processes ... "); |
137 | pm_freezing = true; | 137 | pm_freezing = true; |
138 | error = try_to_freeze_tasks(true); | 138 | error = try_to_freeze_tasks(true); |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 15e6baef5c73..c0248c74d6d4 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -72,6 +72,8 @@ static void freeze_begin(void) | |||
72 | 72 | ||
73 | static void freeze_enter(void) | 73 | static void freeze_enter(void) |
74 | { | 74 | { |
75 | trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, true); | ||
76 | |||
75 | spin_lock_irq(&suspend_freeze_lock); | 77 | spin_lock_irq(&suspend_freeze_lock); |
76 | if (pm_wakeup_pending()) | 78 | if (pm_wakeup_pending()) |
77 | goto out; | 79 | goto out; |
@@ -98,6 +100,27 @@ static void freeze_enter(void) | |||
98 | out: | 100 | out: |
99 | suspend_freeze_state = FREEZE_STATE_NONE; | 101 | suspend_freeze_state = FREEZE_STATE_NONE; |
100 | spin_unlock_irq(&suspend_freeze_lock); | 102 | spin_unlock_irq(&suspend_freeze_lock); |
103 | |||
104 | trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, false); | ||
105 | } | ||
106 | |||
107 | static void s2idle_loop(void) | ||
108 | { | ||
109 | do { | ||
110 | freeze_enter(); | ||
111 | |||
112 | if (freeze_ops && freeze_ops->wake) | ||
113 | freeze_ops->wake(); | ||
114 | |||
115 | dpm_resume_noirq(PMSG_RESUME); | ||
116 | if (freeze_ops && freeze_ops->sync) | ||
117 | freeze_ops->sync(); | ||
118 | |||
119 | if (pm_wakeup_pending()) | ||
120 | break; | ||
121 | |||
122 | pm_wakeup_clear(false); | ||
123 | } while (!dpm_suspend_noirq(PMSG_SUSPEND)); | ||
101 | } | 124 | } |
102 | 125 | ||
103 | void freeze_wake(void) | 126 | void freeze_wake(void) |
@@ -371,10 +394,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
371 | * all the devices are suspended. | 394 | * all the devices are suspended. |
372 | */ | 395 | */ |
373 | if (state == PM_SUSPEND_FREEZE) { | 396 | if (state == PM_SUSPEND_FREEZE) { |
374 | trace_suspend_resume(TPS("machine_suspend"), state, true); | 397 | s2idle_loop(); |
375 | freeze_enter(); | 398 | goto Platform_early_resume; |
376 | trace_suspend_resume(TPS("machine_suspend"), state, false); | ||
377 | goto Platform_wake; | ||
378 | } | 399 | } |
379 | 400 | ||
380 | error = disable_nonboot_cpus(); | 401 | error = disable_nonboot_cpus(); |