struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
                                                       u32 gpe_number);
 
+struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
+                                                    struct acpi_gpe_block_info
+                                                    *gpe_block);
+
 /*
  * evgpeblk
  */
 
 u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list);
 
-acpi_status
-acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info);
-
 acpi_status acpi_ev_gpe_initialize(void);
 
 /*
 
        struct acpi_gpe_register_info *register_info;   /* Backpointer to register info */
        u8 flags;               /* Misc info about this GPE */
        u8 gpe_number;          /* This GPE */
-       u8 runtime_count;
-       u8 wakeup_count;
+       u8 runtime_count;       /* References to a run GPE */
+       u8 wakeup_count;        /* References to a wake GPE */
 };
 
 /* Information about a GPE register pair, one per each status/enable pair in an array */
        struct acpi_gpe_event_info *event_info; /* One for each GPE */
        struct acpi_generic_address block_address;      /* Base address of the block */
        u32 register_count;     /* Number of register pairs in block */
+       u16 gpe_count;          /* Number of individual GPEs in block */
        u8 block_base_number;   /* Base GPE number for this block */
 };
 
 
  *
  * 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
  *
  ******************************************************************************/
 
            (1 <<
             (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
 
+       /* 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);
 }
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Enable a GPE based on the GPE type
+ * 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 status;
 
+
        ACPI_FUNCTION_TRACE(ev_enable_gpe);
 
-       /* Make sure HW enable masks are updated */
+
+       /*
+        * 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))
+       if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
+       }
+
+       /* Clear the GPE (of stale events) */
 
-       /* Clear the GPE (of stale events), then enable it */
        status = acpi_hw_clear_gpe(gpe_event_info);
-       if (ACPI_FAILURE(status))
+       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);
 }
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Disable a GPE based on the GPE type
+ * 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_FUNCTION_TRACE(ev_disable_gpe);
 
