aboutsummaryrefslogtreecommitdiffstats
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.c9
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/sleep.c37
-rw-r--r--drivers/base/power/main.c5
-rw-r--r--drivers/base/power/wakeup.c18
-rw-r--r--include/acpi/acpi_bus.h6
-rw-r--r--include/linux/suspend.h7
-rw-r--r--kernel/power/process.c2
-rw-r--r--kernel/power/suspend.c35
11 files changed, 103 insertions, 25 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index d42eeef9d928..1cbb88d938e5 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -782,7 +782,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume)
782 if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || 782 if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
783 (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && 783 (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
784 (battery->capacity_now <= battery->alarm))) 784 (battery->capacity_now <= battery->alarm)))
785 pm_wakeup_event(&battery->device->dev, 0); 785 acpi_pm_wakeup_event(&battery->device->dev);
786 786
787 return result; 787 return result;
788} 788}
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index e19f530f1083..91cfdf377df7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -217,7 +217,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
217 } 217 }
218 218
219 if (state) 219 if (state)
220 pm_wakeup_event(&device->dev, 0); 220 acpi_pm_wakeup_event(&device->dev);
221 221
222 ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); 222 ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
223 if (ret == NOTIFY_DONE) 223 if (ret == NOTIFY_DONE)
@@ -402,7 +402,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
402 } else { 402 } else {
403 int keycode; 403 int keycode;
404 404
405 pm_wakeup_event(&device->dev, 0); 405 acpi_pm_wakeup_event(&device->dev);
406 if (button->suspended) 406 if (button->suspended)
407 break; 407 break;
408 408
@@ -534,6 +534,7 @@ static int acpi_button_add(struct acpi_device *device)
534 lid_device = device; 534 lid_device = device;
535 } 535 }
536 536
537 device_init_wakeup(&device->dev, true);
537 printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); 538 printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
538 return 0; 539 return 0;
539 540
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index f13c62c4b117..ca0210213773 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
@@ -385,6 +386,12 @@ EXPORT_SYMBOL(acpi_bus_power_manageable);
385#ifdef CONFIG_PM 386#ifdef CONFIG_PM
386static DEFINE_MUTEX(acpi_pm_notifier_lock); 387static DEFINE_MUTEX(acpi_pm_notifier_lock);
387 388
389void acpi_pm_wakeup_event(struct device *dev)
390{
391 pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup());
392}
393EXPORT_SYMBOL_GPL(acpi_pm_wakeup_event);
394
388static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) 395static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
389{ 396{
390 struct acpi_device *adev; 397 struct acpi_device *adev;
@@ -399,7 +406,7 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
399 mutex_lock(&acpi_pm_notifier_lock); 406 mutex_lock(&acpi_pm_notifier_lock);
400 407
401 if (adev->wakeup.flags.notifier_present) { 408 if (adev->wakeup.flags.notifier_present) {
402 __pm_wakeup_event(adev->wakeup.ws, 0); 409 pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
403 if (adev->wakeup.context.func) 410 if (adev->wakeup.context.func)
404 adev->wakeup.context.func(&adev->wakeup.context); 411 adev->wakeup.context.func(&adev->wakeup.context);
405 } 412 }
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 66229ffa909b..75924ea69071 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -198,8 +198,10 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
198 Suspend/Resume 198 Suspend/Resume
199 -------------------------------------------------------------------------- */ 199 -------------------------------------------------------------------------- */
200#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT 200#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT
201extern bool acpi_s2idle_wakeup(void);
201extern int acpi_sleep_init(void); 202extern int acpi_sleep_init(void);
202#else 203#else
204static inline bool acpi_s2idle_wakeup(void) { return false; }
203static inline int acpi_sleep_init(void) { return -ENXIO; } 205static inline int acpi_sleep_init(void) { return -ENXIO; }
204#endif 206#endif
205 207
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index a4782c75ebdd..555de11a56b6 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -650,6 +650,8 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
650 .recover = acpi_pm_finish, 650 .recover = acpi_pm_finish,
651}; 651};
652 652
653static bool s2idle_wakeup;
654
653static int acpi_freeze_begin(void) 655static int acpi_freeze_begin(void)
654{ 656{
655 acpi_scan_lock_acquire(); 657 acpi_scan_lock_acquire();
@@ -666,6 +668,33 @@ static int acpi_freeze_prepare(void)
666 return 0; 668 return 0;
667} 669}
668 670
671static void acpi_freeze_wake(void)
672{
673 /*
674 * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means
675 * that the SCI has triggered while suspended, so cancel the wakeup in
676 * case it has not been a wakeup event (the GPEs will be checked later).
677 */
678 if (acpi_sci_irq_valid() &&
679 !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) {
680 pm_system_cancel_wakeup();
681 s2idle_wakeup = true;
682 }
683}
684
685static void acpi_freeze_sync(void)
686{
687 /*
688 * Process all pending events in case there are any wakeup ones.
689 *
690 * The EC driver uses the system workqueue, so that one needs to be
691 * flushed too.
692 */
693 acpi_os_wait_events_complete();
694 flush_scheduled_work();
695 s2idle_wakeup = false;
696}
697
669static void acpi_freeze_restore(void) 698static void acpi_freeze_restore(void)
670{ 699{
671 if (acpi_sci_irq_valid()) 700 if (acpi_sci_irq_valid())
@@ -682,6 +711,8 @@ static void acpi_freeze_end(void)
682static const struct platform_freeze_ops acpi_freeze_ops = { 711static const struct platform_freeze_ops acpi_freeze_ops = {
683 .begin = acpi_freeze_begin, 712 .begin = acpi_freeze_begin,
684 .prepare = acpi_freeze_prepare, 713 .prepare = acpi_freeze_prepare,
714 .wake = acpi_freeze_wake,
715 .sync = acpi_freeze_sync,
685 .restore = acpi_freeze_restore, 716 .restore = acpi_freeze_restore,
686 .end = acpi_freeze_end, 717 .end = acpi_freeze_end,
687}; 718};
@@ -700,9 +731,15 @@ static void acpi_sleep_suspend_setup(void)
700} 731}
701 732
702#else /* !CONFIG_SUSPEND */ 733#else /* !CONFIG_SUSPEND */
734#define s2idle_wakeup (false)
703static inline void acpi_sleep_suspend_setup(void) {} 735static inline void acpi_sleep_suspend_setup(void) {}
704#endif /* !CONFIG_SUSPEND */ 736#endif /* !CONFIG_SUSPEND */
705 737
738bool acpi_s2idle_wakeup(void)
739{
740 return s2idle_wakeup;
741}
742
706#ifdef CONFIG_PM_SLEEP 743#ifdef CONFIG_PM_SLEEP
707static u32 saved_bm_rld; 744static u32 saved_bm_rld;
708 745
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 253f860e8981..ef5b6a6e5045 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1095,11 +1095,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
1095 if (async_error) 1095 if (async_error)
1096 goto Complete; 1096 goto Complete;
1097 1097
1098 if (pm_wakeup_pending()) {
1099 async_error = -EBUSY;
1100 goto Complete;
1101 }
1102
1103 if (dev->power.syscore || dev->power.direct_complete) 1098 if (dev->power.syscore || dev->power.direct_complete)
1104 goto Complete; 1099 goto Complete;
1105 1100
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index c313b600d356..9c36b27996fc 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.
@@ -855,20 +855,26 @@ bool pm_wakeup_pending(void)
855 pm_print_active_wakeup_sources(); 855 pm_print_active_wakeup_sources();
856 } 856 }
857 857
858 return ret || pm_abort_suspend; 858 return ret || atomic_read(&pm_abort_suspend) > 0;
859} 859}
860 860
861void pm_system_wakeup(void) 861void pm_system_wakeup(void)
862{ 862{
863 pm_abort_suspend = true; 863 atomic_inc(&pm_abort_suspend);
864 freeze_wake(); 864 freeze_wake();
865} 865}
866EXPORT_SYMBOL_GPL(pm_system_wakeup); 866EXPORT_SYMBOL_GPL(pm_system_wakeup);
867 867
868void pm_wakeup_clear(void) 868void pm_system_cancel_wakeup(void)
869{
870 atomic_dec(&pm_abort_suspend);
871}
872
873void pm_wakeup_clear(bool reset)
869{ 874{
870 pm_abort_suspend = false;
871 pm_wakeup_irq = 0; 875 pm_wakeup_irq = 0;
876 if (reset)
877 atomic_set(&pm_abort_suspend, 0);
872} 878}
873 879
874void pm_system_irq_wakeup(unsigned int irq_number) 880void pm_system_irq_wakeup(unsigned int irq_number)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 79c0af419300..63a90a624a0f 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -598,15 +598,19 @@ static inline bool acpi_device_always_present(struct acpi_device *adev)
598#endif 598#endif
599 599
600#ifdef CONFIG_PM 600#ifdef CONFIG_PM
601void acpi_pm_wakeup_event(struct device *dev);
601acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, 602acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
602 void (*func)(struct acpi_device_wakeup_context *context)); 603 void (*func)(struct acpi_device_wakeup_context *context));
603acpi_status acpi_remove_pm_notifier(struct acpi_device *adev); 604acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
604int acpi_pm_device_sleep_state(struct device *, int *, int); 605int acpi_pm_device_sleep_state(struct device *, int *, int);
605int acpi_pm_device_run_wake(struct device *, bool); 606int acpi_pm_device_run_wake(struct device *, bool);
606#else 607#else
608static inline void acpi_pm_wakeup_event(struct device *dev)
609{
610}
607static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev, 611static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
608 struct device *dev, 612 struct device *dev,
609 void (*work_func)(struct work_struct *work)) 613 void (*func)(struct acpi_device_wakeup_context *context))
610{ 614{
611 return AE_SUPPORT; 615 return AE_SUPPORT;
612} 616}
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..3ecf275d7e44 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;
@@ -84,11 +86,9 @@ static void freeze_enter(void)
84 86
85 /* Push all the CPUs into the idle loop. */ 87 /* Push all the CPUs into the idle loop. */
86 wake_up_all_idle_cpus(); 88 wake_up_all_idle_cpus();
87 pr_debug("PM: suspend-to-idle\n");
88 /* Make the current CPU wait so it can enter the idle loop too. */ 89 /* Make the current CPU wait so it can enter the idle loop too. */
89 wait_event(suspend_freeze_wait_head, 90 wait_event(suspend_freeze_wait_head,
90 suspend_freeze_state == FREEZE_STATE_WAKE); 91 suspend_freeze_state == FREEZE_STATE_WAKE);
91 pr_debug("PM: resume from suspend-to-idle\n");
92 92
93 cpuidle_pause(); 93 cpuidle_pause();
94 put_online_cpus(); 94 put_online_cpus();
@@ -98,6 +98,31 @@ static void freeze_enter(void)
98 out: 98 out:
99 suspend_freeze_state = FREEZE_STATE_NONE; 99 suspend_freeze_state = FREEZE_STATE_NONE;
100 spin_unlock_irq(&suspend_freeze_lock); 100 spin_unlock_irq(&suspend_freeze_lock);
101
102 trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, false);
103}
104
105static void s2idle_loop(void)
106{
107 pr_debug("PM: suspend-to-idle\n");
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));
124
125 pr_debug("PM: resume from suspend-to-idle\n");
101} 126}
102 127
103void freeze_wake(void) 128void freeze_wake(void)
@@ -371,10 +396,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
371 * all the devices are suspended. 396 * all the devices are suspended.
372 */ 397 */
373 if (state == PM_SUSPEND_FREEZE) { 398 if (state == PM_SUSPEND_FREEZE) {
374 trace_suspend_resume(TPS("machine_suspend"), state, true); 399 s2idle_loop();
375 freeze_enter(); 400 goto Platform_early_resume;
376 trace_suspend_resume(TPS("machine_suspend"), state, false);
377 goto Platform_wake;
378 } 401 }
379 402
380 error = disable_nonboot_cpus(); 403 error = disable_nonboot_cpus();