]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/acpi/acpica/evxfevnt.c
Merge branch 'gpe-regression-fixes' into release
[mv-sheeva.git] / drivers / acpi / acpica / evxfevnt.c
index 7c7bbb4d402ca31a7dcbfe766e5ed2a0eb0e47b3..d97b8dce16681ba90886a3b0e5546cf5b7060ce8 100644 (file)
@@ -69,7 +69,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 
 acpi_status acpi_enable(void)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_enable);
 
@@ -84,21 +84,30 @@ acpi_status acpi_enable(void)
        if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
                ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                                  "System is already in ACPI mode\n"));
-       } else {
-               /* Transition to ACPI mode */
+               return_ACPI_STATUS(AE_OK);
+       }
 
-               status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not transition to ACPI mode"));
-                       return_ACPI_STATUS(status);
-               }
+       /* Transition to ACPI mode */
 
-               ACPI_DEBUG_PRINT((ACPI_DB_INIT,
-                                 "Transition to ACPI mode successful\n"));
+       status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not transition to ACPI mode"));
+               return_ACPI_STATUS(status);
        }
 
-       return_ACPI_STATUS(status);
+       /* 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);
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INIT,
+                         "Transition to ACPI mode successful\n"));
+
+       return_ACPI_STATUS(AE_OK);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_enable)
@@ -199,6 +208,44 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
 
 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
@@ -240,11 +287,11 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
 
        switch (action) {
        case ACPI_GPE_ENABLE:
-               status = acpi_ev_enable_gpe(gpe_event_info);
+               status = acpi_clear_and_enable_gpe(gpe_event_info);
                break;
 
        case ACPI_GPE_DISABLE:
-               status = acpi_ev_disable_gpe(gpe_event_info);
+               status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
                break;
 
        default:
@@ -307,7 +354,11 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
 
                gpe_event_info->runtime_count++;
                if (gpe_event_info->runtime_count == 1) {
-                       status = acpi_ev_enable_gpe(gpe_event_info);
+                       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;
@@ -334,7 +385,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
                 */
                gpe_event_info->wakeup_count++;
                if (gpe_event_info->wakeup_count == 1) {
-                       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
+                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
                }
        }
 
@@ -394,7 +445,12 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
 
                gpe_event_info->runtime_count--;
                if (!gpe_event_info->runtime_count) {
-                       status = acpi_ev_disable_gpe(gpe_event_info);
+                       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;
@@ -415,7 +471,7 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
 
                gpe_event_info->wakeup_count--;
                if (!gpe_event_info->wakeup_count) {
-                       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
+                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
                }
        }