Merge branch 'gpe-regression-fixes' into release
authorLen Brown <len.brown@intel.com>
Sat, 12 Jun 2010 04:51:49 +0000 (00:51 -0400)
committerLen Brown <len.brown@intel.com>
Sat, 12 Jun 2010 04:51:49 +0000 (00:51 -0400)
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/system.c
include/acpi/actypes.h

index 64d1e5c..c3f43da 100644 (file)
@@ -80,10 +80,6 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list);
 acpi_status
 acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info);
 
-acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
-
-acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
-
 struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
                                                       u32 gpe_number);
 
index 5900f13..3239158 100644 (file)
@@ -90,7 +90,11 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width);
 /*
  * hwgpe - GPE support
  */
-acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
+                            struct acpi_gpe_register_info *gpe_register_info);
+
+acpi_status
+acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action);
 
 acpi_status
 acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);
index a221ad4..7c2c336 100644 (file)
@@ -69,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);
 
@@ -78,9 +78,8 @@ 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 */
 
@@ -100,106 +99,6 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
        return_ACPI_STATUS(AE_OK);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_enable_gpe
- *
- * PARAMETERS:  gpe_event_info          - GPE to enable
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Hardware-enable a GPE. Always enables the GPE, regardless
- *              of type or number of references.
- *
- * Note: The GPE lock should be already acquired when this function is called.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-       acpi_status status;
-
-
-       ACPI_FUNCTION_TRACE(ev_enable_gpe);
-
-
-       /*
-        * 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);
-       }
-
-       /* Ensure the HW enable masks are current */
-
-       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* 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_write_gpe_enable_reg(gpe_event_info);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_disable_gpe
- *
- * PARAMETERS:  gpe_event_info          - GPE to disable
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Hardware-disable a GPE. Always disables the requested GPE,
- *              regardless of the type or number of references.
- *
- * Note: The GPE lock should be already acquired when this function is called.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_disable_gpe);
-
-
-       /*
-        * Note: Always disable the GPE, even if we think that that it is already
-        * disabled. It is possible that the AML or some other code has enabled
-        * the GPE behind our back.
-        */
-
-       /* Ensure the HW enable masks are current */
-
-       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /*
-        * Always H/W disable this GPE, even if we don't know the GPE type.
-        * Simply clear the enable bit for this particular GPE, but do not
-        * write out the current GPE enable mask since this may inadvertently
-        * enable GPEs too early. An example is a rogue GPE that has arrived
-        * during ACPICA initialization - possibly because AML or other code
-        * has enabled the GPE.
-        */
-       status = acpi_hw_low_disable_gpe(gpe_event_info);
-       return_ACPI_STATUS(status);
-}
-
 
 /*******************************************************************************
  *
@@ -451,10 +350,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
                return_VOID;
        }
 
-       /* Update the GPE register masks 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.
@@ -607,7 +502,7 @@ 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[0x%2X]",
@@ -644,7 +539,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                 * 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[0x%2X]",
index 7c28f2d..341a38c 100644 (file)
@@ -500,6 +500,19 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
 
                        gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
                        gpe_event_info = &gpe_block->event_info[gpe_index];
+                       gpe_number = gpe_index + gpe_block->block_base_number;
+
+                       /*
+                        * If the GPE has already been enabled for runtime
+                        * signaling, make sure it remains enabled, but do not
+                        * increment its reference counter.
+                        */
+                       if (gpe_event_info->runtime_count) {
+                               acpi_set_gpe(gpe_device, gpe_number,
+                                               ACPI_GPE_ENABLE);
+                               gpe_enabled_count++;
+                               continue;
+                       }
 
                        if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
                                wake_gpe_count++;
@@ -516,7 +529,6 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
 
                        /* Enable this GPE */
 
-                       gpe_number = gpe_index + gpe_block->block_base_number;
                        status = acpi_enable_gpe(gpe_device, gpe_number,
                                                 ACPI_GPE_TYPE_RUNTIME);
                        if (ACPI_FAILURE(status)) {
index cc82502..4a531cd 100644 (file)
@@ -719,13 +719,6 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
        handler->context = context;
        handler->method_node = gpe_event_info->dispatch.method_node;
 
-       /* Disable the GPE before installing the handler */
-
-       status = acpi_ev_disable_gpe(gpe_event_info);
-       if (ACPI_FAILURE (status)) {
-               goto unlock_and_exit;
-       }
-
        /* Install the handler */
 
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
index d5a5efc..d97b8dc 100644 (file)
@@ -208,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
@@ -249,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:
@@ -316,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;
@@ -343,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);
                }
        }
 
@@ -403,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;
@@ -424,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);
                }
        }
 