-       /* Make sure HW enable masks are updated */
+
+       /*
+        * 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))
+       if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
+       }
 
        /*
-        * 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.
+        * 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);
 }
 
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_low_get_gpe_info
+ *
+ * PARAMETERS:  gpe_number          - Raw GPE number
+ *              gpe_block           - A GPE info block
+ *
+ * RETURN:      A GPE event_info struct. NULL if not a valid GPE (The gpe_number
+ *              is not within the specified GPE block)
+ *
+ * DESCRIPTION: Returns the event_info struct associated with this GPE. This is
+ *              the low-level implementation of ev_get_gpe_event_info.
+ *
+ ******************************************************************************/
+
+struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
+                                                    struct acpi_gpe_block_info
+                                                    *gpe_block)
+{
+       u32 gpe_index;
+
+       /*
+        * Validate that the gpe_number is within the specified gpe_block.
+        * (Two steps)
+        */
+       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
                                                       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();
                /* 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);
                        }
                }
 
                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));
 }
 
 /*******************************************************************************
                return_VOID;
        }
 
-       /* Set the GPE flags for return to enabled state */
+       /* Update the GPE register masks for return to enabled state */
 
        (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
 
 
        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[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);
                if (ACPI_FAILURE(status)) {
 
 
 /* Local prototypes */
 static acpi_status
-acpi_ev_save_method_info(acpi_handle obj_handle,
+acpi_ev_match_gpe_method(acpi_handle obj_handle,
                         u32 level, void *obj_desc, void **return_value);
 
 static acpi_status
 
                while (gpe_block) {
                        if ((&gpe_block->event_info[0] <= gpe_event_info) &&
-                           (&gpe_block->event_info[((acpi_size)
-                                                    gpe_block->
-                                                    register_count) * 8] >
+                           (&gpe_block->event_info[gpe_block->gpe_count] >
                             gpe_event_info)) {
                                return (TRUE);
                        }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_save_method_info
+ * FUNCTION:    acpi_ev_match_gpe_method
  *
  * PARAMETERS:  Callback from walk_namespace
  *
  *              information for quick lookup during GPE dispatch
  *
  *              The name of each GPE control method is of the form:
- *              "_Lxx" or "_Exx"
- *              Where:
+ *              "_Lxx" or "_Exx", where:
  *                  L      - means that the GPE is level triggered
  *                  E      - means that the GPE is edge triggered
  *                  xx     - is the GPE number [in HEX]
  ******************************************************************************/
 
 static acpi_status
-acpi_ev_save_method_info(acpi_handle obj_handle,
+acpi_ev_match_gpe_method(acpi_handle obj_handle,
                         u32 level, void *obj_desc, void **return_value)
 {
+       struct acpi_namespace_node *method_node =
+           ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
        struct acpi_gpe_block_info *gpe_block = (void *)obj_desc;
        struct acpi_gpe_event_info *gpe_event_info;
        u32 gpe_number;
        ACPI_FUNCTION_TRACE(ev_save_method_info);
 
        /*
-        * _Lxx and _Exx GPE method support
+        * Match and decode the _Lxx and _Exx GPE method names
         *
-        * 1) Extract the name from the object and convert to a string
+        * 1) Extract the method name and null terminate it
         */
-       ACPI_MOVE_32_TO_32(name,
-                          &((struct acpi_namespace_node *)obj_handle)->name.
-                          integer);
+       ACPI_MOVE_32_TO_32(name, &method_node->name.integer);
        name[ACPI_NAME_SIZE] = 0;
 
+       /* 2) Name must begin with an underscore */
+
+       if (name[0] != '_') {
+               return_ACPI_STATUS(AE_OK);      /* Ignore this method */
+       }
+
        /*
-        * 2) Edge/Level determination is based on the 2nd character
+        * 3) Edge/Level determination is based on the 2nd character
         *    of the method name
         *
-        * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE
-        * if a _PRW object is found that points to this GPE.
+        * NOTE: Default GPE type is RUNTIME only. Later, if a _PRW object is
+        * found that points to this GPE, the ACPI_GPE_CAN_WAKE flag is set.
         */
        switch (name[1]) {
        case 'L':
                break;
 
        default:
-               /* Unknown method type, just ignore it! */
+               /* Unknown method type, just ignore it */
 
                ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
                                  "Ignoring unknown GPE method type: %s "
                return_ACPI_STATUS(AE_OK);
        }
 
-       /* Convert the last two characters of the name to the GPE Number */
+       /* 4) The last two characters of the name are the hex GPE Number */
 
        gpe_number = ACPI_STRTOUL(&name[2], NULL, 16);
        if (gpe_number == ACPI_UINT32_MAX) {
 
        /* Ensure that we have a valid GPE number for this GPE block */
 
-       if ((gpe_number < gpe_block->block_base_number) ||
-           (gpe_number >= (gpe_block->block_base_number +
-                           (gpe_block->register_count * 8)))) {
+       gpe_event_info = acpi_ev_low_get_gpe_info(gpe_number, gpe_block);
+       if (!gpe_event_info) {
                /*
-                * Not valid for this GPE block, just ignore it. However, it may be
-                * valid for a different GPE block, since GPE0 and GPE1 methods both
-                * appear under \_GPE.
+                * This gpe_number is not valid for this GPE block, just ignore it.
+                * However, it may be valid for a different GPE block, since GPE0
+                * and GPE1 methods both appear under \_GPE.
                 */
                return_ACPI_STATUS(AE_OK);
        }
 
        /*
-        * Now we can add this information to the gpe_event_info block for use
-        * during dispatch of this GPE.
+        * Add the GPE information from above to the gpe_event_info block for
+        * use during dispatch of this GPE.
         */
-       gpe_event_info =
-           &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
-
-       gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD);
-
-       gpe_event_info->dispatch.method_node =
-           (struct acpi_namespace_node *)obj_handle;
+       gpe_event_info->flags = (u8)(type | ACPI_GPE_DISPATCH_METHOD);
+       gpe_event_info->dispatch.method_node = method_node;
 
        ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
                          "Registered GPE method %s as GPE number 0x%.2X\n",
  *
  * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
  *              Device. Run the _PRW method. If present, extract the GPE
- *              number and mark the GPE as a WAKE GPE.
+ *              number and mark the GPE as a CAN_WAKE GPE.
  *
  ******************************************************************************/
 
                                         ACPI_BTYPE_PACKAGE, &pkg_desc);
        if (ACPI_FAILURE(status)) {
 
-               /* Ignore all errors from _PRW, we don't want to abort the subsystem */
+               /* Ignore all errors from _PRW, we don't want to abort the walk */
 
                return_ACPI_STATUS(AE_OK);
        }
         *     2) The GPE index(number) is within the range of the Gpe Block
         *          associated with the GPE device.
         */
-       if ((gpe_device == target_gpe_device) &&
-           (gpe_number >= gpe_block->block_base_number) &&
-           (gpe_number < gpe_block->block_base_number +
-            (gpe_block->register_count * 8))) {
-               gpe_event_info = &gpe_block->event_info[gpe_number -
-                                                       gpe_block->
-                                                       block_base_number];
+       if (gpe_device != target_gpe_device) {
+               goto cleanup;
+       }
+
+       gpe_event_info = acpi_ev_low_get_gpe_info(gpe_number, gpe_block);
+       if (gpe_event_info) {
+               /* This GPE can wake the system */
 
                gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
        }
                acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        }
 
-       acpi_current_gpe_count -=
-           gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH;
+       acpi_current_gpe_count -= gpe_block->gpe_count;
 
        /* Free the gpe_block */
 
         * Allocate the GPE event_info block. There are eight distinct GPEs
         * per register. Initialization to zeros is sufficient.
         */
-       gpe_event_info = ACPI_ALLOCATE_ZEROED(((acpi_size) gpe_block->
-                                              register_count *
-                                              ACPI_GPE_REGISTER_WIDTH) *
+       gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->gpe_count *
                                              sizeof(struct
                                                     acpi_gpe_event_info));
        if (!gpe_event_info) {
        /* Initialize the new GPE block */
 
        gpe_block->node = gpe_device;
+       gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
        gpe_block->register_count = register_count;
        gpe_block->block_base_number = gpe_block_base_number;
 
 
        status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
                                        ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
-                                       acpi_ev_save_method_info, NULL,
+                                       acpi_ev_match_gpe_method, NULL,
                                        gpe_block, NULL);
 
        /* Return the new block */
                          "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
                          (u32) gpe_block->block_base_number,
                          (u32) (gpe_block->block_base_number +
-                                ((gpe_block->register_count *
-                                  ACPI_GPE_REGISTER_WIDTH) - 1)),
+                               (gpe_block->gpe_count - 1)),
                          gpe_device->name.ascii, gpe_block->register_count,
                          interrupt_number));
 
        /* Update global count of currently available GPEs */
 
-       acpi_current_gpe_count += register_count * ACPI_GPE_REGISTER_WIDTH;
+       acpi_current_gpe_count += gpe_block->gpe_count;
        return_ACPI_STATUS(AE_OK);
 }
 
 acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
                             struct acpi_gpe_block_info *gpe_block)
 {
+       acpi_status status;
        struct acpi_gpe_event_info *gpe_event_info;
        struct acpi_gpe_walk_info gpe_info;
        u32 wake_gpe_count;
        u32 gpe_enabled_count;
+       u32 gpe_index;
+       u32 gpe_number;
        u32 i;
        u32 j;
 
                gpe_info.gpe_block = gpe_block;
                gpe_info.gpe_device = gpe_device;
 
-               acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+               status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
                                           ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
                                           acpi_ev_match_prw_and_gpe, NULL,
                                           &gpe_info, NULL);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "While executing _PRW methods"));
