Patchwork ACPI: suspend: restore BM_RLD on resume

login
register
mail settings
Submitter Len Brown
Date May 8, 2009, 2:32 a.m.
Message ID <alpine.LFD.2.00.0905072228030.20287@localhost.localdomain>
Download mbox | patch
Permalink /patch/22499/
State Accepted
Headers show

Comments

Len Brown - May 8, 2009, 2:32 a.m.
From: Len Brown <len.brown@intel.com>

In 2.6.29,
31878dd86b7df9a147f5e6cc6e07092b4308782b
"ACPI: remove BM_RLD access from idle entry path"
moved BM_RLD initialization to init-time from run time.

But we discovered that some BIOS do not restore BM_RLD
after suspend, causing device errors on C3 and C4
after resume.  So now the kernel restores BM_RLD.

http://bugzilla.kernel.org/show_bug.cgi?id=13032

Signed-off-by: Len Brown <len.brown@intel.com>
---
 drivers/acpi/processor_idle.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)

Patch

diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f7ca8c5..afa5c03 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -202,15 +202,41 @@  static void acpi_state_timer_broadcast(struct acpi_processor *pr,
  * Suspend / resume control
  */
 static int acpi_idle_suspend;
+static u32 saved_bm_rld;
+
+static void acpi_idle_bm_rld_save(void)
+{
+	acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
+	printk(KERN_NOTICE PREFIX "saved: BM_RLD %u\n", saved_bm_rld);
+}
+static void acpi_idle_bm_rld_restore(void)
+{
+	u32 resumed_bm_rld;
+
+	acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
+	printk(KERN_NOTICE PREFIX "resumed: BM_RLD %u\n", resumed_bm_rld);
+	if (resumed_bm_rld != saved_bm_rld) {
+		printk(KERN_WARNING PREFIX "restored BM_RLD %u\n", saved_bm_rld);
+		acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
+	}
+}
 
 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;
 }