Use the RTC cmos area to track where suspend/resume hangs --- arch/x86/kernel/acpi/realmode/wakemain.c | 22 ++++++++ drivers/acpi/proc.c | 81 +++++++++++++++++++++++++++++++ drivers/acpi/sleep.c | 27 +++++++++- 3 files changed, 129 insertions(+), 1 deletion(-) Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/acpi/realmode/wakemain.c 2009-04-03 09:16:16.000000000 +0800 +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakemain.c 2009-04-03 09:17:24.000000000 +0800 @@ -1,5 +1,26 @@ #include "wakeup.h" #include "boot.h" +static void rtc_cmos_write(char value, unsigned char port) +{ + outb(port, 0x70); + io_delay(); + outb(value, 0x71); + io_delay(); +} +static void acpi_pm_write_timer(u32 timer) +{ +#define M_TIME 0x61 + u32 value; + value = timer & 0xff; + rtc_cmos_write(value, M_TIME); + value = (timer >> 8) & 0xff; + rtc_cmos_write(value, M_TIME + 1); + value = (timer >> 16) & 0xff; + rtc_cmos_write(value, M_TIME + 2); + value = (timer >> 24) & 0xff; + rtc_cmos_write(value, M_TIME + 3); + return; +} static void udelay(int loops) { @@ -63,6 +84,7 @@ void main(void) { + acpi_pm_write_timer(0x8A8A8A8A); /* Kill machine if structures are wrong */ if (wakeup_header.real_magic != 0x12345678) while (1); Index: linux-2.6/drivers/acpi/proc.c =================================================================== --- linux-2.6.orig/drivers/acpi/proc.c 2009-04-03 09:16:16.000000000 +0800 +++ linux-2.6/drivers/acpi/proc.c 2009-04-03 09:17:24.000000000 +0800 @@ -495,7 +495,86 @@ return ACPI_INTERRUPT_HANDLED; } #endif /* HAVE_ACPI_LEGACY_ALARM */ +#define CMOS_COUNT 0x60 +#define CMOS_TIME 0x61 +static ssize_t +acpi_cmos_read(struct file *file, + char __user *buffer, size_t count, loff_t *ppos) +{ + int result = 0; + unsigned long p = *ppos; + int mcount; + char alarm_string[30] = { '\0' }; + int mjiffies = 0; + + if (count < sizeof(alarm_string)) + return 0; + if (p >= sizeof(alarm_string)) + return 0; + + spin_lock_irq(&rtc_lock); + + mcount = CMOS_READ(CMOS_COUNT); + result = CMOS_READ(CMOS_TIME); + mjiffies = result; + result = CMOS_READ(CMOS_TIME + 1); + mjiffies += (result << 8); + result = CMOS_READ(CMOS_TIME + 2); + mjiffies += (result << 16); + result = CMOS_READ(CMOS_TIME + 3); + mjiffies += (result << 24); + spin_unlock_irq(&rtc_lock); + sprintf(alarm_string, "mcount=%d, time=%x\n", + mcount, mjiffies); + printk(KERN_DEBUG "alarm_string is %s\n", + alarm_string); + result = min(sizeof(alarm_string), count); + if (copy_to_user(buffer, alarm_string, result)) { + printk(KERN_DEBUG "Copy fail\n"); + return -EINVAL; + } + *ppos += result; + return result; +} +static ssize_t +acpi_cmos_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + int result = 0; + int mcount; + char alarm_string[30] = { '\0' }; + + if (count > sizeof(alarm_string)) + return 0; + if (copy_from_user(alarm_string, buffer, count)) + return 0; + + sscanf(alarm_string, "%d\n", &mcount); + + spin_lock_irq(&rtc_lock); + + CMOS_WRITE(mcount&0xff, CMOS_COUNT); + CMOS_WRITE(0xAA, CMOS_TIME); + CMOS_WRITE(0xAA, CMOS_TIME + 1); + CMOS_WRITE(0xAA, CMOS_TIME + 2); + CMOS_WRITE(0xAA, CMOS_TIME + 3); + + spin_unlock_irq(&rtc_lock); + + + *ppos += count; + printk(KERN_DEBUG "cmos write count is %d\n", + mcount); + + result = 0; + return count; +} +static const struct file_operations acpi_cmos_fops = { + .owner = THIS_MODULE, + .read = acpi_cmos_read, + .write = acpi_cmos_write, +}; static int __init acpi_sleep_proc_init(void) { if (acpi_disabled) @@ -525,6 +604,8 @@ proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR, acpi_root_dir, &acpi_system_wakeup_device_fops); + proc_create("cmos", S_IRUGO | S_IWUSR, NULL, + &acpi_cmos_fops); return 0; } Index: linux-2.6/drivers/acpi/sleep.c =================================================================== --- linux-2.6.orig/drivers/acpi/sleep.c 2009-04-03 09:16:16.000000000 +0800 +++ linux-2.6/drivers/acpi/sleep.c 2009-04-03 09:17:24.000000000 +0800 @@ -22,8 +22,27 @@ #include #include #include "sleep.h" +#include u8 sleep_states[ACPI_S_STATE_COUNT]; +static void acpi_pm_write_timer(u32 timer) +{ +#define M_TIME 0x61 + u32 value; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); + value = timer & 0xff; + CMOS_WRITE(value, M_TIME); + value = (timer >> 8) & 0xff; + CMOS_WRITE(value, M_TIME + 1); + value = (timer >> 16) & 0xff; + CMOS_WRITE(value, M_TIME + 2); + value = (timer >> 24) & 0xff; + CMOS_WRITE(value, M_TIME + 3); + + spin_unlock_irqrestore(&rtc_lock, flags); + return; +} static void acpi_sleep_tts_switch(u32 acpi_state) { @@ -235,6 +254,10 @@ local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); + { + unsigned long mjiffies = jiffies + 5; + acpi_pm_write_timer(mjiffies); + } switch (acpi_state) { case ACPI_STATE_S1: barrier(); @@ -245,7 +268,9 @@ do_suspend_lowlevel(); break; } - + { + acpi_pm_write_timer(0xB8B8B8B8); + } /* If ACPI is not enabled by the BIOS, we need to enable it here. */ if (set_sci_en_on_resume) acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);