sys/external/bsd/acpica/dist/events/evgpeinit.c
author christos <christos@NetBSD.org>
Tue, 18 Aug 2015 09:53:33 +0000
branchtrunk
changeset 237198 b816d1d365c1
parent 234620 e7ce51fddfdc
child 240046 f07d95be48eb
permissions -rw-r--r--
---------------------------------------- 17 July 2015. Summary of changes for version 20150717: 1) ACPICA kernel-resident subsystem: Improved the partitioning between the Debugger and Disassembler components. This allows the Debugger to be used standalone within kernel code without the Disassembler (which is used for single stepping also). This renames and moves one file, dmobject.c to dbobject.c. Lv Zheng. Debugger: Implemented a new command to trace the execution of control methods (Trace). This is especially useful for the in-kernel version of the debugger when file I/O may not be available for method trace output. See the ACPICA reference for more information. Lv Zheng. Moved all C library prototypes (used for the local versions of these functions when requested) to a new header, acclib.h Cleaned up the use of non-ANSI C library functions. These functions are implemented locally in ACPICA. Moved all such functions to a common source file, utnonansi.c Debugger: Fixed a problem with the "!!" command (get last command executed) where the debugger could enter an infinite loop and eventually crash. Removed the use of local macros that were used for some of the standard C library functions to automatically cast input parameters. This mostly affected the is* functions where the input parameter is defined to be an int. This required a few modifications to the main ACPICA source code to provide casting for these functions and eliminate possible compiler warnings for these parameters. Across the source code, added additional status/error checking to resolve issues discovered by static source code analysis tools such as Coverity. Example Code and Data Size: These are the sizes for the OS-independent acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The debug version of the code includes the debug output trace mechanism and has a much larger code and data size. Current Release: Non-Debug Version: 100.9K Code, 24.5K Data, 125.4K Total Debug Version: 197.8K Code, 81.5K Data, 279.3K Total Previous Release: Non-Debug Version: 100.6K Code, 27.6K Data, 128.2K Total Debug Version: 196.2K Code, 81.0K Data, 277.2K Total 2) iASL Compiler/Disassembler and Tools: iASL: Fixed a regression where the device map file feature no longer worked properly when used in conjunction with the disassembler. It only worked properly with the compiler itself. iASL: Implemented a new warning for method LocalX variables that are set but never used (similar to a C compiler such as gcc). This also applies to ArgX variables that are not defined by the parent method, and are instead (legally) used as local variables. iASL/Preprocessor: Finished the pass-through of line numbers from the preprocessor to the compiler. This ensures that compiler errors/warnings have the correct original line numbers and filenames, regardless of any #include files. iASL/Preprocessor: Fixed a couple of issues with comment handling and the pass-through of comments to the preprocessor output file (which becomes the compiler input file). Also fixed a problem with // comments that appear after a math expression. iASL: Added support for the TCPA server table to the table compiler and template generator. (The client table was already previously supported) iASL/Preprocessor: Added a permanent #define of the symbol "__IASL__" to identify the iASL compiler. Cleaned up the use of the macros NEGATIVE and POSITIVE which were defined multiple times. The new names are ACPI_SIGN_NEGATIVE and ACPI_SIGN_POSITIVE. AcpiHelp: Update to expand help messages for the iASL preprocessor directives. ---------------------------------------- 19 June 2015. Summary of changes for version 20150619: Two regressions in version 20150616 have been addressed: Fixes some problems/issues with the C library macro removal (ACPI_STRLEN, etc.) This update changes ACPICA to only use the standard headers for functions, or the prototypes for the local versions of the C library functions. Across the source code, this required some additional casts for some Clib invocations for portability. Moved all local prototypes to a new file, acclib.h Fixes several problems with recent changes to the handling of the FACS table that could cause some systems not to boot. ---------------------------------------- 16 June 2015. Summary of changes for version 20150616: 1) ACPICA kernel-resident subsystem: Across the entire ACPICA source code base, the various macros for the C library functions (such as ACPI_STRLEN, etc.) have been removed and replaced by the standard C library names (strlen, etc.) The original purpose for these macros is no longer applicable. This simplification reduces the number of macros used in the ACPICA source code significantly, improving readability and maintainability. Implemented support for a new ACPI table, the OSDT. This table, the "override" SDT, can be loaded directly by the host OS at boot time. It enables the replacement of existing namespace objects that were installed via the DSDT and/or SSDTs. The primary purpose for this is to replace buggy or incorrect ASL/AML code obtained via the BIOS. The OSDT is slated for inclusion in a future version of the ACPI Specification. Lv Zheng/Bob Moore. Added support for systems with (improperly) two FACS tables -- a "32-bit" table (via FADT 32-bit legacy field) and a "64-bit" table (via the 64-bit X field). This change will support both automatically. There continues to be systems found with this issue. This support requires a change to the AcpiSetFirmwareWakingVector interface. Also, a public global variable has been added to allow the host to select which FACS is desired (AcpiGbl_Use32BitFacsAddresses). See the ACPICA reference for more details Lv Zheng. Added a new feature to allow for systems that do not contain an FACS. Although this is already supported on hardware-reduced platforms, the feature has been extended for all platforms. The reasoning is that we do not want to abort the entire ACPICA initialization just because the system is seriously buggy and has no FACS. Fixed a problem where the GUID strings for NFIT tables (in acuuid.h) were not correctly transcribed from the ACPI specification in ACPICA version 20150515. Implemented support for the _CLS object in the AcpiGetObjectInfo external interface. Updated the definitions of the TCPA and TPM2 ACPI tables to the more recent TCG ACPI Specification, December 14, 2014. Table disassembler and compiler also updated. Note: The TCPA "server" table is not supported by the disassembler/table-compiler at this time. ACPI 6.0: Added definitions for the new GIC version field in the MADT. Example Code and Data Size: These are the sizes for the OS-independent acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The debug version of the code includes the debug output trace mechanism and has a much larger code and data size. Current Release: Non-Debug Version: 100.6K Code, 27.6K Data, 128.2K Total Debug Version: 196.2K Code, 81.0K Data, 277.2K Total Previous Release: Non-Debug Version: 99.9K Code, 27.5K Data, 127.4K Total Debug Version: 195.2K Code, 80.8K Data, 276.0K Total 2) iASL Compiler/Disassembler and Tools: Disassembler: Fixed a problem with the new symbolic operator disassembler where incorrect ASL code could be emitted in some cases for the "non- commutative" operators -- Subtract, Divide, Modulo, ShiftLeft, and ShiftRight. The actual problem cases seem to be rather unusual in common ASL code, however. David Box. Modified the linux version of acpidump to obtain ACPI tables from not just /dev/mem (which may not exist) and /sys/firmware/acpi/tables. Lv Zheng. iASL: Fixed a problem where the user preprocessor output file (.i) contained extra data that was not expected. The compiler was using this file as a temporary file and passed through #line directives in order to keep compiler error messages in sync with the input file and line number across multiple include files. The (.i) is no longer a temporary file as the compiler uses a new, different file for the original purpose. iASL: Fixed a problem where comments within the original ASL source code file were not passed through to the preprocessor output file, nor any listing files. iASL: Fixed some issues for the handling of the "#include" preprocessor directive and the similar (but not the same) "Include" ASL operator. iASL: Add support for the new OSDT in both the disassembler and compiler. iASL: Fixed a problem with the constant folding support where a Buffer object could be incorrectly generated (incorrectly formed) during a conversion to a Store() operator. AcpiHelp: Updated for new NFIT GUIDs, "External" AML opcode, and new description text for the _REV predefined name. _REV now permanently returns 2, as per the ACPI 6.0 specification. Debugger: Enhanced the output of the Debug ASL object for references produced by the Index operator. For Buffers and strings, only output the actual byte pointed to by the index. For packages, only print the single package element decoded by the index. Previously, the entire buffer/string/package was emitted. iASL/Table-compiler: Fixed a regression where the "generic" data types were no longer recognized, causing errors. ---------------------------------------- 15 May 2015. Summary of changes for version 20150515: This release implements most of ACPI 6.0 as described below. 1) ACPICA kernel-resident subsystem: Implemented runtime argument checking and return value checking for all new ACPI 6.0 predefined names. This includes: _BTH, _CR3, _DSD, _LPI, _MTL, _PRR, _RDI, _RST, _TFP, _TSN. Example Code and Data Size: These are the sizes for the OS-independent acpica.lib produced by the Microsoft Visual C++ 9.0 32-bit compiler. The debug version of the code includes the debug output trace mechanism and has a much larger code and data size. Current Release: Non-Debug Version: 99.9K Code, 27.5K Data, 127.4K Total Debug Version: 195.2K Code, 80.8K Data, 276.0K Total Previous Release: Non-Debug Version: 99.1K Code, 27.3K Data, 126.4K Total Debug Version: 192.8K Code, 79.9K Data, 272.7K Total 2) iASL Compiler/Disassembler and Tools: iASL compiler: Added compile-time support for all new ACPI 6.0 predefined names (argument count validation and return value typechecking.) iASL disassembler and table compiler: implemented support for all new ACPI 6.0 tables. This includes: DRTM, IORT, LPIT, NFIT, STAO, WPBT, XENV. iASL disassembler and table compiler: Added ACPI 6.0 changes to existing tables: FADT, MADT. iASL preprocessor: Added a new directive to enable inclusion of binary blobs into ASL code. The new directive is #includebuffer. It takes a binary file as input and emits a named ascii buffer object into the ASL code. AcpiHelp: Added support for all new ACPI 6.0 predefined names. AcpiHelp: Added a new option, -d, to display all iASL preprocessor directives. AcpiHelp: Added a new option, -t, to display all known/supported ACPI tables.

