Merge branches 'release', 'misc' and 'misc-2.6.25' into release
authorLen Brown <len.brown@intel.com>
Thu, 7 Feb 2008 08:13:13 +0000 (03:13 -0500)
committerLen Brown <len.brown@intel.com>
Thu, 7 Feb 2008 08:13:13 +0000 (03:13 -0500)
1  2  3 
arch/ia64/kernel/acpi.c
arch/x86/kernel/acpi/boot.c
drivers/acpi/osl.c
drivers/acpi/sleep/main.c

diff --combined arch/ia64/kernel/acpi.c
@@@@ -69,20 -69,6 -69,6 +69,20 @@@@ unsigned int acpi_cpei_phys_cpuid
   
   unsigned long acpi_wakeup_address = 0;
   
 ++#ifdef CONFIG_IA64_GENERIC
 ++static unsigned long __init acpi_find_rsdp(void)
 ++{
 ++     unsigned long rsdp_phys = 0;
 ++
 ++     if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
 ++             rsdp_phys = efi.acpi20;
 ++     else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
 ++             printk(KERN_WARNING PREFIX
 ++                    "v1.0/r0.71 tables no longer supported\n");
 ++     return rsdp_phys;
 ++}
 ++#endif
 ++
   const char __init *
   acpi_get_sysname(void)
   {
@@@@ -166,7 -152,7 -152,7 +166,7 @@@@ int acpi_request_vector(u32 int_type
        return vector;
   }
   
- -char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+ +char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
   {
        return __va(phys_addr);
   }
@@@@ -645,6 -631,18 -631,18 +645,6 @@@@ static int __init acpi_parse_fadt(struc
        return 0;
   }
   
 --unsigned long __init acpi_find_rsdp(void)
 --{
 --     unsigned long rsdp_phys = 0;
 --
 --     if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
 --             rsdp_phys = efi.acpi20;
 --     else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
 --             printk(KERN_WARNING PREFIX
 --                    "v1.0/r0.71 tables no longer supported\n");
 --     return rsdp_phys;
 --}
 --
   int __init acpi_boot_init(void)
   {
   
@@@@ -106,7 -106,7 -106,7 +106,7 @@@@ enum acpi_irq_model_id acpi_irq_model 
   #ifdef       CONFIG_X86_64
   
   /* rely on all ACPI tables being in the direct mapping */
- -char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+ +char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
   {
        if (!phys_addr || !size)
                return NULL;
    * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
    * count idx down while incrementing the phys address.
    */
- -char *__acpi_map_table(unsigned long phys, unsigned long size)
+ +char *__init __acpi_map_table(unsigned long phys, unsigned long size)
   {
        unsigned long base, offset, mapped_size;
        int idx;
@@@@ -496,8 -496,7 -496,8 +496,8 @@@@ EXPORT_SYMBOL(acpi_register_gsi)
    *  ACPI based hotplug support for CPU
    */
   #ifdef CONFIG_ACPI_HOTPLUG_CPU
 - int acpi_map_lsapic(acpi_handle handle, int *pcpu)
 + 
 + static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
   {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
        return 0;
   }
   
 + /* wrapper to silence section mismatch warning */
 + int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
 + {
 +      return _acpi_map_lsapic(handle, pcpu);
 + }
   EXPORT_SYMBOL(acpi_map_lsapic);
   
   int acpi_unmap_lsapic(int cpu)
@@@@ -587,6 -581,25 -587,25 +587,6 @@@@ int acpi_unregister_ioapic(acpi_handle 
   
   EXPORT_SYMBOL(acpi_unregister_ioapic);
   
 --static unsigned long __init
 --acpi_scan_rsdp(unsigned long start, unsigned long length)
 --{
 --     unsigned long offset = 0;
 --     unsigned long sig_len = sizeof("RSD PTR ") - 1;
 --
 --     /*
 --      * Scan all 16-byte boundaries of the physical memory region for the
 --      * RSDP signature.
 --      */
 --     for (offset = 0; offset < length; offset += 16) {
 --             if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
 --                     continue;
 --             return (start + offset);
 --     }
 --
 --     return 0;
 --}
 --
   static int __init acpi_parse_sbf(struct acpi_table_header *table)
   {
        struct acpi_table_boot *sb;
@@@@ -729,6 -742,27 -748,27 +729,6 @@@@ static int __init acpi_parse_fadt(struc
        return 0;
   }
   
 --unsigned long __init acpi_find_rsdp(void)
 --{
 --     unsigned long rsdp_phys = 0;
 --
 --     if (efi_enabled) {
 --             if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
 --                     return efi.acpi20;
 --             else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
 --                     return efi.acpi;
 --     }
 --     /*
 --      * Scan memory looking for the RSDP signature. First search EBDA (low
 --      * memory) paragraphs and then search upper memory (E0000-FFFFF).
 --      */
 --     rsdp_phys = acpi_scan_rsdp(0, 0x400);
 --     if (!rsdp_phys)
 --             rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
 --
 --     return rsdp_phys;
 --}
 --
   #ifdef       CONFIG_X86_LOCAL_APIC
   /*
    * Parse LAPIC entries in MADT
diff --combined drivers/acpi/osl.c
@@@@ -77,55 -77,11 -77,55 +77,55 @@@@ static struct workqueue_struct *kacpi_n
   #define      OSI_STRING_LENGTH_MAX 64        /* arbitrary */
   static char osi_additional_string[OSI_STRING_LENGTH_MAX];
   
 - static int osi_linux;                /* disable _OSI(Linux) by default */
 + /*
 +  * "Ode to _OSI(Linux)"
 +  *
 +  * osi_linux -- Control response to BIOS _OSI(Linux) query.
 +  *
 +  * As Linux evolves, the features that it supports change.
 +  * So an OSI string such as "Linux" is not specific enough
 +  * to be useful across multiple versions of Linux.  It
 +  * doesn't identify any particular feature, interface,
 +  * or even any particular version of Linux...
 +  *
 +  * Unfortunately, Linux-2.6.22 and earlier responded "yes"
 +  * to a BIOS _OSI(Linux) query.  When
 +  * a reference mobile BIOS started using it, its use
 +  * started to spread to many vendor platforms.
 +  * As it is not supportable, we need to halt that spread.
 +  *
 +  * Today, most BIOS references to _OSI(Linux) are noise --
 +  * they have no functional effect and are just dead code
 +  * carried over from the reference BIOS.
 +  *
 +  * The next most common case is that _OSI(Linux) harms Linux,
 +  * usually by causing the BIOS to follow paths that are
 +  * not tested during Windows validation.
 +  *
 +  * Finally, there is a short list of platforms
 +  * where OSI(Linux) benefits Linux.
 +  *
 +  * In Linux-2.6.23, OSI(Linux) is first disabled by default.
 +  * DMI is used to disable the dmesg warning about OSI(Linux)
 +  * on platforms where it is known to have no effect.
 +  * But a dmesg warning remains for systems where
 +  * we do not know if OSI(Linux) is good or bad for the system.
 +  * DMI is also used to enable OSI(Linux) for the machines
 +  * that are known to need it.
 +  *
 +  * BIOS writers should NOT query _OSI(Linux) on future systems.
 +  * It will be ignored by default, and to get Linux to
 +  * not ignore it will require a kernel source update to
 +  * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation.
 +  */
 + #define OSI_LINUX_ENABLE 0
   
 - #ifdef CONFIG_DMI
 - static struct __initdata dmi_system_id acpi_osl_dmi_table[];
 - #endif
  -struct osi_linux {
 ++static struct osi_linux {
 +      unsigned int    enable:1;
 +      unsigned int    dmi:1;
 +      unsigned int    cmdline:1;
 +      unsigned int    known:1;
 + } osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0};
   
   static void __init acpi_request_region (struct acpi_generic_address *addr,
        unsigned int length, char *desc)
@@@@ -177,6 -133,7 -177,6 +177,6 @@@@ device_initcall(acpi_reserve_resources)
   
   acpi_status __init acpi_os_initialize(void)
   {
 -      dmi_check_system(acpi_osl_dmi_table);
        return AE_OK;
   }
   
@@@@ -250,15 -207,12 -250,11 +250,16 @@@@ acpi_physical_address __init acpi_os_ge
                               "System description tables not found\n");
                        return 0;
                }
 --     } else
 --             return acpi_find_rsdp();
 ++     } else {
 ++             acpi_physical_address pa = 0;
 ++
 ++             acpi_find_root_pointer(&pa);
 ++             return pa;
 ++     }
   }
   
- -void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+ +void __iomem *__init_refok
+ +acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
   {
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@@@ -665,6 -619,25 -661,25 +666,6 @@@@ static void acpi_os_execute_deferred(st
        dpc->function(dpc->context);
        kfree(dpc);
   
 --     /* Yield cpu to notify thread */
 --     cond_resched();
 --
 --     return;
 --}
 --
 --static void acpi_os_execute_notify(struct work_struct *work)
 --{
 --     struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
 --
 --     if (!dpc) {
 --             printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
 --             return;
 --     }
 --
 --     dpc->function(dpc->context);
 --
 --     kfree(dpc);
 --
        return;
   }
   
@@@@ -688,7 -661,7 -703,7 +689,7 @@@@ acpi_status acpi_os_execute(acpi_execut
   {
        acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
 --
 ++     struct workqueue_struct *queue;
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
        dpc->function = function;
        dpc->context = context;
   
 --     if (type == OSL_NOTIFY_HANDLER) {
 --             INIT_WORK(&dpc->work, acpi_os_execute_notify);
 --             if (!queue_work(kacpi_notify_wq, &dpc->work)) {
 --                     status = AE_ERROR;
 --                     kfree(dpc);
 --             }
 --     } else {
 --             INIT_WORK(&dpc->work, acpi_os_execute_deferred);
 --             if (!queue_work(kacpid_wq, &dpc->work)) {
 --                     ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 --                               "Call to queue_work() failed.\n"));
 --                     status = AE_ERROR;
 --                     kfree(dpc);
 --             }
 ++     INIT_WORK(&dpc->work, acpi_os_execute_deferred);
 ++     queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
 ++     if (!queue_work(queue, &dpc->work)) {
 ++             ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 ++                       "Call to queue_work() failed.\n"));
 ++             status = AE_ERROR;
 ++             kfree(dpc);
        }
        return_ACPI_STATUS(status);
   }
