Merge branch 'acpica-gpe' into release
authorLen Brown <len.brown@intel.com>
Sun, 15 Aug 2010 04:25:40 +0000 (00:25 -0400)
committerLen Brown <len.brown@intel.com>
Sun, 15 Aug 2010 04:25:40 +0000 (00:25 -0400)
1  2 
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/sleep.c
drivers/acpi/wakeup.c
include/acpi/acpixf.h

@@@ -99,13 -99,6 +99,6 @@@ u8 ACPI_INIT_GLOBAL(acpi_gbl_all_method
   */
  u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
  
- /*
-  * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and
-  * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only
-  * be enabled just before going to sleep.
-  */
- u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
  /*
   * Optionally use default values for the ACPI register widths. Set this to
   * TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
@@@ -115,7 -108,7 +108,7 @@@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_defaul
  /*
   * Optionally enable output from the AML Debug Object.
   */
 -u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
 +u32 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
  
  /*
   * Optionally copy the entire DSDT to local memory (instead of simply
@@@ -70,7 -70,6 +70,7 @@@ acpi_ev_get_gpe_device(struct acpi_gpe_
  acpi_status acpi_enable(void)
  {
        acpi_status status;
 +      int retry;
  
        ACPI_FUNCTION_TRACE(acpi_enable);
  
  
        /* Sanity check that transition succeeded */
  
 -      if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) {
 -              ACPI_ERROR((AE_INFO,
 -                          "Hardware did not enter ACPI mode"));
 -              return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
 +      for (retry = 0; retry < 30000; ++retry) {
 +              if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
 +                      if (retry != 0)
 +                              ACPI_WARNING((AE_INFO,
 +                              "Platform took > %d00 usec to enter ACPI mode", retry));
 +                      return_ACPI_STATUS(AE_OK);
 +              }
 +              acpi_os_stall(100);     /* 100 usec */
        }
  
 -      ACPI_DEBUG_PRINT((ACPI_DB_INIT,
 -                        "Transition to ACPI mode successful\n"));
 -
 -      return_ACPI_STATUS(AE_OK);
 +      ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode"));
 +      return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
  }
  
  ACPI_EXPORT_SYMBOL(acpi_enable)
@@@ -213,101 -210,71 +213,71 @@@ ACPI_EXPORT_SYMBOL(acpi_enable_event
  
  /*******************************************************************************
   *
-  * FUNCTION:    acpi_clear_and_enable_gpe
-  *
-  * PARAMETERS:  gpe_event_info  - GPE to enable
-  *
-  * RETURN:      Status
-  *
-  * DESCRIPTION: Clear the given GPE from stale events and enable it.
-  *
-  ******************************************************************************/
- static acpi_status
- acpi_clear_and_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
- {
-       acpi_status status;
-       /*
-        * We will only allow a GPE to be enabled if it has either an
-        * associated method (_Lxx/_Exx) or a handler. Otherwise, the
-        * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
-        * first time it fires.
-        */
-       if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
-               return_ACPI_STATUS(AE_NO_HANDLER);
-       }
-       /* Clear the GPE (of stale events) */
-       status = acpi_hw_clear_gpe(gpe_event_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-       /* Enable the requested GPE */
-       status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
-       return_ACPI_STATUS(status);
- }
- /*******************************************************************************
-  *
-  * FUNCTION:    acpi_set_gpe
+  * FUNCTION:    acpi_gpe_wakeup
   *
   * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
   *              gpe_number      - GPE level within the GPE block
-  *              action          - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+  *              Action          - Enable or Disable
   *
   * RETURN:      Status
   *
-  * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
-  *              the reference count mechanism used in the acpi_enable_gpe and
-  *              acpi_disable_gpe interfaces -- and should be used with care.
-  *
-  * Note: Typically used to disable a runtime GPE for short period of time,
-  * then re-enable it, without disturbing the existing reference counts. This
-  * is useful, for example, in the Embedded Controller (EC) driver.
+  * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit.
   *
   ******************************************************************************/
- acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+ acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action)
  {
+       acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
-       acpi_status status;
+       struct acpi_gpe_register_info *gpe_register_info;
        acpi_cpu_flags flags;
+       u32 register_bit;
  
-       ACPI_FUNCTION_TRACE(acpi_set_gpe);
+       ACPI_FUNCTION_TRACE(acpi_gpe_wakeup);
  
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  
        /* Ensure that we have a valid GPE number */
  
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-       if (!gpe_event_info) {
+       if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
                status = AE_BAD_PARAMETER;
                goto unlock_and_exit;
        }
  
+       gpe_register_info = gpe_event_info->register_info;
+       if (!gpe_register_info) {
+               status = AE_NOT_EXIST;
+               goto unlock_and_exit;
+       }
+       register_bit =
+           acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
        /* Perform the action */
  
        switch (action) {
        case ACPI_GPE_ENABLE:
-               status = acpi_clear_and_enable_gpe(gpe_event_info);
+               ACPI_SET_BIT(gpe_register_info->enable_for_wake,
+                            (u8)register_bit);
                break;
  
        case ACPI_GPE_DISABLE:
-               status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+               ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
+                              (u8)register_bit);
                break;
  
        default:
+               ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
                status = AE_BAD_PARAMETER;
                break;
        }
  
      unlock_and_exit:
+ unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
  }
  
- ACPI_EXPORT_SYMBOL(acpi_set_gpe)
+ ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup)
  
  /*******************************************************************************
   *
   *
   * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
   *              gpe_number      - GPE level within the GPE block
-  *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
-  *                                or both
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
-  *              hardware-enabled (for runtime GPEs), or the GPE register mask
-  *              is updated (for wake GPEs).
+  *              hardware-enabled.
   *
   ******************************************************************************/
- acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
+ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
  {
-       acpi_status status = AE_OK;
+       acpi_status status = AE_BAD_PARAMETER;
        struct acpi_gpe_event_info *gpe_event_info;
        acpi_cpu_flags flags;
  
        ACPI_FUNCTION_TRACE(acpi_enable_gpe);
  
-       /* Parameter validation */
-       if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  
        /* Ensure that we have a valid GPE number */
  
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-       if (!gpe_event_info) {
-               status = AE_BAD_PARAMETER;
-               goto unlock_and_exit;
-       }
-       if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
-               if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
-                       status = AE_LIMIT;      /* Too many references */
-                       goto unlock_and_exit;
-               }
-               gpe_event_info->runtime_count++;
-               if (gpe_event_info->runtime_count == 1) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-                       if (ACPI_SUCCESS(status)) {
-                               status = acpi_clear_and_enable_gpe(gpe_event_info);
-                       }
-                       if (ACPI_FAILURE(status)) {
-                               gpe_event_info->runtime_count--;
-                               goto unlock_and_exit;
-                       }
-               }
-       }
-       if (gpe_type & ACPI_GPE_TYPE_WAKE) {
-               /* The GPE must have the ability to wake the system */
-               if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
-                       status = AE_TYPE;
-                       goto unlock_and_exit;
-               }
-               if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
-                       status = AE_LIMIT;      /* Too many references */
-                       goto unlock_and_exit;
-               }
-               /*
-                * Update the enable mask on the first wakeup reference. Wake GPEs
-                * are only hardware-enabled just before sleeping.
-                */
-               gpe_event_info->wakeup_count++;
-               if (gpe_event_info->wakeup_count == 1) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-               }
+       if (gpe_event_info) {
+               status = acpi_raw_enable_gpe(gpe_event_info);
        }
  
- unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
  }
@@@ -404,8 -317,6 +320,6 @@@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe
   *
   * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
   *              gpe_number      - GPE level within the GPE block
-  *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
-  *                                or both
   *
   * RETURN:      Status
   *
   *              the GPE mask bit disabled (for wake GPEs)
   *
   ******************************************************************************/
- acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
+ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
  {
-       acpi_status status = AE_OK;
+       acpi_status status = AE_BAD_PARAMETER;
        struct acpi_gpe_event_info *gpe_event_info;
        acpi_cpu_flags flags;
  
        ACPI_FUNCTION_TRACE(acpi_disable_gpe);
  
-       /* Parameter validation */
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+       /* Ensure that we have a valid GPE number */
  
-       if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+       if (gpe_event_info) {
+               status = acpi_raw_disable_gpe(gpe_event_info) ;
        }
  
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+       return_ACPI_STATUS(status);
+ }
+ ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
+ /*******************************************************************************
+  *
+  * FUNCTION:    acpi_gpe_can_wake
+  *
+  * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
+  *              gpe_number      - GPE level within the GPE block
+  *
+  * RETURN:      Status
+  *
+  * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE.  If the GPE
+  *              has a corresponding method and is currently enabled, disable it
+  *              (GPEs with corresponding methods are enabled unconditionally
+  *              during initialization, but GPEs that can wake up are expected
+  *              to be initially disabled).
+  *
+  ******************************************************************************/
+ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
+ {
+       acpi_status status = AE_OK;
+       struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
+       ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  
        /* Ensure that we have a valid GPE number */
                goto unlock_and_exit;
        }
  
-       /* Hardware-disable a runtime GPE on removal of the last reference */
-       if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
-               if (!gpe_event_info->runtime_count) {
-                       status = AE_LIMIT;      /* There are no references to remove */
-                       goto unlock_and_exit;
-               }
-               gpe_event_info->runtime_count--;
-               if (!gpe_event_info->runtime_count) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-                       if (ACPI_SUCCESS(status)) {
-                               status = acpi_hw_low_set_gpe(gpe_event_info,
-                                                            ACPI_GPE_DISABLE);
-                       }
-                       if (ACPI_FAILURE(status)) {
-                               gpe_event_info->runtime_count++;
-                               goto unlock_and_exit;
-                       }
-               }
+       if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
+               goto unlock_and_exit;
        }
  
-       /*
-        * Update masks for wake GPE on removal of the last reference.
-        * No need to hardware-disable wake GPEs here, they are not currently
-        * enabled.
-        */
-       if (gpe_type & ACPI_GPE_TYPE_WAKE) {
-               if (!gpe_event_info->wakeup_count) {
-                       status = AE_LIMIT;      /* There are no references to remove */
-                       goto unlock_and_exit;
-               }
-               gpe_event_info->wakeup_count--;
-               if (!gpe_event_info->wakeup_count) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-               }
+       gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+       if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
+               (void)acpi_raw_disable_gpe(gpe_event_info);
        }
  
  unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
  }
- ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
+ ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake)
  
  /*******************************************************************************
   *
@@@ -800,7 -712,7 +715,7 @@@ acpi_install_gpe_block(acpi_handle gpe_
  
        obj_desc->device.gpe_block = gpe_block;
  
-       /* Run the _PRW methods and enable the runtime GPEs in the new block */
+       /* Enable the runtime GPEs in the new block */
  
        status = acpi_ev_initialize_gpe_block(node, gpe_block);
  