/******************************************************************************
 *
 * Module Name: evgpeinit - System GPE initialization and update
 *
 *****************************************************************************/

/*
 * Copyright (C) 2000 - 2015, Intel Corp.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include "acpi.h"
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"

#define _COMPONENT          ACPI_EVENTS
        ACPI_MODULE_NAME    ("evgpeinit")

#if (!ACPI_REDUCED_HARDWARE) /* Entire module */

/*
 * Note: History of _PRW support in ACPICA
 *
 * Originally (2000 - 2010), the GPE initialization code performed a walk of
 * the entire namespace to execute the _PRW methods and detect all GPEs
 * capable of waking the system.
 *
 * As of 10/2010, the _PRW method execution has been removed since it is
 * actually unnecessary. The host OS must in fact execute all _PRW methods
 * in order to identify the device/power-resource dependencies. We now put
 * the onus on the host OS to identify the wake GPEs as part of this process
 * and to inform ACPICA of these GPEs via the AcpiSetupGpeForWake interface. This
 * not only reduces the complexity of the ACPICA initialization code, but in
 * some cases (on systems with very large namespaces) it should reduce the
 * kernel boot time as well.
 */

/*******************************************************************************
 *
 * FUNCTION:    AcpiEvGpeInitialize
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Initialize the GPE data structures and the FADT GPE 0/1 blocks
 *
 ******************************************************************************/

