[Resend][PATCH -mm] Hibernation: Check if ACPI is enabled during restore in the right place

2007-09-12 Thread Rafael J. Wysocki
From: Rafael J. Wysocki <[EMAIL PROTECTED]>

The following scenario leads to total confusion of the platform firmware on
some boxes (eg. HPC nx6325):
* Hibernate with ACPI enabled
* Resume passing "acpi=off" to the boot kernel

To prevent this from happening it's necessary to check if ACPI is enabled (and
enable it if that's not the case) _right_ _after_ control has been transfered
from the boot kernel to the image kernel, before device_power_up() is called
(ie. with interrupts disabled).  Enabling ACPI after calling device_power_up()
turns out to be insufficient.

For this reason, introduce new hibernation callback ->leave() that will be
executed before device_power_up() by the restored image kernel.  To make it
work, it also is necessary to move swsusp_suspend() from swsusp.c to disk.c
(it's name is changed to "create_image", which is more up to the point).

Signed-off-by: Rafael J. Wysocki <[EMAIL PROTECTED]>
Acked-by: Pavel Machek <[EMAIL PROTECTED]>
---
 drivers/acpi/sleep/main.c |7 -
 include/linux/suspend.h   |7 +
 kernel/power/disk.c   |   58 +-
 kernel/power/power.h  |1 
 kernel/power/swsusp.c |   33 --
 5 files changed, 70 insertions(+), 36 deletions(-)

Index: linux-2.6.23-rc6/drivers/acpi/sleep/main.c
===
--- linux-2.6.23-rc6.orig/drivers/acpi/sleep/main.c
+++ linux-2.6.23-rc6/drivers/acpi/sleep/main.c
@@ -238,13 +238,17 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
-static void acpi_hibernation_finish(void)
+static void acpi_hibernation_leave(void)
 {
/*
 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 * enable it here.
 */
acpi_enable();
+}
+
+static void acpi_hibernation_finish(void)
+{
acpi_leave_sleep_state(ACPI_STATE_S4);
acpi_disable_wakeup_device(ACPI_STATE_S4);
 
@@ -274,6 +278,7 @@ static struct platform_hibernation_ops a
.finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
+   .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
 };
Index: linux-2.6.23-rc6/include/linux/suspend.h
===
--- linux-2.6.23-rc6.orig/include/linux/suspend.h
+++ linux-2.6.23-rc6/include/linux/suspend.h
@@ -156,6 +156,12 @@ extern void mark_free_pages(struct zone 
  * Called after the nonboot CPUs have been disabled and all of the low
  * level devices have been shut down (runs with IRQs off).
  *
+ * @leave: Perform the first stage of the cleanup after the system sleep state
+ * indicated by @set_target() has been left.
+ * Called right after the control has been passed from the boot kernel to
+ * the image kernel, before the nonboot CPUs are enabled and before devices
+ * are resumed.  Executed with interrupts disabled.
+ *
  * @pre_restore: Prepare system for the restoration from a hibernation image.
  * Called right after devices have been frozen and before the nonboot
  * CPUs are disabled (runs with IRQs on).
@@ -170,6 +176,7 @@ struct platform_hibernation_ops {
void (*finish)(void);
int (*prepare)(void);
int (*enter)(void);
+   void (*leave)(void);
int (*pre_restore)(void);
void (*restore_cleanup)(void);
 };
Index: linux-2.6.23-rc6/kernel/power/disk.c
===
--- linux-2.6.23-rc6.orig/kernel/power/disk.c
+++ linux-2.6.23-rc6/kernel/power/disk.c
@@ -93,6 +93,17 @@ static int platform_pre_snapshot(int pla
 }
 
 /**
+ * platform_leave - prepare the machine for switching to the normal mode
+ * of operation using the platform driver (called with interrupts disabled)
+ */
+
+static void platform_leave(int platform_mode)
+{
+   if (platform_mode && hibernation_ops)
+   hibernation_ops->leave();
+}
+
+/**
  * platform_finish - switch the machine to the normal mode of operation
  * using the platform driver (must be called after platform_prepare())
  */
@@ -129,6 +140,51 @@ static void platform_restore_cleanup(int
 }
 
 /**
+ * create_image - freeze devices that need to be frozen with interrupts
+ * off, create the hibernation image and thaw those devices.  Control
+ * reappears in this routine after a restore.
+ */
+
+int create_image(int platform_mode)
+{
+   int error;
+
+   error = arch_prepare_suspend();
+   if (error)
+   return error;
+
+   local_irq_disable();
+   /* At this point, device_suspend() has been called, but *not*
+* device_power_down(). We *must* call device_power_down() now.
+* Otherwise, drivers for some devices (e.g. interrupt controllers)
+  

[Resend][PATCH -mm] Hibernation: Check if ACPI is enabled during restore in the right place

2007-09-12 Thread Rafael J. Wysocki
From: Rafael J. Wysocki [EMAIL PROTECTED]

The following scenario leads to total confusion of the platform firmware on
some boxes (eg. HPC nx6325):
* Hibernate with ACPI enabled
* Resume passing acpi=off to the boot kernel

To prevent this from happening it's necessary to check if ACPI is enabled (and
enable it if that's not the case) _right_ _after_ control has been transfered
from the boot kernel to the image kernel, before device_power_up() is called
(ie. with interrupts disabled).  Enabling ACPI after calling device_power_up()
turns out to be insufficient.

For this reason, introduce new hibernation callback -leave() that will be
executed before device_power_up() by the restored image kernel.  To make it
work, it also is necessary to move swsusp_suspend() from swsusp.c to disk.c
(it's name is changed to create_image, which is more up to the point).

Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED]
Acked-by: Pavel Machek [EMAIL PROTECTED]
---
 drivers/acpi/sleep/main.c |7 -
 include/linux/suspend.h   |7 +
 kernel/power/disk.c   |   58 +-
 kernel/power/power.h  |1 
 kernel/power/swsusp.c |   33 --
 5 files changed, 70 insertions(+), 36 deletions(-)

Index: linux-2.6.23-rc6/drivers/acpi/sleep/main.c
===
--- linux-2.6.23-rc6.orig/drivers/acpi/sleep/main.c
+++ linux-2.6.23-rc6/drivers/acpi/sleep/main.c
@@ -238,13 +238,17 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
-static void acpi_hibernation_finish(void)
+static void acpi_hibernation_leave(void)
 {
/*
 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 * enable it here.
 */
acpi_enable();
+}
+
+static void acpi_hibernation_finish(void)
+{
acpi_leave_sleep_state(ACPI_STATE_S4);
acpi_disable_wakeup_device(ACPI_STATE_S4);
 
@@ -274,6 +278,7 @@ static struct platform_hibernation_ops a
.finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
+   .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
 };
Index: linux-2.6.23-rc6/include/linux/suspend.h
===
--- linux-2.6.23-rc6.orig/include/linux/suspend.h
+++ linux-2.6.23-rc6/include/linux/suspend.h
@@ -156,6 +156,12 @@ extern void mark_free_pages(struct zone 
  * Called after the nonboot CPUs have been disabled and all of the low
  * level devices have been shut down (runs with IRQs off).
  *
+ * @leave: Perform the first stage of the cleanup after the system sleep state
+ * indicated by @set_target() has been left.
+ * Called right after the control has been passed from the boot kernel to
+ * the image kernel, before the nonboot CPUs are enabled and before devices
+ * are resumed.  Executed with interrupts disabled.
+ *
  * @pre_restore: Prepare system for the restoration from a hibernation image.
  * Called right after devices have been frozen and before the nonboot
  * CPUs are disabled (runs with IRQs on).
@@ -170,6 +176,7 @@ struct platform_hibernation_ops {
void (*finish)(void);
int (*prepare)(void);
int (*enter)(void);
+   void (*leave)(void);
int (*pre_restore)(void);
void (*restore_cleanup)(void);
 };
Index: linux-2.6.23-rc6/kernel/power/disk.c
===
--- linux-2.6.23-rc6.orig/kernel/power/disk.c
+++ linux-2.6.23-rc6/kernel/power/disk.c
@@ -93,6 +93,17 @@ static int platform_pre_snapshot(int pla
 }
 
 /**
+ * platform_leave - prepare the machine for switching to the normal mode
+ * of operation using the platform driver (called with interrupts disabled)
+ */
+
+static void platform_leave(int platform_mode)
+{
+   if (platform_mode  hibernation_ops)
+   hibernation_ops-leave();
+}
+
+/**
  * platform_finish - switch the machine to the normal mode of operation
  * using the platform driver (must be called after platform_prepare())
  */
@@ -129,6 +140,51 @@ static void platform_restore_cleanup(int
 }
 
 /**
+ * create_image - freeze devices that need to be frozen with interrupts
+ * off, create the hibernation image and thaw those devices.  Control
+ * reappears in this routine after a restore.
+ */
+
+int create_image(int platform_mode)
+{
+   int error;
+
+   error = arch_prepare_suspend();
+   if (error)
+   return error;
+
+   local_irq_disable();
+   /* At this point, device_suspend() has been called, but *not*
+* device_power_down(). We *must* call device_power_down() now.
+* Otherwise, drivers for some devices (e.g. interrupt controllers)
+* 

Re: [PATCH -mm] Hibernation: Check if ACPI is enabled during restore in the right place

2007-09-06 Thread Pavel Machek
On Sun 2007-09-02 00:21:37, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[EMAIL PROTECTED]>
> 
> The following scenario leads to total confusion of the platform firmware on
> some boxes (eg. HPC nx6325):
> * Hibernate with ACPI enabled
> * Pass "acpi=off" to the boot kernel
> 
> To prevent this from happening it's necessary to check if ACPI is enabled (and
> enable it if that's not the case) _right_ _after_ control has been transfered
> from the boot kernel to the image kernel, before device_power_up() is called
> (ie. with interrupts disabled).  Enabling ACPI after calling device_power_up()
> turns out to be insufficient.
> 
> For this reason, introduce new hibernation callback ->leave() that will be
> executed before device_power_up() by the restored image kernel.  To make it
> work, it also is necessary to move swsusp_suspend() from swsusp.c to disk.c
> (it's name is changed to "create_image", which is more up to the point).
> 
> Signed-off-by: Rafael J. Wysocki <[EMAIL PROTECTED]>

ACK.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) 
http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH -mm] Hibernation: Check if ACPI is enabled during restore in the right place

2007-09-01 Thread Rafael J. Wysocki
From: Rafael J. Wysocki <[EMAIL PROTECTED]>

The following scenario leads to total confusion of the platform firmware on
some boxes (eg. HPC nx6325):
* Hibernate with ACPI enabled
* Pass "acpi=off" to the boot kernel

To prevent this from happening it's necessary to check if ACPI is enabled (and
enable it if that's not the case) _right_ _after_ control has been transfered
from the boot kernel to the image kernel, before device_power_up() is called
(ie. with interrupts disabled).  Enabling ACPI after calling device_power_up()
turns out to be insufficient.

For this reason, introduce new hibernation callback ->leave() that will be
executed before device_power_up() by the restored image kernel.  To make it
work, it also is necessary to move swsusp_suspend() from swsusp.c to disk.c
(it's name is changed to "create_image", which is more up to the point).

Signed-off-by: Rafael J. Wysocki <[EMAIL PROTECTED]>
---
 drivers/acpi/sleep/main.c |7 -
 include/linux/suspend.h   |7 +
 kernel/power/disk.c   |   58 +-
 kernel/power/power.h  |1 
 kernel/power/swsusp.c |   33 --
 5 files changed, 70 insertions(+), 36 deletions(-)

Index: linux-2.6.23-rc4-mm1/drivers/acpi/sleep/main.c
===
--- linux-2.6.23-rc4-mm1.orig/drivers/acpi/sleep/main.c
+++ linux-2.6.23-rc4-mm1/drivers/acpi/sleep/main.c
@@ -231,13 +231,17 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
-static void acpi_hibernation_finish(void)
+static void acpi_hibernation_leave(void)
 {
/*
 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 * enable it here.
 */
acpi_enable();
+}
+
+static void acpi_hibernation_finish(void)
+{
acpi_leave_sleep_state(ACPI_STATE_S4);
acpi_disable_wakeup_device(ACPI_STATE_S4);
 
@@ -267,6 +271,7 @@ static struct platform_hibernation_ops a
.finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
+   .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
 };
Index: linux-2.6.23-rc4-mm1/include/linux/suspend.h
===
--- linux-2.6.23-rc4-mm1.orig/include/linux/suspend.h
+++ linux-2.6.23-rc4-mm1/include/linux/suspend.h
@@ -156,6 +156,12 @@ extern void mark_free_pages(struct zone 
  * Called after the nonboot CPUs have been disabled and all of the low
  * level devices have been shut down (runs with IRQs off).
  *
+ * @leave: Perform the first stage of the cleanup after the system sleep state
+ * indicated by @set_target() has been left.
+ * Called right after the control has been passed from the boot kernel to
+ * the image kernel, before the nonboot CPUs are enabled and before devices
+ * are resumed.  Executed with interrupts disabled.
+ *
  * @pre_restore: Prepare system for the restoration from a hibernation image.
  * Called right after devices have been frozen and before the nonboot
  * CPUs are disabled (runs with IRQs on).
@@ -170,6 +176,7 @@ struct platform_hibernation_ops {
void (*finish)(void);
int (*prepare)(void);
int (*enter)(void);
+   void (*leave)(void);
int (*pre_restore)(void);
void (*restore_cleanup)(void);
 };
Index: linux-2.6.23-rc4-mm1/kernel/power/disk.c
===
--- linux-2.6.23-rc4-mm1.orig/kernel/power/disk.c
+++ linux-2.6.23-rc4-mm1/kernel/power/disk.c
@@ -93,6 +93,17 @@ static int platform_pre_snapshot(int pla
 }
 
 /**
+ * platform_leave - prepare the machine for switching to the normal mode
+ * of operation using the platform driver (called with interrupts disabled)
+ */
+
+static void platform_leave(int platform_mode)
+{
+   if (platform_mode && hibernation_ops)
+   hibernation_ops->leave();
+}
+
+/**
  * platform_finish - switch the machine to the normal mode of operation
  * using the platform driver (must be called after platform_prepare())
  */
@@ -129,6 +140,51 @@ static void platform_restore_cleanup(int
 }
 
 /**
+ * create_image - freeze devices that need to be frozen with interrupts
+ * off, create the hibernation image and thaw those devices.  Control
+ * reappears in this routine after a restore.
+ */
+
+int create_image(int platform_mode)
+{
+   int error;
+
+   error = arch_prepare_suspend();
+   if (error)
+   return error;
+
+   local_irq_disable();
+   /* At this point, device_suspend() has been called, but *not*
+* device_power_down(). We *must* call device_power_down() now.
+* Otherwise, drivers for some devices (e.g. interrupt controllers)
+* become 

[PATCH -mm] Hibernation: Check if ACPI is enabled during restore in the right place

2007-09-01 Thread Rafael J. Wysocki
From: Rafael J. Wysocki [EMAIL PROTECTED]

The following scenario leads to total confusion of the platform firmware on
some boxes (eg. HPC nx6325):
* Hibernate with ACPI enabled
* Pass acpi=off to the boot kernel

To prevent this from happening it's necessary to check if ACPI is enabled (and
enable it if that's not the case) _right_ _after_ control has been transfered
from the boot kernel to the image kernel, before device_power_up() is called
(ie. with interrupts disabled).  Enabling ACPI after calling device_power_up()
turns out to be insufficient.

For this reason, introduce new hibernation callback -leave() that will be
executed before device_power_up() by the restored image kernel.  To make it
work, it also is necessary to move swsusp_suspend() from swsusp.c to disk.c
(it's name is changed to create_image, which is more up to the point).

Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED]
---
 drivers/acpi/sleep/main.c |7 -
 include/linux/suspend.h   |7 +
 kernel/power/disk.c   |   58 +-
 kernel/power/power.h  |1 
 kernel/power/swsusp.c |   33 --
 5 files changed, 70 insertions(+), 36 deletions(-)

Index: linux-2.6.23-rc4-mm1/drivers/acpi/sleep/main.c
===
--- linux-2.6.23-rc4-mm1.orig/drivers/acpi/sleep/main.c
+++ linux-2.6.23-rc4-mm1/drivers/acpi/sleep/main.c
@@ -231,13 +231,17 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
-static void acpi_hibernation_finish(void)
+static void acpi_hibernation_leave(void)
 {
/*
 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 * enable it here.
 */
acpi_enable();
+}
+
+static void acpi_hibernation_finish(void)
+{
acpi_leave_sleep_state(ACPI_STATE_S4);
acpi_disable_wakeup_device(ACPI_STATE_S4);
 
@@ -267,6 +271,7 @@ static struct platform_hibernation_ops a
.finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
+   .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
 };
Index: linux-2.6.23-rc4-mm1/include/linux/suspend.h
===
--- linux-2.6.23-rc4-mm1.orig/include/linux/suspend.h
+++ linux-2.6.23-rc4-mm1/include/linux/suspend.h
@@ -156,6 +156,12 @@ extern void mark_free_pages(struct zone 
  * Called after the nonboot CPUs have been disabled and all of the low
  * level devices have been shut down (runs with IRQs off).
  *
+ * @leave: Perform the first stage of the cleanup after the system sleep state
+ * indicated by @set_target() has been left.
+ * Called right after the control has been passed from the boot kernel to
+ * the image kernel, before the nonboot CPUs are enabled and before devices
+ * are resumed.  Executed with interrupts disabled.
+ *
  * @pre_restore: Prepare system for the restoration from a hibernation image.
  * Called right after devices have been frozen and before the nonboot
  * CPUs are disabled (runs with IRQs on).
@@ -170,6 +176,7 @@ struct platform_hibernation_ops {
void (*finish)(void);
int (*prepare)(void);
int (*enter)(void);
+   void (*leave)(void);
int (*pre_restore)(void);
void (*restore_cleanup)(void);
 };
Index: linux-2.6.23-rc4-mm1/kernel/power/disk.c
===
--- linux-2.6.23-rc4-mm1.orig/kernel/power/disk.c
+++ linux-2.6.23-rc4-mm1/kernel/power/disk.c
@@ -93,6 +93,17 @@ static int platform_pre_snapshot(int pla
 }
 
 /**
+ * platform_leave - prepare the machine for switching to the normal mode
+ * of operation using the platform driver (called with interrupts disabled)
+ */
+
+static void platform_leave(int platform_mode)
+{
+   if (platform_mode  hibernation_ops)
+   hibernation_ops-leave();
+}
+
+/**
  * platform_finish - switch the machine to the normal mode of operation
  * using the platform driver (must be called after platform_prepare())
  */
@@ -129,6 +140,51 @@ static void platform_restore_cleanup(int
 }
 
 /**
+ * create_image - freeze devices that need to be frozen with interrupts
+ * off, create the hibernation image and thaw those devices.  Control
+ * reappears in this routine after a restore.
+ */
+
+int create_image(int platform_mode)
+{
+   int error;
+
+   error = arch_prepare_suspend();
+   if (error)
+   return error;
+
+   local_irq_disable();
+   /* At this point, device_suspend() has been called, but *not*
+* device_power_down(). We *must* call device_power_down() now.
+* Otherwise, drivers for some devices (e.g. interrupt controllers)
+* become