summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/battery.c2
-rw-r--r--drivers/acpi/button.c5
-rw-r--r--drivers/acpi/device_pm.c3
-rw-r--r--drivers/acpi/sleep.c28
-rw-r--r--drivers/base/power/main.c5
-rw-r--r--drivers/base/power/wakeup.c18
-rw-r--r--include/linux/suspend.h7
-rw-r--r--kernel/power/process.c2
-rw-r--r--kernel/power/suspend.c29
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
669static 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
681static 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
668static void acpi_freeze_restore(void) 693static 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)
681static const struct platform_freeze_ops acpi_freeze_ops = { 707static 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. */
29unsigned int pm_wakeup_irq __read_mostly; 29unsigned 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. */
32static bool pm_abort_suspend __read_mostly; 32static 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
862void pm_system_wakeup(void) 862void 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}
867EXPORT_SYMBOL_GPL(pm_system_wakeup); 867EXPORT_SYMBOL_GPL(pm_system_wakeup);
868 868
869void pm_wakeup_clear(void) 869void pm_system_cancel_wakeup(void)
870{
871 atomic_dec(&pm_abort_suspend);
872}
873
874void 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
875void pm_system_irq_wakeup(unsigned int irq_number) 881void 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 {
189struct platform_freeze_ops { 189struct 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
429extern bool pm_wakeup_pending(void); 431extern bool pm_wakeup_pending(void);
430extern void pm_system_wakeup(void); 432extern void pm_system_wakeup(void);
431extern void pm_wakeup_clear(void); 433extern void pm_system_cancel_wakeup(void);
434extern void pm_wakeup_clear(bool reset);
432extern void pm_system_irq_wakeup(unsigned int irq_number); 435extern void pm_system_irq_wakeup(unsigned int irq_number);
433extern bool pm_get_wakeup_count(unsigned int *count, bool block); 436extern bool pm_get_wakeup_count(unsigned int *count, bool block);
434extern bool pm_save_wakeup_count(unsigned int count); 437extern bool pm_save_wakeup_count(unsigned int count);
@@ -478,7 +481,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
478 481
479static inline bool pm_wakeup_pending(void) { return false; } 482static inline bool pm_wakeup_pending(void) { return false; }
480static inline void pm_system_wakeup(void) {} 483static inline void pm_system_wakeup(void) {}
481static inline void pm_wakeup_clear(void) {} 484static inline void pm_wakeup_clear(bool reset) {}
482static inline void pm_system_irq_wakeup(unsigned int irq_number) {} 485static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
483 486
484static inline void lock_system_sleep(void) {} 487static 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
73static void freeze_enter(void) 73static 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
107static 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
103void freeze_wake(void) 126void 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();