ACPI_STATUS
AcpiEvGpeInitialize (
    void)
{
    UINT32                  RegisterCount0 = 0;
    UINT32                  RegisterCount1 = 0;
    UINT32                  GpeNumberMax = 0;
    ACPI_STATUS             Status;


    ACPI_FUNCTION_TRACE (EvGpeInitialize);


    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
        "Initializing General Purpose Events (GPEs):\n"));

    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
    if (ACPI_FAILURE (Status))
    {
        return_ACPI_STATUS (Status);
    }

    /*
     * Initialize the GPE Block(s) defined in the FADT
     *
     * Why the GPE register block lengths are divided by 2:  From the ACPI
     * Spec, section "General-Purpose Event Registers", we have:
     *
     * "Each register block contains two registers of equal length
     *  GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
     *  GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
     *  The length of the GPE1_STS and GPE1_EN registers is equal to
     *  half the GPE1_LEN. If a generic register block is not supported
     *  then its respective block pointer and block length values in the
     *  FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
     *  to be the same size."
     */

    /*
     * Determine the maximum GPE number for this machine.
     *
     * Note: both GPE0 and GPE1 are optional, and either can exist without
     * the other.
     *
     * If EITHER the register length OR the block address are zero, then that
     * particular block is not supported.
     */
    if (AcpiGbl_FADT.Gpe0BlockLength &&
        AcpiGbl_FADT.XGpe0Block.Address)
    {
        /* GPE block 0 exists (has both length and address > 0) */

        RegisterCount0 = (UINT16) (AcpiGbl_FADT.Gpe0BlockLength / 2);
        GpeNumberMax = (RegisterCount0 * ACPI_GPE_REGISTER_WIDTH) - 1;

        /* Install GPE Block 0 */

        Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice,
                    AcpiGbl_FADT.XGpe0Block.Address,
                    AcpiGbl_FADT.XGpe0Block.SpaceId,
                    RegisterCount0, 0,
                    AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[0]);

        if (ACPI_FAILURE (Status))
        {
            ACPI_EXCEPTION ((AE_INFO, Status,
                "Could not create GPE Block 0"));
        }
    }

    if (AcpiGbl_FADT.Gpe1BlockLength &&
        AcpiGbl_FADT.XGpe1Block.Address)
    {
        /* GPE block 1 exists (has both length and address > 0) */

        RegisterCount1 = (UINT16) (AcpiGbl_FADT.Gpe1BlockLength / 2);

        /* Check for GPE0/GPE1 overlap (if both banks exist) */

        if ((RegisterCount0) &&
            (GpeNumberMax >= AcpiGbl_FADT.Gpe1Base))
        {
            ACPI_ERROR ((AE_INFO,
                "GPE0 block (GPE 0 to %u) overlaps the GPE1 block "
                "(GPE %u to %u) - Ignoring GPE1",
                GpeNumberMax, AcpiGbl_FADT.Gpe1Base,
                AcpiGbl_FADT.Gpe1Base +
                ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1)));

            /* Ignore GPE1 block by setting the register count to zero */

            RegisterCount1 = 0;
        }
        else
        {
            /* Install GPE Block 1 */

            Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice,
                        AcpiGbl_FADT.XGpe1Block.Address,
                        AcpiGbl_FADT.XGpe1Block.SpaceId,
                        RegisterCount1,
                        AcpiGbl_FADT.Gpe1Base,
                        AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[1]);

            if (ACPI_FAILURE (Status))
            {
                ACPI_EXCEPTION ((AE_INFO, Status,
                    "Could not create GPE Block 1"));
            }

            /*
             * GPE0 and GPE1 do not have to be contiguous in the GPE number
             * space. However, GPE0 always starts at GPE number zero.
             */
            GpeNumberMax = AcpiGbl_FADT.Gpe1Base +
                            ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1);
        }
    }

    /* Exit if there are no GPE registers */

    if ((RegisterCount0 + RegisterCount1) == 0)
    {
        /* GPEs are not required by ACPI, this is OK */

        ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
            "There are no GPE blocks defined in the FADT\n"));
        Status = AE_OK;
        goto Cleanup;
    }