diff --combined drivers/acpi/sleep.c
@@@ -70,10 -70,10 +70,10 @@@ static int acpi_sleep_prepare(u32 acpi_
  
        }
        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_enable_wakeup_devices(acpi_state);
        acpi_enter_sleep_state_prep(acpi_state);
        return 0;
  }
  #ifdef CONFIG_ACPI_SLEEP
  static u32 acpi_target_sleep_state = ACPI_STATE_S0;
  
 +/*
 + * The ACPI specification wants us to save NVS memory regions during hibernation
 + * and to restore them during the subsequent resume.  Windows does that also for
 + * suspend to RAM.  However, it is known that this mechanism does not work on
 + * all machines, so we allow the user to disable it with the help of the
 + * 'acpi_sleep=nonvs' kernel command line option.
 + */
 +static bool nvs_nosave;
 +
 +void __init acpi_nvs_nosave(void)
 +{
 +      nvs_nosave = true;
 +}
 +
  /*
   * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
   * user to request that behavior by using the 'acpi_old_suspend_ordering'
@@@ -118,16 -104,6 +118,16 @@@ static int acpi_pm_freeze(void
        return 0;
  }
  
 +/**
 + * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
 + */
 +static int acpi_pm_pre_suspend(void)
 +{
 +      acpi_pm_freeze();
 +      suspend_nvs_save();
 +      return 0;
 +}
 +
  /**
   *    __acpi_pm_prepare - Prepare the platform to enter the target state.
   *
  static int __acpi_pm_prepare(void)
  {
        int error = acpi_sleep_prepare(acpi_target_sleep_state);
 -
 -      suspend_nvs_save();
 -
        if (error)
                acpi_target_sleep_state = ACPI_STATE_S0;
 +
        return error;
  }
  
  static int acpi_pm_prepare(void)
  {
        int error = __acpi_pm_prepare();
 -
        if (!error)
 -              acpi_pm_freeze();
 +              acpi_pm_pre_suspend();
  
        return error;
  }
@@@ -166,6 -145,7 +166,6 @@@ static void acpi_pm_finish(void
  {
        u32 acpi_state = acpi_target_sleep_state;
  
 -      suspend_nvs_free();
        acpi_ec_unblock_transactions();
  
        if (acpi_state == ACPI_STATE_S0)
  
        printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n",
                acpi_state);
 -      acpi_disable_wakeup_device(acpi_state);
 +      acpi_disable_wakeup_devices(acpi_state);
        acpi_leave_sleep_state(acpi_state);
  
        /* reset firmware waking vector */
   */
  static void acpi_pm_end(void)
  {
 +      suspend_nvs_free();
        /*
         * This is necessary in case acpi_pm_finish() is not called during a
         * failing transition to a sleep state.
@@@ -218,7 -197,8 +218,7 @@@ static int acpi_suspend_begin(suspend_s
        u32 acpi_state = acpi_suspend_states[pm_state];
        int error = 0;
  
 -      error = suspend_nvs_alloc();
 -
 +      error = nvs_nosave ? 0 : suspend_nvs_alloc();
        if (error)
                return error;
  
@@@ -258,6 -238,7 +258,6 @@@ static int acpi_suspend_enter(suspend_s
        }
  
        local_irq_save(flags);
 -      acpi_enable_wakeup_device(acpi_state);
        switch (acpi_state) {
        case ACPI_STATE_S1:
                barrier();
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
  }
  
 -static void acpi_suspend_finish(void)
 -{
 -      acpi_pm_finish();
 -}
 -
  static int acpi_suspend_state_valid(suspend_state_t pm_state)
  {
        u32 acpi_state;
@@@ -324,7 -310,7 +324,7 @@@ static struct platform_suspend_ops acpi
        .begin = acpi_suspend_begin,
        .prepare_late = acpi_pm_prepare,
        .enter = acpi_suspend_enter,
 -      .wake = acpi_suspend_finish,
 +      .wake = acpi_pm_finish,
        .end = acpi_pm_end,
  };
  
  static int acpi_suspend_begin_old(suspend_state_t pm_state)
  {
        int error = acpi_suspend_begin(pm_state);
 -
        if (!error)
                error = __acpi_pm_prepare();
 +
        return error;
  }
  
  static struct platform_suspend_ops acpi_suspend_ops_old = {
        .valid = acpi_suspend_state_valid,
        .begin = acpi_suspend_begin_old,
 -      .prepare_late = acpi_pm_freeze,
 +      .prepare_late = acpi_pm_pre_suspend,
        .enter = acpi_suspend_enter,
 -      .wake = acpi_suspend_finish,
 +      .wake = acpi_pm_finish,
        .end = acpi_pm_end,
        .recover = acpi_pm_finish,
  };
@@@ -402,6 -388,20 +402,6 @@@ static struct dmi_system_id __initdata 
  #endif /* CONFIG_SUSPEND */
  
  #ifdef CONFIG_HIBERNATION
 -/*
 - * The ACPI specification wants us to save NVS memory regions during hibernation
 - * and to restore them during the subsequent resume.  However, it is not certain
 - * if this mechanism is going to work on all machines, so we allow the user to
 - * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
 - * option.
 - */
 -static bool s4_no_nvs;
 -
 -void __init acpi_s4_no_nvs(void)
 -{
 -      s4_no_nvs = true;
 -}
 -
  static unsigned long s4_hardware_signature;
  static struct acpi_table_facs *facs;
  static bool nosigcheck;
@@@ -415,7 -415,7 +415,7 @@@ static int acpi_hibernation_begin(void
  {
        int error;
  
 -      error = s4_no_nvs ? 0 : suspend_nvs_alloc();
 +      error = nvs_nosave ? 0 : suspend_nvs_alloc();
        if (!error) {
                acpi_target_sleep_state = ACPI_STATE_S4;
                acpi_sleep_tts_switch(acpi_target_sleep_state);
        return error;
  }
  
 -static int acpi_hibernation_pre_snapshot(void)
 -{
 -      int error = acpi_pm_prepare();
 -
 -      if (!error)
 -              suspend_nvs_save();
 -
 -      return error;
 -}
 -
  static int acpi_hibernation_enter(void)
  {
        acpi_status status = AE_OK;
        ACPI_FLUSH_CPU_CACHE();
  
        local_irq_save(flags);
 -      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 */
@@@ -471,7 -482,7 +471,7 @@@ static void acpi_pm_thaw(void
  static struct platform_hibernation_ops acpi_hibernation_ops = {
        .begin = acpi_hibernation_begin,
        .end = acpi_pm_end,
 -      .pre_snapshot = acpi_hibernation_pre_snapshot,
 +      .pre_snapshot = acpi_pm_prepare,
        .finish = acpi_pm_finish,
        .prepare = acpi_pm_prepare,
        .enter = acpi_hibernation_enter,
@@@ -499,7 -510,7 +499,7 @@@ static int acpi_hibernation_begin_old(v
        error = acpi_sleep_prepare(ACPI_STATE_S4);
  
        if (!error) {
 -              if (!s4_no_nvs)
 +              if (!nvs_nosave)
                        error = suspend_nvs_alloc();
                if (!error)
                        acpi_target_sleep_state = ACPI_STATE_S4;
        return error;
  }
  
 -static int acpi_hibernation_pre_snapshot_old(void)
 -{
 -      acpi_pm_freeze();
 -      suspend_nvs_save();
 -      return 0;
 -}
 -
  /*
   * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
   * been requested.
  static struct platform_hibernation_ops acpi_hibernation_ops_old = {
        .begin = acpi_hibernation_begin_old,
        .end = acpi_pm_end,
 -      .pre_snapshot = acpi_hibernation_pre_snapshot_old,
 +      .pre_snapshot = acpi_pm_pre_suspend,
        .prepare = acpi_pm_freeze,
        .finish = acpi_pm_finish,
        .enter = acpi_hibernation_enter,
@@@ -646,18 -664,9 +646,9 @@@ int acpi_pm_device_sleep_wake(struct de
                return -ENODEV;
        }
  
-       if (enable) {
-               error = acpi_enable_wakeup_device_power(adev,
-                                               acpi_target_sleep_state);
-               if (!error)
-                       acpi_enable_gpe(adev->wakeup.gpe_device,
-                                       adev->wakeup.gpe_number,
-                                       ACPI_GPE_TYPE_WAKE);
-       } else {
-               acpi_disable_gpe(adev->wakeup.gpe_device, adev->wakeup.gpe_number,
-                               ACPI_GPE_TYPE_WAKE);
-               error = acpi_disable_wakeup_device_power(adev);
-       }
+       error = enable ?
+               acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
+               acpi_disable_wakeup_device_power(adev);
        if (!error)
                dev_info(dev, "wake-up capability %s by ACPI\n",
                                enable ? "enabled" : "disabled");
@@@ -678,6 -687,7 +669,6 @@@ static void acpi_power_off(void
        /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
        printk(KERN_DEBUG "%s called\n", __func__);
        local_irq_disable();
 -      acpi_enable_wakeup_device(ACPI_STATE_S5);
        acpi_enter_sleep_state(ACPI_STATE_S5);
  }
  
diff --combined drivers/acpi/wakeup.c
  ACPI_MODULE_NAME("wakeup_devices")
  
  /**
 - * acpi_enable_wakeup_device_prep - Prepare wake-up devices.
 + * acpi_enable_wakeup_devices - Enable wake-up device GPEs.
   * @sleep_state: ACPI system sleep state.
   *
 - * Enable all wake-up devices' power, unless the requested system sleep state is
 - * too deep.
 + * Enable wakeup device power of devices with the state.enable flag set and set
 + * the wakeup enable mask bits in the GPE registers that correspond to wakeup
 + * devices.
   */
 -void acpi_enable_wakeup_device_prep(u8 sleep_state)
 +void acpi_enable_wakeup_devices(u8 sleep_state)
  {
        struct list_head *node, *next;
  
 -      list_for_each_safe(node, next, &acpi_wakeup_device_list) {
 -              struct acpi_device *dev = container_of(node,
 -                                                     struct acpi_device,
 -                                                     wakeup_list);
 -
 -              if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
 -                  || (sleep_state > (u32) dev->wakeup.sleep_state))
 -                      continue;
 -
 -              acpi_enable_wakeup_device_power(dev, sleep_state);
 -      }
 -}
 -
 -/**
 - * acpi_enable_wakeup_device - Enable wake-up device GPEs.
 - * @sleep_state: ACPI system sleep state.
 - *
 - * Enable all wake-up devices' GPEs, with the assumption that
 - * acpi_disable_all_gpes() was executed before, so we don't need to disable any
 - * GPEs here.
 - */
 -void acpi_enable_wakeup_device(u8 sleep_state)
 -{
 -      struct list_head *node, *next;
 -
 -      /* 
 -       * Caution: this routine must be invoked when interrupt is disabled 
 -       * Refer ACPI2.0: P212
 -       */
        list_for_each_safe(node, next, &acpi_wakeup_device_list) {
                struct acpi_device *dev =
                        container_of(node, struct acpi_device, wakeup_list);
  
-               if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
+               if (!dev->wakeup.flags.valid
+                   || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
                    || sleep_state > (u32) dev->wakeup.sleep_state)
                        continue;
  
 +              if (dev->wakeup.state.enabled)
 +                      acpi_enable_wakeup_device_power(dev, sleep_state);
 +
                /* The wake-up power should have been enabled already. */
-               acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
-                               ACPI_GPE_TYPE_WAKE);
+               acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+                               ACPI_GPE_ENABLE);
        }
  }
  
  /**
 - * acpi_disable_wakeup_device - Disable devices' wakeup capability.
 + * acpi_disable_wakeup_devices - Disable devices' wakeup capability.
   * @sleep_state: ACPI system sleep state.
 - *
 - * This function only affects devices with wakeup.state.enabled set, which means
 - * that it reverses the changes made by acpi_enable_wakeup_device_prep().
   */
 -void acpi_disable_wakeup_device(u8 sleep_state)
 +void acpi_disable_wakeup_devices(u8 sleep_state)
  {
        struct list_head *node, *next;
  
                struct acpi_device *dev =
                        container_of(node, struct acpi_device, wakeup_list);
  
-               if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
+               if (!dev->wakeup.flags.valid
+                   || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
                    || (sleep_state > (u32) dev->wakeup.sleep_state))
                        continue;
  
-               acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
-                               ACPI_GPE_TYPE_WAKE);
-               acpi_disable_wakeup_device_power(dev);
+               acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+                               ACPI_GPE_DISABLE);
+               if (dev->wakeup.state.enabled)
+                       acpi_disable_wakeup_device_power(dev);
        }
  }
  
diff --combined include/acpi/acpixf.h
@@@ -47,7 -47,7 +47,7 @@@
  
  /* Current ACPICA subsystem version in YYYYMMDD format */
  
- #define ACPI_CA_VERSION                 0x20100428
+ #define ACPI_CA_VERSION                 0x20100702
  
  #include "actypes.h"
  #include "actbl.h"
@@@ -63,11 -63,10 +63,10 @@@ extern u32 acpi_dbg_layer
  extern u8 acpi_gbl_enable_interpreter_slack;
  extern u8 acpi_gbl_all_methods_serialized;
  extern u8 acpi_gbl_create_osi_method;
- extern u8 acpi_gbl_leave_wake_gpes_disabled;
  extern u8 acpi_gbl_use_default_register_widths;
  extern acpi_name acpi_gbl_trace_method_name;
  extern u32 acpi_gbl_trace_flags;
 -extern u8 acpi_gbl_enable_aml_debug_object;
 +extern u32 acpi_gbl_enable_aml_debug_object;
  extern u8 acpi_gbl_copy_dsdt_locally;
  extern u8 acpi_gbl_truncate_io_addresses;
  
@@@ -282,16 -281,16 +281,16 @@@ acpi_status acpi_get_event_status(u32 e
  /*
   * GPE Interfaces
   */
- acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action);
+ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number);
  
- acpi_status
- acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type);
+ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number);
  
- acpi_status
- acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type);
+ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number);
  
  acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number);
  
+ acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action);
  acpi_status
  acpi_get_gpe_status(acpi_handle gpe_device,
                    u32 gpe_number, acpi_event_status *event_status);