ACPICA: Events: Fix edge-triggered GPE by disabling before acknowledging it.
authorLv Zheng <lv.zheng@intel.com>
Sun, 15 Jun 2014 00:42:31 +0000 (08:42 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 6 Jul 2014 23:08:14 +0000 (01:08 +0200)
Due to ACPI specificiation 5, chapter 5.6.4 General-Purpose Event Handling,
OSPMs need to disable GPE before clearing the status bit for edge-triggered
GPEs.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Tested-by: Gareth Williams <gareth@garethwilliams.me.uk>
Tested-by: Steffen Weber <steffen.weber@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/evgpe.c

index 48f70013b488c7cdbb956b6ab316afe1c8396f03..e4ba4dec86af19ef447f3a4783c39015e558778f 100644 (file)
@@ -697,21 +697,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
                                              acpi_gbl_global_event_handler_context);
        }
 
-       /*
-        * If edge-triggered, clear the GPE status bit now. Note that
-        * level-triggered events are cleared after the GPE is serviced.
-        */
-       if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
-           ACPI_GPE_EDGE_TRIGGERED) {
-               status = acpi_hw_clear_gpe(gpe_event_info);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_EXCEPTION((AE_INFO, status,
-                                       "Unable to clear GPE %02X",
-                                       gpe_number));
-                       return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
-               }
-       }
-
        /*
         * Always disable the GPE so that it does not keep firing before
         * any asynchronous activity completes (either from the execution
@@ -728,6 +713,23 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
                return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
        }
 
+       /*
+        * If edge-triggered, clear the GPE status bit now. Note that
+        * level-triggered events are cleared after the GPE is serviced.
+        */
+       if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+           ACPI_GPE_EDGE_TRIGGERED) {
+               status = acpi_hw_clear_gpe(gpe_event_info);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "Unable to clear GPE %02X",
+                                       gpe_number));
+                       (void)acpi_hw_low_set_gpe(gpe_event_info,
+                                                 ACPI_GPE_CONDITIONAL_ENABLE);
+                       return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+               }
+       }
+
        /*
         * Dispatch the GPE to either an installed handler or the control
         * method associated with this GPE (_Lxx or _Exx). If a handler