Merge branches 'release', 'acpi_pm_device_sleep_state' and 'battery' into release
authorLen Brown <len.brown@intel.com>
Thu, 7 Feb 2008 08:07:03 +0000 (03:07 -0500)
committerLen Brown <len.brown@intel.com>
Thu, 7 Feb 2008 08:07:03 +0000 (03:07 -0500)
1  2  3 
drivers/acpi/sleep/main.c

index 485de1347075c812c4c7dbd4347c67cca7bd67b3,99181c8f023e995ddee02db168d9ef682a74bd4e,485de1347075c812c4c7dbd4347c67cca7bd67b3..7f97e32fc33f7d049c14e63b258da3c4b1e1d283
@@@@ -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;
        }
   
 +      /* Reprogram control registers and execute _BFS */
 +      acpi_leave_sleep_state_prep(acpi_state);
 + 
        /* ACPI 3.0 specs (P62) says that it's the responsabilty
         * 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,11 -386,20 -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)
@@@@ -489,7 -412,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)