@@@@ -985,37 -965,13 -1007,37 +986,37 @@@@ static int __init acpi_os_name_setup(ch
   
   __setup("acpi_os_name=", acpi_os_name_setup);
   
 - static void enable_osi_linux(int enable) {
 + static void __init set_osi_linux(unsigned int enable)
 + {
 +      if (osi_linux.enable != enable) {
 +              osi_linux.enable = enable;
 +              printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
 +                      enable ? "Add": "Delet");
 +      }
 +      return;
 + }
 + 
 + static void __init acpi_cmdline_osi_linux(unsigned int enable)
 + {
 +      osi_linux.cmdline = 1;  /* cmdline set the default */
 +      set_osi_linux(enable);
 + 
 +      return;
 + }
 + 
 + void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
 + {
 +      osi_linux.dmi = 1;      /* DMI knows that this box asks OSI(Linux) */
 + 
 +      printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
 + 
 +      if (enable == -1)
 +              return;
 + 
 +      osi_linux.known = 1;    /* DMI knows which OSI(Linux) default needed */
   
 -      if (osi_linux != enable)
 -              printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
 -                      enable ? "En": "Dis");
 +      set_osi_linux(enable);
   
 -      osi_linux = enable;
        return;
   }
   
@@@@ -1032,12 -988,12 -1054,12 +1033,12 @@@@ static int __init acpi_osi_setup(char *
                printk(KERN_INFO PREFIX "_OSI method disabled\n");
                acpi_gbl_create_osi_method = FALSE;
        } else if (!strcmp("!Linux", str)) {
 -              enable_osi_linux(0);
 +              acpi_cmdline_osi_linux(0);      /* !enable */
        } else if (*str == '!') {
                if (acpi_osi_invalidate(++str) == AE_OK)
                        printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
        } else if (!strcmp("Linux", str)) {
 -              enable_osi_linux(1);
 +              acpi_cmdline_osi_linux(1);      /* enable */
        } else if (*osi_additional_string == '\0') {
                strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
                printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
@@@@ -1186,34 -1142,6 -1208,34 +1187,34 @@@@ acpi_status acpi_os_release_object(acpi
        return (AE_OK);
   }
   
  -int acpi_dmi_dump(void)
 + /**
 +  *   acpi_dmi_dump - dump DMI slots needed for blacklist entry
 +  *
 +  *   Returns 0 on success
 +  */
  -             dmi_get_slot(DMI_SYS_VENDOR));
 ++static int acpi_dmi_dump(void)
 + {
 + 
 +      if (!dmi_available)
 +              return -1;
 + 
 +      printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
  -             dmi_get_slot(DMI_PRODUCT_NAME));
 ++             dmi_get_system_info(DMI_SYS_VENDOR));
 +      printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
  -             dmi_get_slot(DMI_PRODUCT_VERSION));
 ++             dmi_get_system_info(DMI_PRODUCT_NAME));
 +      printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
  -             dmi_get_slot(DMI_BOARD_NAME));
 ++             dmi_get_system_info(DMI_PRODUCT_VERSION));
 +      printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
  -             dmi_get_slot(DMI_BIOS_VENDOR));
 ++             dmi_get_system_info(DMI_BOARD_NAME));
 +      printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
  -             dmi_get_slot(DMI_BIOS_DATE));
 ++             dmi_get_system_info(DMI_BIOS_VENDOR));
 +      printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
 ++             dmi_get_system_info(DMI_BIOS_DATE));
 + 
 +      return 0;
 + }
 + 
 + 
   /******************************************************************************
    *
    * FUNCTION:    acpi_os_validate_interface
@@@@ -1233,29 -1161,13 -1255,29 +1234,29 @@@@ acpi_os_validate_interface (char *inter
        if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
                return AE_OK;
        if (!strcmp("Linux", interface)) {
 -              printk(KERN_WARNING PREFIX
 -                      "System BIOS is requesting _OSI(Linux)\n");
 -              printk(KERN_WARNING PREFIX
 -                      "If \"acpi_osi=Linux\" works better,\n"
 -                      "Please send dmidecode "
 -                      "to linux-acpi@vger.kernel.org\n");
 -              if(osi_linux)
 + 
 +              printk(KERN_NOTICE PREFIX
 +                      "BIOS _OSI(Linux) query %s%s\n",
 +                      osi_linux.enable ? "honored" : "ignored",
 +                      osi_linux.cmdline ? " via cmdline" :
 +                      osi_linux.dmi ? " via DMI" : "");
 + 
 +              if (!osi_linux.dmi) {
 +                      if (acpi_dmi_dump())
 +                              printk(KERN_NOTICE PREFIX
 +                                      "[please extract dmidecode output]\n");
 +                      printk(KERN_NOTICE PREFIX
 +                              "Please send DMI info above to "
 +                              "linux-acpi@vger.kernel.org\n");
 +              }
 +              if (!osi_linux.known && !osi_linux.cmdline) {
 +                      printk(KERN_NOTICE PREFIX
 +                              "If \"acpi_osi=%sLinux\" works better, "
 +                              "please notify linux-acpi@vger.kernel.org\n",
 +                              osi_linux.enable ? "!" : "");
 +              }
 + 
 +              if (osi_linux.enable)
                        return AE_OK;
        }
        return AE_SUPPORT;
@@@@ -1287,4 -1199,28 -1309,4 +1288,4 @@@@ acpi_os_validate_address 
       return AE_OK;
   }
   
 - #ifdef CONFIG_DMI
 - static int dmi_osi_linux(const struct dmi_system_id *d)
 - {
 -      printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
 -      enable_osi_linux(1);
 -      return 0;
 - }
 - 
 - static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
 -      /*
 -       * Boxes that need _OSI(Linux)
 -       */
 -      {
 -       .callback = dmi_osi_linux,
 -       .ident = "Intel Napa CRB",
 -       .matches = {
 -                   DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 -                   DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
 -                   },
 -       },
 -      {}
 - };
 - #endif /* CONFIG_DMI */
 - 
   #endif