+               }
        }
 
        /*
-        * Enable all GPEs that have a corresponding method and aren't
+        * Enable all GPEs that have a corresponding method and are not
         * capable of generating wakeups. Any other GPEs within this block
-        * must be enabled via the acpi_enable_gpe() interface.
+        * must be enabled via the acpi_enable_gpe interface.
         */
        wake_gpe_count = 0;
        gpe_enabled_count = 0;
-       if (gpe_device == acpi_gbl_fadt_gpe_device)
+
+       if (gpe_device == acpi_gbl_fadt_gpe_device) {
                gpe_device = NULL;
+       }
 
        for (i = 0; i < gpe_block->register_count; i++) {
                for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
-                       acpi_status status;
-                       acpi_size gpe_index;
-                       int gpe_number;
 
                        /* Get the info block for this particular GPE */
-                       gpe_index = (acpi_size)i * ACPI_GPE_REGISTER_WIDTH + j;
+
+                       gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
                        gpe_event_info = &gpe_block->event_info[gpe_index];
 
                        if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
                                wake_gpe_count++;
-                               if (acpi_gbl_leave_wake_gpes_disabled)
+                               if (acpi_gbl_leave_wake_gpes_disabled) {
                                        continue;
+                               }
                        }
 
-                       if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD))
+                       /* Ignore GPEs that have no corresponding _Lxx/_Exx method */
+
+                       if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) {
                                continue;
+                       }
+
+                       /* 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))
-                               ACPI_ERROR((AE_INFO,
-                                               "Failed to enable GPE %02X\n",
+                                                ACPI_GPE_TYPE_RUNTIME);
+                       if (ACPI_FAILURE(status)) {
+                               ACPI_EXCEPTION((AE_INFO, status,
+                                               "Could not enable GPE 0x%02X",
                                                gpe_number));
-                       else
-                               gpe_enabled_count++;
+                               continue;
+                       }
+
+                       gpe_enabled_count++;
                }
        }
 
 
 
        /* Parameter validation */
 
