]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/acpi/acpica/evgpe.c
Merge branch 'gpe-regression-fixes' into release
[karo-tx-linux.git] / drivers / acpi / acpica / evgpe.c
index 78c55508aff5adee685ca664a6f33531e469663a..7c2c336006a1f316e280e990876eb6ffcd2f0e1f 100644 (file)
@@ -60,7 +60,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Updates GPE register enable masks based on the GPE type
+ * DESCRIPTION: Updates GPE register enable masks based upon whether there are
+ *              references (either wake or run) to this GPE
  *
  ******************************************************************************/
 
@@ -68,7 +69,7 @@ acpi_status
 acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
 {
        struct acpi_gpe_register_info *gpe_register_info;
-       u8 register_bit;
+       u32 register_bit;
 
        ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks);
 
@@ -77,92 +78,66 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
                return_ACPI_STATUS(AE_NOT_EXIST);
        }
 
-       register_bit = (u8)
-           (1 <<
-            (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
+       register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+                                               gpe_register_info);
+
+       /* Clear the wake/run bits up front */
 
        ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, register_bit);
        ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
 
-       if (gpe_event_info->runtime_count)
+       /* Set the mask bits only if there are references to this GPE */
+
+       if (gpe_event_info->runtime_count) {
                ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
+       }
 
-       if (gpe_event_info->wakeup_count)
+       if (gpe_event_info->wakeup_count) {
                ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
+       }
 
        return_ACPI_STATUS(AE_OK);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_enable_gpe
- *
- * PARAMETERS:  gpe_event_info          - GPE to enable
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Enable a GPE based on the GPE type
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_enable_gpe);
-
-       /* Make sure HW enable masks are updated */
-
-       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-       if (ACPI_FAILURE(status))
-               return_ACPI_STATUS(status);
-
-       /* Clear the GPE (of stale events), then enable it */
-       status = acpi_hw_clear_gpe(gpe_event_info);
-       if (ACPI_FAILURE(status))
-               return_ACPI_STATUS(status);
-
-       /* Enable the requested GPE */
-       status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
-       return_ACPI_STATUS(status);
-}
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_disable_gpe
+ * FUNCTION:    acpi_ev_low_get_gpe_info
  *
- * PARAMETERS:  gpe_event_info          - GPE to disable
+ * PARAMETERS:  gpe_number          - Raw GPE number
+ *              gpe_block           - A GPE info block
  *
- * RETURN:      Status
+ * RETURN:      A GPE event_info struct. NULL if not a valid GPE (The gpe_number
+ *              is not within the specified GPE block)
  *
- * DESCRIPTION: Disable a GPE based on the GPE type
+ * DESCRIPTION: Returns the event_info struct associated with this GPE. This is
+ *              the low-level implementation of ev_get_gpe_event_info.
  *
  ******************************************************************************/
 
-acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
+                                                    struct acpi_gpe_block_info
+                                                    *gpe_block)
 {
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_disable_gpe);
-
-       /* Make sure HW enable masks are updated */
-
-       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-       if (ACPI_FAILURE(status))
-               return_ACPI_STATUS(status);
+       u32 gpe_index;
 
        /*
-        * Even if we don't know the GPE type, make sure that we always
-        * disable it. low_disable_gpe will just clear the enable bit for this
-        * GPE and write it. It will not write out the current GPE enable mask,
-        * since this may inadvertently enable GPEs too early, if a rogue GPE has
-        * come in during ACPICA initialization - possibly as a result of AML or
-        * other code that has enabled the GPE.
+        * Validate that the gpe_number is within the specified gpe_block.
+        * (Two steps)
         */