@@@@ -26,24 -26,9 -26,24 +26,24 @@@@ u8 sleep_states[ACPI_S_STATE_COUNT]
   
   #ifdef CONFIG_PM_SLEEP
   static u32 acpi_target_sleep_state = ACPI_STATE_S0;
 + static bool acpi_sleep_finish_wake_up;
 + 
 + /*
 +  * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we
 +  * allow the user to request that behavior by using the 'acpi_new_pts_ordering'
 +  * kernel command line option that causes the following variable to be set.
 +  */
 + static bool new_pts_ordering;
 + 
 + static int __init acpi_new_pts_ordering(char *str)
 + {
 +      new_pts_ordering = true;
 +      return 1;
 + }
 + __setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
   #endif
   
 - int acpi_sleep_prepare(u32 acpi_state)
 + static int acpi_sleep_prepare(u32 acpi_state)
   {
   #ifdef CONFIG_ACPI_SLEEP
        /* do we have a wakeup address for S2 and S3? */
        ACPI_FLUSH_CPU_CACHE();
        acpi_enable_wakeup_device_prep(acpi_state);
   #endif
 +      printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
 +              acpi_state);
        acpi_enter_sleep_state_prep(acpi_state);
        return 0;
   }
@@@@ -80,25 -63,17 -80,25 +80,25 @@@@ static u32 acpi_suspend_states[] = 
   static int init_8259A_after_S1;
   
   /**
 -  *   acpi_pm_set_target - Set the target system sleep state to the state
 +  *   acpi_pm_begin - Set the target system sleep state to the state
    *           associated with given @pm_state, if supported.
    */
   
 - static int acpi_pm_set_target(suspend_state_t pm_state)
 + static int acpi_pm_begin(suspend_state_t pm_state)
   {
        u32 acpi_state = acpi_suspend_states[pm_state];
        int error = 0;
   
        if (sleep_states[acpi_state]) {
                acpi_target_sleep_state = acpi_state;
 +              if (new_pts_ordering)
 +                      return 0;
 + 
 +              error = acpi_sleep_prepare(acpi_state);
 +              if (error)
 +                      acpi_target_sleep_state = ACPI_STATE_S0;
 +              else
 +                      acpi_sleep_finish_wake_up = true;
        } else {
                printk(KERN_ERR "ACPI does not support this state: %d\n",
                        pm_state);
   
   static int acpi_pm_prepare(void)
   {
 -      int error = acpi_sleep_prepare(acpi_target_sleep_state);
 +      if (new_pts_ordering) {
 +              int error = acpi_sleep_prepare(acpi_target_sleep_state);
   
 -      if (error)
 -              acpi_target_sleep_state = ACPI_STATE_S0;
 +              if (error) {
 +                      acpi_target_sleep_state = ACPI_STATE_S0;
 +                      return error;
 +              }
 +              acpi_sleep_finish_wake_up = true;
 +      }
   
 -      return error;
 +      return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
   }
   
   /**
@@@@ -150,8 -120,10 -150,8 +150,8 @@@@ static int acpi_pm_enter(suspend_state_
        if (acpi_state == ACPI_STATE_S3) {
                int error = acpi_save_state_mem();
   
 -              if (error) {
 -                      acpi_target_sleep_state = ACPI_STATE_S0;
 +              if (error)
                        return error;
 -              }
        }
   
        local_irq_save(flags);
                break;
        }
   
 -      /* ACPI 3.0 specs (P62) says that it's the responsabilty
 +      /* Reprogram control registers and execute _BFS */
 +      acpi_leave_sleep_state_prep(acpi_state);
 + 
-       /* ACPI 3.0 specs (P62) says that it's the responsabilty
++      /* ACPI 3.0 specs (P62) says that it's the responsibility
         * of the OSPM to clear the status bit [ implying that the
         * POWER_BUTTON event should not reach userspace ]
         */
        if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
                acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
   
 +      /*
 +       * Disable and clear GPE status before interrupt is enabled. Some GPEs
 +       * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
 +       * acpi_leave_sleep_state will reenable specific GPEs later
 +       */
 +      acpi_hw_disable_all_gpes();
 + 
        local_irq_restore(flags);
        printk(KERN_DEBUG "Back to C!\n");
   
   }
   
   /**
 -  *   acpi_pm_finish - Finish up suspend sequence.
 +  *   acpi_pm_finish - Instruct the platform to leave a sleep state.
    *
    *   This is called after we wake back up (or if entering the sleep state
    *   failed). 
@@@@ -212,7 -174,6 -212,7 +212,7 @@@@ static void acpi_pm_finish(void
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
   
        acpi_target_sleep_state = ACPI_STATE_S0;
 +      acpi_sleep_finish_wake_up = false;
   
   #ifdef CONFIG_X86
        if (init_8259A_after_S1) {
   #endif
   }
   
 + /**
 +  *   acpi_pm_end - Finish up suspend sequence.
 +  */
 + 
 + static void acpi_pm_end(void)
 + {
 +      /*
 +       * This is necessary in case acpi_pm_finish() is not called directly
 +       * during a failing transition to a sleep state.
 +       */
 +      if (acpi_sleep_finish_wake_up)
 +              acpi_pm_finish();
 + }
 + 
   static int acpi_pm_state_valid(suspend_state_t pm_state)
   {
        u32 acpi_state;
   
   static struct platform_suspend_ops acpi_pm_ops = {
        .valid = acpi_pm_state_valid,
 -      .set_target = acpi_pm_set_target,
 +      .begin = acpi_pm_begin,
        .prepare = acpi_pm_prepare,
        .enter = acpi_pm_enter,
        .finish = acpi_pm_finish,
 +      .end = acpi_pm_end,
   };
   
   /*
@@@@ -283,36 -229,15 -283,36 +283,36 @@@@ static struct dmi_system_id __initdata 
   #endif /* CONFIG_SUSPEND */
   
   #ifdef CONFIG_HIBERNATION
 - static int acpi_hibernation_start(void)
 + static int acpi_hibernation_begin(void)
   {
 +      int error;
 + 
        acpi_target_sleep_state = ACPI_STATE_S4;
 -      return 0;
 +      if (new_pts_ordering)
 +              return 0;
 + 
 +      error = acpi_sleep_prepare(ACPI_STATE_S4);
 +      if (error)
 +              acpi_target_sleep_state = ACPI_STATE_S0;
 +      else
 +              acpi_sleep_finish_wake_up = true;
 + 
 +      return error;
   }
   
   static int acpi_hibernation_prepare(void)
   {
 -      return acpi_sleep_prepare(ACPI_STATE_S4);
 +      if (new_pts_ordering) {
 +              int error = acpi_sleep_prepare(ACPI_STATE_S4);
 + 
 +              if (error) {
 +                      acpi_target_sleep_state = ACPI_STATE_S0;
 +                      return error;
 +              }
 +              acpi_sleep_finish_wake_up = true;
 +      }
 + 
 +      return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
   }
   
   static int acpi_hibernation_enter(void)
        acpi_enable_wakeup_device(ACPI_STATE_S4);
        /* This shouldn't return.  If it returns, we have a problem */
        status = acpi_enter_sleep_state(ACPI_STATE_S4);
 +      /* Reprogram control registers and execute _BFS */
 +      acpi_leave_sleep_state_prep(ACPI_STATE_S4);
        local_irq_restore(flags);
   
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@@@ -340,12 -263,15 -340,12 +340,12 @@@@ static void acpi_hibernation_leave(void
         * enable it here.
         */
        acpi_enable();
 +      /* Reprogram control registers and execute _BFS */
 +      acpi_leave_sleep_state_prep(ACPI_STATE_S4);
   }
   
   static void acpi_hibernation_finish(void)
   {
 -      /*
 -       * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 -       * enable it here.
 -       */
 -      acpi_enable();
        acpi_disable_wakeup_device(ACPI_STATE_S4);
        acpi_leave_sleep_state(ACPI_STATE_S4);
   
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
   
        acpi_target_sleep_state = ACPI_STATE_S0;
 +      acpi_sleep_finish_wake_up = false;
 + }
 + 
 + static void acpi_hibernation_end(void)
 + {
 +      /*
 +       * This is necessary in case acpi_hibernation_finish() is not called
 +       * directly during a failing transition to the sleep state.
 +       */
 +      if (acpi_sleep_finish_wake_up)
 +              acpi_hibernation_finish();
   }
   
   static int acpi_hibernation_pre_restore(void)
@@@@ -381,8 -296,7 -381,8 +381,8 @@@@ static void acpi_hibernation_restore_cl
   }
   
   static struct platform_hibernation_ops acpi_hibernation_ops = {
 -      .start = acpi_hibernation_start,
 +      .begin = acpi_hibernation_begin,
 +      .end = acpi_hibernation_end,
        .pre_snapshot = acpi_hibernation_prepare,
        .finish = acpi_hibernation_finish,
        .prepare = acpi_hibernation_prepare,
@@@@ -472,20 -386,11 -472,11 +472,20 @@@@ int acpi_pm_device_sleep_state(struct d
        if (acpi_target_sleep_state == ACPI_STATE_S0 ||
            (wake && adev->wakeup.state.enabled &&
             adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
 ++             acpi_status status;
 ++
                acpi_method[3] = 'W';
 --             acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
 --             /* Sanity check */
 --             if (d_max < d_min)
 ++             status = acpi_evaluate_integer(handle, acpi_method, NULL,
 ++                                             &d_max);
 ++             if (ACPI_FAILURE(status)) {
 ++                     d_max = d_min;
 ++             } else if (d_max < d_min) {
 ++                     /* Warn the user of the broken DSDT */
 ++                     printk(KERN_WARNING "ACPI: Wrong value from %s\n",
 ++                             acpi_method);
 ++                     /* Sanitize it */
                        d_min = d_max;
 ++             }
        }
   
        if (d_min_p)
@@@@ -498,7 -403,6 -489,7 +498,7 @@@@ static void acpi_power_off_prepare(void
   {
        /* Prepare to power off the system */
        acpi_sleep_prepare(ACPI_STATE_S5);
 +      acpi_hw_disable_all_gpes();
   }
   
   static void acpi_power_off(void)