-       if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
-               status = AE_BAD_PARAMETER;
-               goto exit;
+       if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) {
+               return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
        status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
        if (ACPI_FAILURE(status)) {
-               goto exit;
+               return_ACPI_STATUS(status);
        }
 
        /* Ensure that we have a valid GPE number */
        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);
 
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
-      unlock_and_exit:
+unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-      exit:
-       if (ACPI_FAILURE(status))
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Installing notify handler failed"));
        return_ACPI_STATUS(status);
 }
 
 
  *
  * FUNCTION:    acpi_set_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              action          - Enable or disable
- *                                Called from ISR or not
+ *              action          - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Enable or disable an ACPI event (general purpose)
+ * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
+ *              the reference count mechanism used in the acpi_enable_gpe and
+ *              acpi_disable_gpe interfaces -- and should be used with care.
+ *
+ * Note: Typically used to disable a runtime GPE for short period of time,
+ * then re-enable it, without disturbing the existing reference counts. This
+ * is useful, for example, in the Embedded Controller (EC) driver.
  *
  ******************************************************************************/
 acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
 {
-       acpi_status status = AE_OK;
-       acpi_cpu_flags flags;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_status status;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_set_gpe);
 
                break;
 
        default:
-               ACPI_ERROR((AE_INFO, "Invalid action\n"));
                status = AE_BAD_PARAMETER;
                break;
        }
  *
  * FUNCTION:    acpi_enable_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              type            - Purpose the GPE will be used for
+ *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
+ *                                or both
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Take a reference to a GPE and enable it if necessary
+ * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
+ *              hardware-enabled (for runtime GPEs), or the GPE register mask
+ *              is updated (for wake GPEs).
  *
  ******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
 {
        acpi_status status = AE_OK;
-       acpi_cpu_flags flags;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_enable_gpe);
 
-       if (type & ~ACPI_GPE_TYPE_WAKE_RUN)
+       /* Parameter validation */
+
+       if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
+       }
 
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
                goto unlock_and_exit;
        }
 
-       if (type & ACPI_GPE_TYPE_RUNTIME) {
-               if (++gpe_event_info->runtime_count == 1) {
+       if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
+               if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
+                       status = AE_LIMIT;      /* Too many references */
+                       goto unlock_and_exit;
+               }
+
+               gpe_event_info->runtime_count++;
+               if (gpe_event_info->runtime_count == 1) {
                        status = acpi_ev_enable_gpe(gpe_event_info);
-                       if (ACPI_FAILURE(status))
+                       if (ACPI_FAILURE(status)) {
                                gpe_event_info->runtime_count--;
+                               goto unlock_and_exit;
+                       }
                }
        }
 
-       if (type & ACPI_GPE_TYPE_WAKE) {
+       if (gpe_type & ACPI_GPE_TYPE_WAKE) {
+               /* The GPE must have the ability to wake the system */
+
                if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
-                       status = AE_BAD_PARAMETER;
+                       status = AE_TYPE;
+                       goto unlock_and_exit;
+               }
+
+               if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
+                       status = AE_LIMIT;      /* Too many references */
                        goto unlock_and_exit;
                }
 
                /*
-                * Wake-up GPEs are only enabled right prior to putting the
-                * system into a sleep state.
+                * Update the enable mask on the first wakeup reference. Wake GPEs
+                * are only hardware-enabled just before sleeping.
                 */