-       status = acpi_hw_low_disable_gpe(gpe_event_info);
-       return_ACPI_STATUS(status);
+       if (!gpe_block || (gpe_number < gpe_block->block_base_number)) {
+               return (NULL);
+       }
+
+       gpe_index = gpe_number - gpe_block->block_base_number;
+       if (gpe_index >= gpe_block->gpe_count) {
+               return (NULL);
+       }
+
+       return (&gpe_block->event_info[gpe_index]);
 }
 
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_get_gpe_event_info
@@ -184,29 +159,23 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
                                                       u32 gpe_number)
 {
        union acpi_operand_object *obj_desc;
-       struct acpi_gpe_block_info *gpe_block;
+       struct acpi_gpe_event_info *gpe_info;
        u32 i;
 
        ACPI_FUNCTION_ENTRY();
 
-       /* A NULL gpe_block means use the FADT-defined GPE block(s) */
+       /* A NULL gpe_device means use the FADT-defined GPE block(s) */
 
        if (!gpe_device) {
 
                /* Examine GPE Block 0 and 1 (These blocks are permanent) */
 
                for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) {
-                       gpe_block = acpi_gbl_gpe_fadt_blocks[i];
-                       if (gpe_block) {
-                               if ((gpe_number >= gpe_block->block_base_number)
-                                   && (gpe_number <
-                                       gpe_block->block_base_number +
-                                       (gpe_block->register_count * 8))) {
-                                       return (&gpe_block->
-                                               event_info[gpe_number -
-                                                          gpe_block->
-                                                          block_base_number]);
-                               }
+                       gpe_info = acpi_ev_low_get_gpe_info(gpe_number,
+                                                           acpi_gbl_gpe_fadt_blocks
+                                                           [i]);
+                       if (gpe_info) {
+                               return (gpe_info);
                        }
                }
 
@@ -223,16 +192,8 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
                return (NULL);
        }
 
-       gpe_block = obj_desc->device.gpe_block;
-
-       if ((gpe_number >= gpe_block->block_base_number) &&
-           (gpe_number <
-            gpe_block->block_base_number + (gpe_block->register_count * 8))) {
-               return (&gpe_block->
-                       event_info[gpe_number - gpe_block->block_base_number]);
-       }
-
-       return (NULL);
+       return (acpi_ev_low_get_gpe_info
+               (gpe_number, obj_desc->device.gpe_block));
 }
 
 /*******************************************************************************
@@ -389,10 +350,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
                return_VOID;
        }
 
-       /* Set the GPE flags for return to enabled state */
-
-       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
-
        /*
         * Take a snapshot of the GPE info for this level - we copy the info to
         * prevent a race condition with remove_handler/remove_block.
@@ -499,7 +456,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                status = acpi_hw_clear_gpe(gpe_event_info);
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
-                                       "Unable to clear GPE[%2X]",
+                                       "Unable to clear GPE[0x%2X]",
                                        gpe_number));
                        return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
                }
@@ -532,7 +489,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                        status = acpi_hw_clear_gpe(gpe_event_info);
                        if (ACPI_FAILURE(status)) {
                                ACPI_EXCEPTION((AE_INFO, status,
-                                               "Unable to clear GPE[%2X]",
+                                       "Unable to clear GPE[0x%2X]",
                                                gpe_number));
                                return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
                        }
@@ -545,10 +502,10 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                 * Disable the GPE, so it doesn't keep firing before the method has a
                 * chance to run (it runs asynchronously with interrupts enabled).
                 */
-               status = acpi_ev_disable_gpe(gpe_event_info);
+               status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
-                                       "Unable to disable GPE[%2X]",
+                                       "Unable to disable GPE[0x%2X]",
                                        gpe_number));
                        return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
                }
@@ -562,27 +519,30 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                                         gpe_event_info);
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
-                                       "Unable to queue handler for GPE[%2X] - event disabled",
+                                       "Unable to queue handler for GPE[0x%2X] - event disabled",
                                        gpe_number));
                }
                break;
 
        default:
 
-               /* No handler or method to run! */
-
+               /*
+                * No handler or method to run!
+                * 03/2010: This case should no longer be possible. We will not allow
+                * a GPE to be enabled if it has no handler or method.
+                */
                ACPI_ERROR((AE_INFO,
-                           "No handler or method for GPE[%2X], disabling event",
+                           "No handler or method for GPE[0x%2X], disabling event",
                            gpe_number));
 
                /*
-                * Disable the GPE. The GPE will remain disabled until the ACPICA
-                * Core Subsystem is restarted, or a handler is installed.
+                * Disable the GPE. The GPE will remain disabled a handler
+                * is installed or ACPICA is restarted.
                 */
-               status = acpi_ev_disable_gpe(gpe_event_info);
+               status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
-                                       "Unable to disable GPE[%2X]",
+                                       "Unable to disable GPE[0x%2X]",
                                        gpe_number));
                        return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
                }