Cleanup:
    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
    return_ACPI_STATUS (AE_OK);
}


/*******************************************************************************
 *
 * FUNCTION:    AcpiEvUpdateGpes
 *
 * PARAMETERS:  TableOwnerId        - ID of the newly-loaded ACPI table
 *
 * RETURN:      None
 *
 * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
 *              result of a Load() or LoadTable() operation. If new GPE
 *              methods have been installed, register the new methods.
 *
 ******************************************************************************/

void
AcpiEvUpdateGpes (
    ACPI_OWNER_ID           TableOwnerId)
{
    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo;
    ACPI_GPE_BLOCK_INFO     *GpeBlock;
    ACPI_GPE_WALK_INFO      WalkInfo;
    ACPI_STATUS             Status = AE_OK;


    /*
     * Find any _Lxx/_Exx GPE methods that have just been loaded.
     *
     * Any GPEs that correspond to new _Lxx/_Exx methods are immediately
     * enabled.
     *
     * Examine the namespace underneath each GpeDevice within the
     * GpeBlock lists.
     */
    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
    if (ACPI_FAILURE (Status))
    {
        return;
    }

    WalkInfo.Count = 0;
    WalkInfo.OwnerId = TableOwnerId;
    WalkInfo.ExecuteByOwnerId = TRUE;

    /* Walk the interrupt level descriptor list */

    GpeXruptInfo = AcpiGbl_GpeXruptListHead;
    while (GpeXruptInfo)
    {
        /* Walk all Gpe Blocks attached to this interrupt level */

        GpeBlock = GpeXruptInfo->GpeBlockListHead;
        while (GpeBlock)
        {
            WalkInfo.GpeBlock = GpeBlock;
            WalkInfo.GpeDevice = GpeBlock->Node;

            Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD,
                        WalkInfo.GpeDevice, ACPI_UINT32_MAX,
                        ACPI_NS_WALK_NO_UNLOCK, AcpiEvMatchGpeMethod,
                        NULL, &WalkInfo, NULL);
            if (ACPI_FAILURE (Status))
            {
                ACPI_EXCEPTION ((AE_INFO, Status,
                    "While decoding _Lxx/_Exx methods"));
            }

            GpeBlock = GpeBlock->Next;
        }

        GpeXruptInfo = GpeXruptInfo->Next;
    }

    if (WalkInfo.Count)
    {
        ACPI_INFO ((AE_INFO, "Enabled %u new GPEs", WalkInfo.Count));
    }

    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
    return;
}