-               if (++gpe_event_info->wakeup_count == 1)
-                       acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               gpe_event_info->wakeup_count++;
+               if (gpe_event_info->wakeup_count == 1) {
+                       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               }
        }
 
 unlock_and_exit:
  *
  * FUNCTION:    acpi_disable_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              type            - Purpose the GPE won't be used for any more
+ *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
+ *                                or both
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Release a reference to a GPE and disable it if necessary
+ * DESCRIPTION: Remove a reference to a GPE. When the last reference is
+ *              removed, only then is the GPE disabled (for runtime GPEs), or
+ *              the GPE mask bit disabled (for wake GPEs)
  *
  ******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
 {
        acpi_status status = AE_OK;
-       acpi_cpu_flags flags;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_disable_gpe);
 
-       if (type & ~ACPI_GPE_TYPE_WAKE_RUN)
+       /* Parameter validation */
+
+       if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
+       }
 
        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);
                goto unlock_and_exit;
        }
 
-       if ((type & ACPI_GPE_TYPE_RUNTIME) && gpe_event_info->runtime_count) {
-               if (--gpe_event_info->runtime_count == 0)
+       /* Hardware-disable a runtime GPE on removal of the last reference */
+
+       if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
+               if (!gpe_event_info->runtime_count) {
+                       status = AE_LIMIT;      /* There are no references to remove */
+                       goto unlock_and_exit;
+               }
+
+               gpe_event_info->runtime_count--;
+               if (!gpe_event_info->runtime_count) {
                        status = acpi_ev_disable_gpe(gpe_event_info);
+                       if (ACPI_FAILURE(status)) {
+                               gpe_event_info->runtime_count++;
+                               goto unlock_and_exit;
+                       }
+               }
        }
 