index bd72319..3450309 100644 (file)
@@ -57,21 +57,47 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 
 /******************************************************************************
  *
- * FUNCTION:   acpi_hw_low_disable_gpe
+ * FUNCTION:   acpi_hw_gpe_register_bit
+ *
+ * PARAMETERS: gpe_event_info      - Info block for the GPE
+ *             gpe_register_info   - Info block for the GPE register
+ *
+ * RETURN:     Status
+ *
+ * DESCRIPTION:        Compute GPE enable mask with one bit corresponding to the given
+ *             GPE set.
+ *
+ ******************************************************************************/
+
+u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
+                            struct acpi_gpe_register_info *gpe_register_info)
+{
+       return (u32)1 << (gpe_event_info->gpe_number -
+                               gpe_register_info->base_gpe_number);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:   acpi_hw_low_set_gpe
  *
  * PARAMETERS: gpe_event_info      - Info block for the GPE to be disabled
+ *             action              - Enable or disable
  *
  * RETURN:     Status
  *
- * DESCRIPTION: Disable a single GPE in the enable register.
+ * DESCRIPTION: Enable or disable a single GPE in its enable register.
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status
+acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
 {
        struct acpi_gpe_register_info *gpe_register_info;
        acpi_status status;
        u32 enable_mask;
+       u32 register_bit;
+
+       ACPI_FUNCTION_ENTRY();
 
        /* Get the info block for the entire GPE register */
 
@@ -87,11 +113,27 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
                return (status);
        }
 
-       /* Clear just the bit that corresponds to this GPE */
+       /* Set ot clear just the bit that corresponds to this GPE */
 
-       ACPI_CLEAR_BIT(enable_mask, ((u32)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);
+       switch (action) {
+       case ACPI_GPE_COND_ENABLE:
+               if (!(register_bit & gpe_register_info->enable_for_run))
+                       return (AE_BAD_PARAMETER);
+
+       case ACPI_GPE_ENABLE:
+               ACPI_SET_BIT(enable_mask, register_bit);
+               break;
+
+       case ACPI_GPE_DISABLE:
+               ACPI_CLEAR_BIT(enable_mask, register_bit);
+               break;
+
+       default:
+               ACPI_ERROR((AE_INFO, "Invalid action\n"));
+               return (AE_BAD_PARAMETER);
+       }
 
        /* Write the updated enable mask */
 
@@ -116,23 +158,11 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
 acpi_status
 acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
 {
-       struct acpi_gpe_register_info *gpe_register_info;
        acpi_status status;
 
        ACPI_FUNCTION_ENTRY();
 
-       /* Get the info block for the entire GPE register */
-
-       gpe_register_info = gpe_event_info->register_info;
-       if (!gpe_register_info) {
-               return (AE_NOT_EXIST);
-       }
-
-       /* Write the entire GPE (runtime) enable register */
-
-       status = acpi_hw_write(gpe_register_info->enable_for_run,
-                              &gpe_register_info->enable_address);
-
+       status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_COND_ENABLE);
        return (status);
 }
 
@@ -150,21 +180,28 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
 
 acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
 {
+       struct acpi_gpe_register_info *gpe_register_info;
        acpi_status status;
-       u8 register_bit;
+       u32 register_bit;
 
        ACPI_FUNCTION_ENTRY();
 
-       register_bit = (u8)(1 <<
-                           (gpe_event_info->gpe_number -
-                            gpe_event_info->register_info->base_gpe_number));
+       /* Get the info block for the entire GPE register */
+
+       gpe_register_info = gpe_event_info->register_info;
+       if (!gpe_register_info) {
+               return (AE_NOT_EXIST);
+       }
+
+       register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+                                               gpe_register_info);
 
        /*
         * Write a one to the appropriate bit in the status register to
         * clear this GPE.
         */
        status = acpi_hw_write(register_bit,
-                              &gpe_event_info->register_info->status_address);
+                              &gpe_register_info->status_address);
 
        return (status);
 }
@@ -187,7 +224,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
                       acpi_event_status * event_status)
 {
        u32 in_byte;
-       u8 register_bit;
+       u32 register_bit;
        struct acpi_gpe_register_info *gpe_register_info;
        acpi_status status;
        acpi_event_status local_event_status = 0;
@@ -204,9 +241,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
 
        /* Get the register bitmask for this GPE */
 
-       register_bit = (u8)(1 <<
-                           (gpe_event_info->gpe_number -
-                            gpe_event_info->register_info->base_gpe_number));
+       register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+                                               gpe_register_info);
 
        /* GPE currently enabled? (enabled for runtime?) */
 
index c79e789..f8db50a 100644 (file)
@@ -388,10 +388,12 @@ static ssize_t counter_set(struct kobject *kobj,
        if (index < num_gpes) {
                if (!strcmp(buf, "disable\n") &&
                                (status & ACPI_EVENT_FLAG_ENABLED))
-                       result = acpi_set_gpe(handle, index, ACPI_GPE_DISABLE);
+                       result = acpi_disable_gpe(handle, index,
+                                               ACPI_GPE_TYPE_RUNTIME);
                else if (!strcmp(buf, "enable\n") &&
                                !(status & ACPI_EVENT_FLAG_ENABLED))
-                       result = acpi_set_gpe(handle, index, ACPI_GPE_ENABLE);
+                       result = acpi_enable_gpe(handle, index,
+                                               ACPI_GPE_TYPE_RUNTIME);
                else if (!strcmp(buf, "clear\n") &&
                                (status & ACPI_EVENT_FLAG_SET))
                        result = acpi_clear_gpe(handle, index);
index bade172..d55f4a7 100644 (file)
@@ -663,10 +663,11 @@ typedef u32 acpi_event_status;
 #define ACPI_GPE_MAX                    0xFF
 #define ACPI_NUM_GPE                    256
 
-/* Actions for acpi_set_gpe */
+/* Actions for acpi_set_gpe and acpi_hw_low_set_gpe */
 
 #define ACPI_GPE_ENABLE                 0
 #define ACPI_GPE_DISABLE                1
+#define ACPI_GPE_COND_ENABLE            2
 
 /* gpe_types for acpi_enable_gpe and acpi_disable_gpe */