diff options
| author | Jung-uk Kim <jkim@FreeBSD.org> | 2013-01-02 19:01:21 +0000 | 
|---|---|---|
| committer | Jung-uk Kim <jkim@FreeBSD.org> | 2013-01-02 19:01:21 +0000 | 
| commit | b28e481ae9b051dab150e9b5a89730cdc1103a9c (patch) | |
| tree | 434e706ece73a93073f350c91cd35ed7d7e98811 /source/components/events/evhandler.c | |
| parent | c2463a8709e5b3a5ce54c09d35b4820a756b0fc5 (diff) | |
Notes
Diffstat (limited to 'source/components/events/evhandler.c')
| -rw-r--r-- | source/components/events/evhandler.c | 578 | 
1 files changed, 578 insertions, 0 deletions
| diff --git a/source/components/events/evhandler.c b/source/components/events/evhandler.c new file mode 100644 index 0000000000000..609891a36fddb --- /dev/null +++ b/source/components/events/evhandler.c @@ -0,0 +1,578 @@ +/****************************************************************************** + * + * Module Name: evhandler - Support for Address Space handlers + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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. + */ + + +#define __EVHANDLER_C__ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" + +#define _COMPONENT          ACPI_EVENTS +        ACPI_MODULE_NAME    ("evhandler") + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiEvInstallHandler ( +    ACPI_HANDLE             ObjHandle, +    UINT32                  Level, +    void                    *Context, +    void                    **ReturnValue); + +/* These are the address spaces that will get default handlers */ + +UINT8        AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] = +{ +    ACPI_ADR_SPACE_SYSTEM_MEMORY, +    ACPI_ADR_SPACE_SYSTEM_IO, +    ACPI_ADR_SPACE_PCI_CONFIG, +    ACPI_ADR_SPACE_DATA_TABLE +}; + + +/******************************************************************************* + * + * FUNCTION:    AcpiEvInstallRegionHandlers + * + * PARAMETERS:  None + * + * RETURN:      Status + * + * DESCRIPTION: Installs the core subsystem default address space handlers. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInstallRegionHandlers ( +    void) +{ +    ACPI_STATUS             Status; +    UINT32                  i; + + +    ACPI_FUNCTION_TRACE (EvInstallRegionHandlers); + + +    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); +    if (ACPI_FAILURE (Status)) +    { +        return_ACPI_STATUS (Status); +    } + +    /* +     * All address spaces (PCI Config, EC, SMBus) are scope dependent and +     * registration must occur for a specific device. +     * +     * In the case of the system memory and IO address spaces there is +     * currently no device associated with the address space. For these we +     * use the root. +     * +     * We install the default PCI config space handler at the root so that +     * this space is immediately available even though the we have not +     * enumerated all the PCI Root Buses yet. This is to conform to the ACPI +     * specification which states that the PCI config space must be always +     * available -- even though we are nowhere near ready to find the PCI root +     * buses at this point. +     * +     * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler +     * has already been installed (via AcpiInstallAddressSpaceHandler). +     * Similar for AE_SAME_HANDLER. +     */ +    for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) +    { +        Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode, +                    AcpiGbl_DefaultAddressSpaces[i], +                    ACPI_DEFAULT_HANDLER, NULL, NULL); +        switch (Status) +        { +        case AE_OK: +        case AE_SAME_HANDLER: +        case AE_ALREADY_EXISTS: + +            /* These exceptions are all OK */ + +            Status = AE_OK; +            break; + +        default: + +            goto UnlockAndExit; +        } +    } + +UnlockAndExit: +    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); +    return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION:    AcpiEvHasDefaultHandler + * + * PARAMETERS:  Node                - Namespace node for the device + *              SpaceId             - The address space ID + * + * RETURN:      TRUE if default handler is installed, FALSE otherwise + * + * DESCRIPTION: Check if the default handler is installed for the requested + *              space ID. + * + ******************************************************************************/ + +BOOLEAN +AcpiEvHasDefaultHandler ( +    ACPI_NAMESPACE_NODE     *Node, +    ACPI_ADR_SPACE_TYPE     SpaceId) +{ +    ACPI_OPERAND_OBJECT     *ObjDesc; +    ACPI_OPERAND_OBJECT     *HandlerObj; + + +    /* Must have an existing internal object */ + +    ObjDesc = AcpiNsGetAttachedObject (Node); +    if (ObjDesc) +    { +        HandlerObj = ObjDesc->Device.Handler; + +        /* Walk the linked list of handlers for this object */ + +        while (HandlerObj) +        { +            if (HandlerObj->AddressSpace.SpaceId == SpaceId) +            { +                if (HandlerObj->AddressSpace.HandlerFlags & +                        ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) +                { +                    return (TRUE); +                } +            } + +            HandlerObj = HandlerObj->AddressSpace.Next; +        } +    } + +    return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION:    AcpiEvInstallHandler + * + * PARAMETERS:  WalkNamespace callback + * + * DESCRIPTION: This routine installs an address handler into objects that are + *              of type Region or Device. + * + *              If the Object is a Device, and the device has a handler of + *              the same type then the search is terminated in that branch. + * + *              This is because the existing handler is closer in proximity + *              to any more regions than the one we are trying to install. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvInstallHandler ( +    ACPI_HANDLE             ObjHandle, +    UINT32                  Level, +    void                    *Context, +    void                    **ReturnValue) +{ +    ACPI_OPERAND_OBJECT     *HandlerObj; +    ACPI_OPERAND_OBJECT     *NextHandlerObj; +    ACPI_OPERAND_OBJECT     *ObjDesc; +    ACPI_NAMESPACE_NODE     *Node; +    ACPI_STATUS             Status; + + +    ACPI_FUNCTION_NAME (EvInstallHandler); + + +    HandlerObj = (ACPI_OPERAND_OBJECT  *) Context; + +    /* Parameter validation */ + +    if (!HandlerObj) +    { +        return (AE_OK); +    } + +    /* Convert and validate the device handle */ + +    Node = AcpiNsValidateHandle (ObjHandle); +    if (!Node) +    { +        return (AE_BAD_PARAMETER); +    } + +    /* +     * We only care about regions and objects that are allowed to have +     * address space handlers +     */ +    if ((Node->Type != ACPI_TYPE_DEVICE) && +        (Node->Type != ACPI_TYPE_REGION) && +        (Node != AcpiGbl_RootNode)) +    { +        return (AE_OK); +    } + +    /* Check for an existing internal object */ + +    ObjDesc = AcpiNsGetAttachedObject (Node); +    if (!ObjDesc) +    { +        /* No object, just exit */ + +        return (AE_OK); +    } + +    /* Devices are handled different than regions */ + +    if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE) +    { +        /* Check if this Device already has a handler for this address space */ + +        NextHandlerObj = ObjDesc->Device.Handler; +        while (NextHandlerObj) +        { +            /* Found a handler, is it for the same address space? */ + +            if (NextHandlerObj->AddressSpace.SpaceId == +                    HandlerObj->AddressSpace.SpaceId) +            { +                ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, +                    "Found handler for region [%s] in device %p(%p) " +                    "handler %p\n", +                    AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId), +                    ObjDesc, NextHandlerObj, HandlerObj)); + +                /* +                 * Since the object we found it on was a device, then it +                 * means that someone has already installed a handler for +                 * the branch of the namespace from this device on. Just +                 * bail out telling the walk routine to not traverse this +                 * branch. This preserves the scoping rule for handlers. +                 */ +                return (AE_CTRL_DEPTH); +            } + +            /* Walk the linked list of handlers attached to this device */ + +            NextHandlerObj = NextHandlerObj->AddressSpace.Next; +        } + +        /* +         * As long as the device didn't have a handler for this space we +         * don't care about it. We just ignore it and proceed. +         */ +        return (AE_OK); +    } + +    /* Object is a Region */ + +    if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId) +    { +        /* This region is for a different address space, just ignore it */ + +        return (AE_OK); +    } + +    /* +     * Now we have a region and it is for the handler's address space type. +     * +     * First disconnect region for any previous handler (if any) +     */ +    AcpiEvDetachRegion (ObjDesc, FALSE); + +    /* Connect the region to the new handler */ + +    Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE); +    return (Status); +} + + +/******************************************************************************* + * + * FUNCTION:    AcpiEvInstallSpaceHandler + * + * PARAMETERS:  Node            - Namespace node for the device + *              SpaceId         - The address space ID + *              Handler         - Address of the handler + *              Setup           - Address of the setup function + *              Context         - Value passed to the handler on each access + * + * RETURN:      Status + * + * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. + *              Assumes namespace is locked + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvInstallSpaceHandler ( +    ACPI_NAMESPACE_NODE     *Node, +    ACPI_ADR_SPACE_TYPE     SpaceId, +    ACPI_ADR_SPACE_HANDLER  Handler, +    ACPI_ADR_SPACE_SETUP    Setup, +    void                    *Context) +{ +    ACPI_OPERAND_OBJECT     *ObjDesc; +    ACPI_OPERAND_OBJECT     *HandlerObj; +    ACPI_STATUS             Status; +    ACPI_OBJECT_TYPE        Type; +    UINT8                  Flags = 0; + + +    ACPI_FUNCTION_TRACE (EvInstallSpaceHandler); + + +    /* +     * This registration is valid for only the types below and the root. This +     * is where the default handlers get placed. +     */ +    if ((Node->Type != ACPI_TYPE_DEVICE)     && +        (Node->Type != ACPI_TYPE_PROCESSOR)  && +        (Node->Type != ACPI_TYPE_THERMAL)    && +        (Node != AcpiGbl_RootNode)) +    { +        Status = AE_BAD_PARAMETER; +        goto UnlockAndExit; +    } + +    if (Handler == ACPI_DEFAULT_HANDLER) +    { +        Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; + +        switch (SpaceId) +        { +        case ACPI_ADR_SPACE_SYSTEM_MEMORY: +            Handler = AcpiExSystemMemorySpaceHandler; +            Setup   = AcpiEvSystemMemoryRegionSetup; +            break; + +        case ACPI_ADR_SPACE_SYSTEM_IO: +            Handler = AcpiExSystemIoSpaceHandler; +            Setup   = AcpiEvIoSpaceRegionSetup; +            break; + +        case ACPI_ADR_SPACE_PCI_CONFIG: +            Handler = AcpiExPciConfigSpaceHandler; +            Setup   = AcpiEvPciConfigRegionSetup; +            break; + +        case ACPI_ADR_SPACE_CMOS: +            Handler = AcpiExCmosSpaceHandler; +            Setup   = AcpiEvCmosRegionSetup; +            break; + +        case ACPI_ADR_SPACE_PCI_BAR_TARGET: +            Handler = AcpiExPciBarSpaceHandler; +            Setup   = AcpiEvPciBarRegionSetup; +            break; + +        case ACPI_ADR_SPACE_DATA_TABLE: +            Handler = AcpiExDataTableSpaceHandler; +            Setup   = NULL; +            break; + +        default: +            Status = AE_BAD_PARAMETER; +            goto UnlockAndExit; +        } +    } + +    /* If the caller hasn't specified a setup routine, use the default */ + +    if (!Setup) +    { +        Setup = AcpiEvDefaultRegionSetup; +    } + +    /* Check for an existing internal object */ + +    ObjDesc = AcpiNsGetAttachedObject (Node); +    if (ObjDesc) +    { +        /* +         * The attached device object already exists. Make sure the handler +         * is not already installed. +         */ +        HandlerObj = ObjDesc->Device.Handler; + +        /* Walk the handler list for this device */ + +        while (HandlerObj) +        { +            /* Same SpaceId indicates a handler already installed */ + +            if (HandlerObj->AddressSpace.SpaceId == SpaceId) +            { +                if (HandlerObj->AddressSpace.Handler == Handler) +                { +                    /* +                     * It is (relatively) OK to attempt to install the SAME +                     * handler twice. This can easily happen with the +                     * PCI_Config space. +                     */ +                    Status = AE_SAME_HANDLER; +                    goto UnlockAndExit; +                } +                else +                { +                    /* A handler is already installed */ + +                    Status = AE_ALREADY_EXISTS; +                } +                goto UnlockAndExit; +            } + +            /* Walk the linked list of handlers */ + +            HandlerObj = HandlerObj->AddressSpace.Next; +        } +    } +    else +    { +        ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, +            "Creating object on Device %p while installing handler\n", Node)); + +        /* ObjDesc does not exist, create one */ + +        if (Node->Type == ACPI_TYPE_ANY) +        { +            Type = ACPI_TYPE_DEVICE; +        } +        else +        { +            Type = Node->Type; +        } + +        ObjDesc = AcpiUtCreateInternalObject (Type); +        if (!ObjDesc) +        { +            Status = AE_NO_MEMORY; +            goto UnlockAndExit; +        } + +        /* Init new descriptor */ + +        ObjDesc->Common.Type = (UINT8) Type; + +        /* Attach the new object to the Node */ + +        Status = AcpiNsAttachObject (Node, ObjDesc, Type); + +        /* Remove local reference to the object */ + +        AcpiUtRemoveReference (ObjDesc); + +        if (ACPI_FAILURE (Status)) +        { +            goto UnlockAndExit; +        } +    } + +    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, +        "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", +        AcpiUtGetRegionName (SpaceId), SpaceId, +        AcpiUtGetNodeName (Node), Node, ObjDesc)); + +    /* +     * Install the handler +     * +     * At this point there is no existing handler. Just allocate the object +     * for the handler and link it into the list. +     */ +    HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); +    if (!HandlerObj) +    { +        Status = AE_NO_MEMORY; +        goto UnlockAndExit; +    } + +    /* Init handler obj */ + +    HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId; +    HandlerObj->AddressSpace.HandlerFlags = Flags; +    HandlerObj->AddressSpace.RegionList = NULL; +    HandlerObj->AddressSpace.Node = Node; +    HandlerObj->AddressSpace.Handler = Handler; +    HandlerObj->AddressSpace.Context = Context; +    HandlerObj->AddressSpace.Setup  = Setup; + +    /* Install at head of Device.AddressSpace list */ + +    HandlerObj->AddressSpace.Next = ObjDesc->Device.Handler; + +    /* +     * The Device object is the first reference on the HandlerObj. +     * Each region that uses the handler adds a reference. +     */ +    ObjDesc->Device.Handler = HandlerObj; + +    /* +     * Walk the namespace finding all of the regions this +     * handler will manage. +     * +     * Start at the device and search the branch toward +     * the leaf nodes until either the leaf is encountered or +     * a device is detected that has an address handler of the +     * same type. +     * +     * In either case, back up and search down the remainder +     * of the branch +     */ +    Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX, +                ACPI_NS_WALK_UNLOCK, AcpiEvInstallHandler, NULL, +                HandlerObj, NULL); + +UnlockAndExit: +    return_ACPI_STATUS (Status); +} | 