-       if ((type & ACPI_GPE_TYPE_WAKE) && gpe_event_info->wakeup_count) {
-               /*
-                * Wake-up GPEs are not enabled after leaving system sleep
-                * states, so we don't need to disable them here.
-                */
-               if (--gpe_event_info->wakeup_count == 0)
-                       acpi_ev_update_gpe_enable_masks(gpe_event_info);
+       /*
+        * Update masks for wake GPE on removal of the last reference.
+        * No need to hardware-disable wake GPEs here, they are not currently
+        * enabled.
+        */
+       if (gpe_type & ACPI_GPE_TYPE_WAKE) {
+               if (!gpe_event_info->wakeup_count) {
+                       status = AE_LIMIT;      /* There are no references to remove */
+                       goto unlock_and_exit;
+               }
+
+               gpe_event_info->wakeup_count--;
+               if (!gpe_event_info->wakeup_count) {
+                       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               }
        }
 
 unlock_and_exit:
  *
  * FUNCTION:    acpi_clear_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              Flags           - Called from an ISR or not
  *
  * RETURN:      Status
  *
  * DESCRIPTION: Clear an ACPI event (general purpose)
  *
  ******************************************************************************/
-acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
+acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
 {
        acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_clear_gpe);
 
-       /* Use semaphore lock if not executing at interrupt level */
-
-       if (flags & ACPI_NOT_ISR) {
-               status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-       }
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
        /* Ensure that we have a valid GPE number */
 
        status = acpi_hw_clear_gpe(gpe_event_info);
 
       unlock_and_exit:
-       if (flags & ACPI_NOT_ISR) {
-               (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-       }
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
 
  *
  * FUNCTION:    acpi_get_gpe_status
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              Flags           - Called from an ISR or not
  *              event_status    - Where the current status of the event will
  *                                be returned
  *
  ******************************************************************************/
 acpi_status
 acpi_get_gpe_status(acpi_handle gpe_device,
-                   u32 gpe_number, u32 flags, acpi_event_status * event_status)
+                   u32 gpe_number, acpi_event_status *event_status)
 {
        acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
 
-       /* Use semaphore lock if not executing at interrupt level */
-
-       if (flags & ACPI_NOT_ISR) {
-               status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-       }
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
        /* Ensure that we have a valid GPE number */
 
                *event_status |= ACPI_EVENT_FLAG_HANDLE;
 
       unlock_and_exit:
-       if (flags & ACPI_NOT_ISR) {
-               (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-       }
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
 
                goto unlock_and_exit;
        }
 
-       /* Run the _PRW methods and enable the GPEs */
-
-       status = acpi_ev_initialize_gpe_block(node, gpe_block);
-       if (ACPI_FAILURE(status)) {
-               goto unlock_and_exit;
-       }
-
-       /* Get the device_object attached to the node */
+       /* Install block in the device_object attached to the node */
 
        obj_desc = acpi_ns_get_attached_object(node);
        if (!obj_desc) {
 
-               /* No object, create a new one */
-
+               /*
+                * No object, create a new one (Device nodes do not always have
+                * an attached object)
+                */
                obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
                if (!obj_desc) {
                        status = AE_NO_MEMORY;
                }
        }
 
-       /* Install the GPE block in the device_object */
+       /* Now install the GPE block in the device_object */
 
        obj_desc->device.gpe_block = gpe_block;
 
+       /* Run the _PRW methods and enable the runtime GPEs in the new block */
+
+       status = acpi_ev_initialize_gpe_block(node, gpe_block);
+
       unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(status);
 
        /* Increment Index by the number of GPEs in this block */
 
-       info->next_block_base_index +=
-           (gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH);
+       info->next_block_base_index += gpe_block->gpe_count;
 
        if (info->index < info->next_block_base_index) {
                /*
 
                        status = AE_AML_OPERAND_TYPE;
                        break;
                }
-#ifdef ACPI_GPE_NOTIFY_CHECK
-               /*
-                * GPE method wake/notify check.  Here, we want to ensure that we
-                * don't receive any "DeviceWake" Notifies from a GPE _Lxx or _Exx
-                * GPE method during system runtime.  If we do, the GPE is marked
-                * as "wake-only" and disabled.
-                *
-                * 1) Is the Notify() value == device_wake?
-                * 2) Is this a GPE deferred method?  (An _Lxx or _Exx method)
-                * 3) Did the original GPE happen at system runtime?
-                *    (versus during wake)
-                *
-                * If all three cases are true, this is a wake-only GPE that should
-                * be disabled at runtime.
-                */
-               if (value == 2) {       /* device_wake */
-                       status =
-                           acpi_ev_check_for_wake_only_gpe(walk_state->
-                                                           gpe_event_info);
-                       if (ACPI_FAILURE(status)) {
-
-                               /* AE_WAKE_ONLY_GPE only error, means ignore this notify */
-
-                               return_ACPI_STATUS(AE_OK)
-                       }
-               }
-#endif
 
                /*
                 * Dispatch the notify to the appropriate handler
 
        }
 
        status = acpi_get_gpe_status(NULL, device->wakeup.gpe_number,
-                                       ACPI_NOT_ISR, &event_status);
+                                       &event_status);
        if (status == AE_OK)
                device->wakeup.flags.run_wake =
                                !!(event_status & ACPI_EVENT_FLAG_HANDLE);
 
                                "Invalid GPE 0x%x\n", index));
                        goto end;
                }
-               result = acpi_get_gpe_status(*handle, index,
-                                               ACPI_NOT_ISR, status);
+               result = acpi_get_gpe_status(*handle, index, status);
        } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS))
                result = acpi_get_event_status(index - num_gpes, status);
 
                        result = acpi_set_gpe(handle, index, ACPI_GPE_ENABLE);
                else if (!strcmp(buf, "clear\n") &&
                                (status & ACPI_EVENT_FLAG_SET))
-                       result = acpi_clear_gpe(handle, index, ACPI_NOT_ISR);
+                       result = acpi_clear_gpe(handle, index);
                else
                        all_counters[index].count = strtoul(buf, NULL, 0);
        } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) {
 
 #define AE_NO_GLOBAL_LOCK               (acpi_status) (0x0017 | AE_CODE_ENVIRONMENTAL)
 #define AE_ABORT_METHOD                 (acpi_status) (0x0018 | AE_CODE_ENVIRONMENTAL)
 #define AE_SAME_HANDLER                 (acpi_status) (0x0019 | AE_CODE_ENVIRONMENTAL)
-#define AE_WAKE_ONLY_GPE                (acpi_status) (0x001A | AE_CODE_ENVIRONMENTAL)
+#define AE_NO_HANDLER                   (acpi_status) (0x001A | AE_CODE_ENVIRONMENTAL)
 #define AE_OWNER_ID_LIMIT               (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL)
 
 #define AE_CODE_ENV_MAX                 0x001B
 
  */
 acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action);
 
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type);
+acpi_status
+acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type);
 
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type);
+acpi_status
+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, u32 flags);
+acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number);
 
 acpi_status
 acpi_get_gpe_status(acpi_handle gpe_device,
-                   u32 gpe_number,
-                   u32 flags, acpi_event_status * event_status);
+                   u32 gpe_number, acpi_event_status *event_status);
 
 acpi_status acpi_disable_all_gpes(void);
 
 
 #define ACPI_GPE_MAX                    0xFF
 #define ACPI_NUM_GPE                    256
 