/*******************************************************************************
 *
 * FUNCTION:    AcpiEvMatchGpeMethod
 *
 * PARAMETERS:  Callback from WalkNamespace
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Called from AcpiWalkNamespace. Expects each object to be a
 *              control method under the _GPE portion of the namespace.
 *              Extract the name and GPE type from the object, saving this
 *              information for quick lookup during GPE dispatch. Allows a
 *              per-OwnerId evaluation if ExecuteByOwnerId is TRUE in the
 *              WalkInfo parameter block.
 *
 *              The name of each GPE control method is of the form:
 *              "_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]
 *
 * If WalkInfo->ExecuteByOwnerId is TRUE, we only execute examine GPE methods
 * with that owner.
 *
 ******************************************************************************/

ACPI_STATUS
AcpiEvMatchGpeMethod (
    ACPI_HANDLE             ObjHandle,
    UINT32                  Level,
    void                    *Context,
    void                    **ReturnValue)
{
    ACPI_NAMESPACE_NODE     *MethodNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
    ACPI_GPE_WALK_INFO      *WalkInfo = ACPI_CAST_PTR (ACPI_GPE_WALK_INFO, Context);
    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
    UINT32                  GpeNumber;
    char                    Name[ACPI_NAME_SIZE + 1];
    UINT8                   Type;


    ACPI_FUNCTION_TRACE (EvMatchGpeMethod);


    /* Check if requested OwnerId matches this OwnerId */

    if ((WalkInfo->ExecuteByOwnerId) &&
        (MethodNode->OwnerId != WalkInfo->OwnerId))
    {
        return_ACPI_STATUS (AE_OK);
    }

    /*
     * Match and decode the _Lxx and _Exx GPE method names
     *
     * 1) Extract the method name and null terminate it
     */
    ACPI_MOVE_32_TO_32 (Name, &MethodNode->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 */
    }

    /*
     * 3) Edge/Level determination is based on the 2nd character
     *    of the method name
     */
    switch (Name[1])
    {
    case 'L':

        Type = ACPI_GPE_LEVEL_TRIGGERED;
        break;

    case 'E':

        Type = ACPI_GPE_EDGE_TRIGGERED;
        break;

    default:

        /* Unknown method type, just ignore it */

        ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
            "Ignoring unknown GPE method type: %s "
            "(name not of form _Lxx or _Exx)", Name));
        return_ACPI_STATUS (AE_OK);
    }

    /* 4) The last two characters of the name are the hex GPE Number */

    GpeNumber = strtoul (&Name[2], NULL, 16);
    if (GpeNumber == ACPI_UINT32_MAX)
    {
        /* Conversion failed; invalid method, just ignore it */

        ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
            "Could not extract GPE number from name: %s "
            "(name is not of form _Lxx or _Exx)", Name));
        return_ACPI_STATUS (AE_OK);
    }

    /* Ensure that we have a valid GPE number for this GPE block */

    GpeEventInfo = AcpiEvLowGetGpeInfo (GpeNumber, WalkInfo->GpeBlock);
    if (!GpeEventInfo)
    {
        /*
         * This GpeNumber 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);
    }

    if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
            ACPI_GPE_DISPATCH_HANDLER) ||
        (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
            ACPI_GPE_DISPATCH_RAW_HANDLER))
    {
        /* If there is already a handler, ignore this GPE method */

        return_ACPI_STATUS (AE_OK);
    }

    if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
            ACPI_GPE_DISPATCH_METHOD)
    {
        /*
         * If there is already a method, ignore this method. But check
         * for a type mismatch (if both the _Lxx AND _Exx exist)
         */
        if (Type != (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
        {
            ACPI_ERROR ((AE_INFO,
                "For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods",
                GpeNumber, GpeNumber, GpeNumber));
        }
        return_ACPI_STATUS (AE_OK);
    }

    /* Disable the GPE in case it's been enabled already. */

    (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);

    /*
     * Add the GPE information from above to the GpeEventInfo block for
     * use during dispatch of this GPE.
     */
    GpeEventInfo->Flags &= ~(ACPI_GPE_DISPATCH_MASK);
    GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_METHOD);
    GpeEventInfo->Dispatch.MethodNode = MethodNode;

    ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
        "Registered GPE method %s as GPE number 0x%.2X\n",
        Name, GpeNumber));
    return_ACPI_STATUS (AE_OK);
}

#endif /* !ACPI_REDUCED_HARDWARE */