]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/acpi/sleep.c
Suspend-related patches for 2.6.27
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / acpi / sleep.c
index 6bc815cd8cb32e219dd9bdf14fbd13cb717253ea..882e970032d5c8054df337b35b1bbd7dfe65a3d8 100644 (file)
 #include <linux/dmi.h>
 #include <linux/cpumask.h>
 
-#include <asm/smp.h>
+#include "realmode/wakeup.h"
+#include "sleep.h"
 
-/* address in low memory of the wakeup routine. */
-unsigned long acpi_wakeup_address = 0;
+unsigned long acpi_wakeup_address;
 unsigned long acpi_realmode_flags;
-extern char wakeup_start, wakeup_end;
 
-extern unsigned long acpi_copy_wakeup_routine(unsigned long);
+/* address in low memory of the wakeup routine. */
+static unsigned long acpi_realmode;
+
+#ifdef CONFIG_64BIT
+static char temp_stack[10240];
+#endif
 
 /**
  * acpi_save_state_mem - save kernel state
  *
  * Create an identity mapped page table and copy the wakeup routine to
  * low memory.
+ *
+ * Note that this is too late to change acpi_wakeup_address.
  */
 int acpi_save_state_mem(void)
 {
-       if (!acpi_wakeup_address) {
-               printk(KERN_ERR "Could not allocate memory during boot, S3 disabled\n");
+       struct wakeup_header *header;
+
+       if (!acpi_realmode) {
+               printk(KERN_ERR "Could not allocate memory during boot, "
+                      "S3 disabled\n");
                return -ENOMEM;
        }
-       memcpy((void *)acpi_wakeup_address, &wakeup_start,
-              &wakeup_end - &wakeup_start);
-       acpi_copy_wakeup_routine(acpi_wakeup_address);
+       memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE);
+
+       header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET);
+       if (header->signature != 0x51ee1111) {
+               printk(KERN_ERR "wakeup header does not match\n");
+               return -EINVAL;
+       }
+
+       header->video_mode = saved_video_mode;
+
+#ifndef CONFIG_64BIT
+       store_gdt((struct desc_ptr *)&header->pmode_gdt);
+
+       header->pmode_efer_low = nx_enabled;
+       if (header->pmode_efer_low & 1) {
+               /* This is strange, why not save efer, always? */
+               rdmsr(MSR_EFER, header->pmode_efer_low,
+                       header->pmode_efer_high);
+       }
+#endif /* !CONFIG_64BIT */
+
+       header->pmode_cr0 = read_cr0();
+       header->pmode_cr4 = read_cr4();
+       header->realmode_flags = acpi_realmode_flags;
+       header->real_magic = 0x12345678;
+
+#ifndef CONFIG_64BIT
+       header->pmode_entry = (u32)&wakeup_pmode_return;
+       header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET);
+       saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */
+       header->trampoline_segment = setup_trampoline() >> 4;
+       init_rsp = (unsigned long)temp_stack + 4096;
+       initial_code = (unsigned long)wakeup_long64;
+       saved_magic = 0x123456789abcdef0;
+#endif /* CONFIG_64BIT */
 
        return 0;
 }
@@ -56,15 +98,20 @@ void acpi_restore_state_mem(void)
  */
 void __init acpi_reserve_bootmem(void)
 {
-       if ((&wakeup_end - &wakeup_start) > PAGE_SIZE*2) {
+       if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
                printk(KERN_ERR
                       "ACPI: Wakeup code way too big, S3 disabled.\n");
                return;
        }
 
-       acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2);
-       if (!acpi_wakeup_address)
+       acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE);
+
+       if (!acpi_realmode) {
                printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
+               return;
+       }
+
+       acpi_wakeup_address = acpi_realmode;
 }
 
 
@@ -77,6 +124,8 @@ static int __init acpi_sleep_setup(char *str)
                        acpi_realmode_flags |= 2;
                if (strncmp(str, "s3_beep", 7) == 0)
                        acpi_realmode_flags |= 4;
+               if (strncmp(str, "old_ordering", 12) == 0)
+                       acpi_old_suspend_ordering();
                str = strchr(str, ',');
                if (str != NULL)
                        str += strspn(str, ", \t");