+/* Actions for acpi_set_gpe */
+
 #define ACPI_GPE_ENABLE                 0
 #define ACPI_GPE_DISABLE                1
 
+/* gpe_types for acpi_enable_gpe and acpi_disable_gpe */
+
+#define ACPI_GPE_TYPE_WAKE              (u8) 0x01
+#define ACPI_GPE_TYPE_RUNTIME           (u8) 0x02
+#define ACPI_GPE_TYPE_WAKE_RUN          (u8) 0x03
+
 /*
  * GPE info flags - Per GPE
- * +-+-+-+---+-+-+-+
- * |7|6|5|4:3|2|1|0|
- * +-+-+-+---+-+-+-+
- *  | | |  |  | | |
- *  | | |  |  | | +--- Interrupt type: Edge or Level Triggered
- *  | | |  |  | +--- GPE can wake the system
- *  | | |  |  +--- Unused
- *  | | |  +--- Type of dispatch -- to method, handler, or none
- *  | | +--- Unused
- *  | +--- Unused
- *  +--- Unused
+ * +-------+---+-+-+
+ * |  7:4  |3:2|1|0|
+ * +-------+---+-+-+
+ *     |     |  | |
+ *     |     |  | +--- Interrupt type: edge or level triggered
+ *     |     |  +----- GPE can wake the system
+ *     |     +-------- Type of dispatch:to method, handler, or none
+ *     +-------------- <Reserved>
  */
 #define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 0x01
 #define ACPI_GPE_LEVEL_TRIGGERED        (u8) 0x01
 #define ACPI_GPE_EDGE_TRIGGERED         (u8) 0x00
 
-#define ACPI_GPE_TYPE_MASK              (u8) 0x06
-#define ACPI_GPE_TYPE_WAKE_RUN          (u8) 0x06
-#define ACPI_GPE_TYPE_WAKE              (u8) 0x02
-#define ACPI_GPE_TYPE_RUNTIME           (u8) 0x04      /* Default */
 #define ACPI_GPE_CAN_WAKE              (u8) 0x02
 
-#define ACPI_GPE_DISPATCH_MASK          (u8) 0x18
-#define ACPI_GPE_DISPATCH_HANDLER       (u8) 0x08
-#define ACPI_GPE_DISPATCH_METHOD        (u8) 0x10
-#define ACPI_GPE_DISPATCH_NOT_USED      (u8) 0x00      /* Default */
+#define ACPI_GPE_DISPATCH_MASK          (u8) 0x0C
+#define ACPI_GPE_DISPATCH_HANDLER       (u8) 0x04
+#define ACPI_GPE_DISPATCH_METHOD        (u8) 0x08
+#define ACPI_GPE_DISPATCH_NOT_USED      (u8) 0x00
 
 /*
  * Flags for GPE and Lock interfaces
  */
-#define ACPI_EVENT_WAKE_ENABLE          0x2    /* acpi_gpe_enable */
-#define ACPI_EVENT_WAKE_DISABLE         0x2    /* acpi_gpe_disable */
-
 #define ACPI_NOT_ISR                    0x1
 #define ACPI_ISR                        0x0