]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
ACPICA: Introduce acpi_gpe_wakeup()
authorRafael J. Wysocki <rjw@sisk.pl>
Thu, 24 Jun 2010 23:18:39 +0000 (01:18 +0200)
committerLen Brown <len.brown@intel.com>
Wed, 7 Jul 2010 02:34:26 +0000 (22:34 -0400)
ACPICA uses reference counters to avoid disabling GPEs too early in
case they have been enabled for many times.  This is done separately
for runtime and for wakeup, but the wakeup GPE reference counter is
not really necessary, because GPEs are only enabled to wake up the
system at the hardware level by acpi_enter_sleep_state().  Thus it
only is necessary to set the corresponding bits in the wakeup enable
masks of these GPEs' registers right before the system enters a sleep
state.  Moreover, the GPE wakeup enable bits can only be set when the
target sleep state of the system is known and they need to be cleared
immediately after wakeup regardless of how many wakeup devices are
associated with a given GPE.

On the basis of the above observations, introduce function
acpi_gpe_wakeup() to be used for setting or clearing the enable bit
corresponding to a given GPE in its enable register's enable_for_wake
mask.  Modify the ACPI suspend and wakeup code the use
acpi_gpe_wakeup() instead of acpi_{enable|disable}_gpe() to set
and clear GPE enable bits in their registers' enable_for_wake masks
during system transitions to a sleep state and back to the working
state, respectively.  [This will allow us to drop the third
argument of acpi_{enable|disable}_gpe() and simplify the GPE
handling code.]

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/sleep.c
drivers/acpi/wakeup.c
include/acpi/acpixf.h
include/acpi/actypes.h

index d97b8dce16681ba90886a3b0e5546cf5b7060ce8..d6a6d4a765926dff17da0b255bc3a9d4a49e7ae9 100644 (file)
@@ -306,6 +306,73 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
 
 ACPI_EXPORT_SYMBOL(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          - Enable or Disable
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit.
+ *
+ ******************************************************************************/
+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;
+       struct acpi_gpe_register_info *gpe_register_info;
+       acpi_cpu_flags flags;
+       u32 register_bit;
+
+       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) {
+               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:
+               ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
+               break;
+
+       case ACPI_GPE_DISABLE:
+               ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
+                              register_bit);
+               break;
+
+       default:
+               ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
+               status = AE_BAD_PARAMETER;
+               break;
+       }
+
+unlock_and_exit:
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+       return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup)
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_enable_gpe
index 5b7c52e4a00f09001becab5df101e7e5fa4dabc8..aaa1af55e280379ad3d5f76a3117124f4a5c96d8 100644 (file)
@@ -664,18 +664,9 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
                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");
index 388747a7ef4fc261b4e09db7866bc86bb9b17570..c80537bc3234dd012a3e047907ad0c572b2e6f6a 100644 (file)
@@ -64,13 +64,14 @@ void acpi_enable_wakeup_device(u8 sleep_state)
                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;
 
                /* 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);
        }
 }
 
@@ -89,13 +90,16 @@ void acpi_disable_wakeup_device(u8 sleep_state)
                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);
        }
 }
 
index 8aaa596e12089016d0a538c219ae88ec744bf694..17396e83e1a4001f9ba963ff8be0d83352241131 100644 (file)
@@ -292,6 +292,8 @@ acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type);
 
 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);
index d55f4a7b824db550d3ce2bfbd2c7235859eb08a4..6a65a94897bf68fe894382e5ca189a950cc60bce 100644 (file)
@@ -663,7 +663,7 @@ typedef u32 acpi_event_status;
 #define ACPI_GPE_MAX                    0xFF
 #define ACPI_NUM_GPE                    256
 
-/* Actions for acpi_set_gpe and acpi_hw_low_set_gpe */
+/* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */
 
 #define ACPI_GPE_ENABLE                 0
 #define ACPI_GPE_DISABLE                1