@@ -41,7 +41,7 @@
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/irqflags.h>
-
+#include <linux/suspend.h>
/*
* Include the apic definitions for x86 to have the APIC timer related
defines
* available also for UP (on SMP it gets magically included via
linux/smp.h).
@@ -221,10 +221,6 @@ static void lapic_timer_state_broadcast(struct
acpi_processor *pr,
#endif
-/*
- * Suspend / resume control
- */
-static int acpi_idle_suspend;
static u32 saved_bm_rld;
static void acpi_idle_bm_rld_save(void)
@@ -243,21 +239,13 @@ static void acpi_idle_bm_rld_restore(void)
int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
{
- if (acpi_idle_suspend == 1)
- return 0;
-
acpi_idle_bm_rld_save();
- acpi_idle_suspend = 1;
return 0;
}
int acpi_processor_resume(struct acpi_device * device)
{
- if (acpi_idle_suspend == 0)
- return 0;
-
acpi_idle_bm_rld_restore();
- acpi_idle_suspend = 0;
return 0;
}
@@ -763,7 +751,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device
*dev,
local_irq_disable();
- if (acpi_idle_suspend) {
+ if (in_suspend_path()) {
local_irq_enable();
cpu_relax();
return -EBUSY;
@@ -838,7 +826,7 @@ static int acpi_idle_enter_simple(struct
cpuidle_device *dev,
local_irq_disable();
- if (acpi_idle_suspend) {
+ if (in_suspend_path()) {
local_irq_enable();
cpu_relax();
return -EBUSY;
@@ -928,7 +916,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device
*dev,
drv, drv->safe_state_index);
} else {
local_irq_disable();
- if (!acpi_idle_suspend)
+ if (!(in_suspend_path()))
acpi_safe_halt();
local_irq_enable();
return -EBUSY;
@@ -937,7 +925,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device
*dev,
local_irq_disable();
- if (acpi_idle_suspend) {
+ if (in_suspend_path()) {
local_irq_enable();
cpu_relax();
return -EBUSY;
@@ -28,6 +28,9 @@
#include "internal.h"
#include "sleep.h"
+/* Suspend/Resume control */
+int idle_suspend;
+
u8 wake_sleep_flags = ACPI_NO_OPTIONAL_METHODS;
static unsigned int gts, bfs;
static int set_param_wake_flag(const char *val, struct kernel_param *kp)
@@ -904,6 +907,36 @@ static void __init acpi_gts_bfs_check(void)
"please notify linux-acpi@vger.kernel.org\n");
}
}
+/**
+ * cpuidle_pm_callback - On some bios, resume hangs
+ * if idle states are entered during suspend.
+ *
+ * acpi_idle_suspend is used by the x86 idle drivers
+ * to decide whether to go into idle states or not.
+ */
+static int
+cpuidle_pm_callback(struct notifier_block *nb,
+ unsigned long action, void *ptr)
+{
+ switch (action) {
+
+ case PM_SUSPEND_PREPARE:
+ if (idle_suspend == 0)
+ idle_suspend = 1;
+ break;
+
+ case PM_POST_SUSPEND:
+ if (idle_suspend == 1)
+ idle_suspend = 0;
+ break;
+
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
int __init acpi_sleep_init(void)
{
@@ -932,6 +965,7 @@ int __init acpi_sleep_init(void)
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
+ pm_notifier(cpuidle_pm_callback, 0);
#endif
#ifdef CONFIG_HIBERNATION
@@ -62,6 +62,7 @@
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/module.h>
+#include <linux/suspend.h>
#include <asm/cpu_device_id.h>
#include <asm/mwait.h>
#include <asm/msr.h>
@@ -254,6 +255,12 @@ static int intel_idle(struct cpuidle_device *dev,
cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
+ if (in_suspend_path()) {
+ local_irq_enable();
+ cpu_relax();
+ return -EBUSY;
+ }
+
/*
* leave_mm() to avoid costly and often unnecessary wakeups
* for flushing the user TLB's associated with the active mm.
@@ -38,6 +38,30 @@ typedef int __bitwise suspend_state_t;
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
+extern int idle_suspend;
+
+/**
+ * in_suspend_path - X86 idle drivers make a call
+ * to this function before entering idle states.
+ *
+ * Entering idle states is prevented if it is in suspend
+ * path.
+ */
+#ifdef CONFIG_ACPI
+static inline int in_suspend_path(void)
+{
+ if (idle_suspend == 1)
+ return 1;
+ else
+ return 0;
+}
+#else
+static inline int in_suspend_path(void)
+{
+ return 0;
+}
+#endif
+
enum suspend_stat_step {
SUSPEND_FREEZE = 1,
SUSPEND_PREPARE,