1/******************************************************************************
2 *
3 * Module Name: evregion - ACPI AddressSpace (OpRegion) handler dispatch
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44
45#define __EVREGION_C__
46
47#include <contrib/dev/acpica/include/acpi.h>
48#include <contrib/dev/acpica/include/accommon.h>
49#include <contrib/dev/acpica/include/acevents.h>
50#include <contrib/dev/acpica/include/acnamesp.h>
51#include <contrib/dev/acpica/include/acinterp.h>
52
53#define _COMPONENT          ACPI_EVENTS
54        ACPI_MODULE_NAME    ("evregion")
55
56
57/* Local prototypes */
58
59static BOOLEAN
60AcpiEvHasDefaultHandler (
61    ACPI_NAMESPACE_NODE     *Node,
62    ACPI_ADR_SPACE_TYPE     SpaceId);
63
64static void
65AcpiEvOrphanEcRegMethod (
66    void);
67
68static ACPI_STATUS
69AcpiEvRegRun (
70    ACPI_HANDLE             ObjHandle,
71    UINT32                  Level,
72    void                    *Context,
73    void                    **ReturnValue);
74
75static ACPI_STATUS
76AcpiEvInstallHandler (
77    ACPI_HANDLE             ObjHandle,
78    UINT32                  Level,
79    void                    *Context,
80    void                    **ReturnValue);
81
82/* These are the address spaces that will get default handlers */
83
84#define ACPI_NUM_DEFAULT_SPACES     4
85
86static UINT8        AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] =
87{
88    ACPI_ADR_SPACE_SYSTEM_MEMORY,
89    ACPI_ADR_SPACE_SYSTEM_IO,
90    ACPI_ADR_SPACE_PCI_CONFIG,
91    ACPI_ADR_SPACE_DATA_TABLE
92};
93
94
95/*******************************************************************************
96 *
97 * FUNCTION:    AcpiEvInstallRegionHandlers
98 *
99 * PARAMETERS:  None
100 *
101 * RETURN:      Status
102 *
103 * DESCRIPTION: Installs the core subsystem default address space handlers.
104 *
105 ******************************************************************************/
106
107ACPI_STATUS
108AcpiEvInstallRegionHandlers (
109    void)
110{
111    ACPI_STATUS             Status;
112    UINT32                  i;
113
114
115    ACPI_FUNCTION_TRACE (EvInstallRegionHandlers);
116
117
118    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
119    if (ACPI_FAILURE (Status))
120    {
121        return_ACPI_STATUS (Status);
122    }
123
124    /*
125     * All address spaces (PCI Config, EC, SMBus) are scope dependent and
126     * registration must occur for a specific device.
127     *
128     * In the case of the system memory and IO address spaces there is
129     * currently no device associated with the address space. For these we
130     * use the root.
131     *
132     * We install the default PCI config space handler at the root so that
133     * this space is immediately available even though the we have not
134     * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
135     * specification which states that the PCI config space must be always
136     * available -- even though we are nowhere near ready to find the PCI root
137     * buses at this point.
138     *
139     * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
140     * has already been installed (via AcpiInstallAddressSpaceHandler).
141     * Similar for AE_SAME_HANDLER.
142     */
143    for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++)
144    {
145        Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode,
146                    AcpiGbl_DefaultAddressSpaces[i],
147                    ACPI_DEFAULT_HANDLER, NULL, NULL);
148        switch (Status)
149        {
150        case AE_OK:
151        case AE_SAME_HANDLER:
152        case AE_ALREADY_EXISTS:
153
154            /* These exceptions are all OK */
155
156            Status = AE_OK;
157            break;
158
159        default:
160
161            goto UnlockAndExit;
162        }
163    }
164
165UnlockAndExit:
166    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
167    return_ACPI_STATUS (Status);
168}
169
170
171/*******************************************************************************
172 *
173 * FUNCTION:    AcpiEvHasDefaultHandler
174 *
175 * PARAMETERS:  Node                - Namespace node for the device
176 *              SpaceId             - The address space ID
177 *
178 * RETURN:      TRUE if default handler is installed, FALSE otherwise
179 *
180 * DESCRIPTION: Check if the default handler is installed for the requested
181 *              space ID.
182 *
183 ******************************************************************************/
184
185static BOOLEAN
186AcpiEvHasDefaultHandler (
187    ACPI_NAMESPACE_NODE     *Node,
188    ACPI_ADR_SPACE_TYPE     SpaceId)
189{
190    ACPI_OPERAND_OBJECT     *ObjDesc;
191    ACPI_OPERAND_OBJECT     *HandlerObj;
192
193
194    /* Must have an existing internal object */
195
196    ObjDesc = AcpiNsGetAttachedObject (Node);
197    if (ObjDesc)
198    {
199        HandlerObj = ObjDesc->Device.Handler;
200
201        /* Walk the linked list of handlers for this object */
202
203        while (HandlerObj)
204        {
205            if (HandlerObj->AddressSpace.SpaceId == SpaceId)
206            {
207                if (HandlerObj->AddressSpace.HandlerFlags &
208                        ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
209                {
210                    return (TRUE);
211                }
212            }
213
214            HandlerObj = HandlerObj->AddressSpace.Next;
215        }
216    }
217
218    return (FALSE);
219}
220
221
222/*******************************************************************************
223 *
224 * FUNCTION:    AcpiEvInitializeOpRegions
225 *
226 * PARAMETERS:  None
227 *
228 * RETURN:      Status
229 *
230 * DESCRIPTION: Execute _REG methods for all Operation Regions that have
231 *              an installed default region handler.
232 *
233 ******************************************************************************/
234
235ACPI_STATUS
236AcpiEvInitializeOpRegions (
237    void)
238{
239    ACPI_STATUS             Status;
240    UINT32                  i;
241
242
243    ACPI_FUNCTION_TRACE (EvInitializeOpRegions);
244
245
246    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
247    if (ACPI_FAILURE (Status))
248    {
249        return_ACPI_STATUS (Status);
250    }
251
252    /* Run the _REG methods for OpRegions in each default address space */
253
254    for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++)
255    {
256        /*
257         * Make sure the installed handler is the DEFAULT handler. If not the
258         * default, the _REG methods will have already been run (when the
259         * handler was installed)
260         */
261        if (AcpiEvHasDefaultHandler (AcpiGbl_RootNode,
262               AcpiGbl_DefaultAddressSpaces[i]))
263        {
264            Status = AcpiEvExecuteRegMethods (AcpiGbl_RootNode,
265                        AcpiGbl_DefaultAddressSpaces[i]);
266        }
267    }
268
269    AcpiGbl_RegMethodsExecuted = TRUE;
270
271    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
272    return_ACPI_STATUS (Status);
273}
274
275
276/*******************************************************************************
277 *
278 * FUNCTION:    AcpiEvExecuteRegMethod
279 *
280 * PARAMETERS:  RegionObj           - Region object
281 *              Function            - Passed to _REG: On (1) or Off (0)
282 *
283 * RETURN:      Status
284 *
285 * DESCRIPTION: Execute _REG method for a region
286 *
287 ******************************************************************************/
288
289ACPI_STATUS
290AcpiEvExecuteRegMethod (
291    ACPI_OPERAND_OBJECT     *RegionObj,
292    UINT32                  Function)
293{
294    ACPI_EVALUATE_INFO      *Info;
295    ACPI_OPERAND_OBJECT     *Args[3];
296    ACPI_OPERAND_OBJECT     *RegionObj2;
297    ACPI_STATUS             Status;
298
299
300    ACPI_FUNCTION_TRACE (EvExecuteRegMethod);
301
302
303    RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
304    if (!RegionObj2)
305    {
306        return_ACPI_STATUS (AE_NOT_EXIST);
307    }
308
309    if (RegionObj2->Extra.Method_REG == NULL)
310    {
311        return_ACPI_STATUS (AE_OK);
312    }
313
314    /* Allocate and initialize the evaluation information block */
315
316    Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
317    if (!Info)
318    {
319        return_ACPI_STATUS (AE_NO_MEMORY);
320    }
321
322    Info->PrefixNode = RegionObj2->Extra.Method_REG;
323    Info->Pathname = NULL;
324    Info->Parameters = Args;
325    Info->Flags = ACPI_IGNORE_RETURN_VALUE;
326
327    /*
328     * The _REG method has two arguments:
329     *
330     * Arg0 - Integer:
331     *  Operation region space ID Same value as RegionObj->Region.SpaceId
332     *
333     * Arg1 - Integer:
334     *  connection status 1 for connecting the handler, 0 for disconnecting
335     *  the handler (Passed as a parameter)
336     */
337    Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId);
338    if (!Args[0])
339    {
340        Status = AE_NO_MEMORY;
341        goto Cleanup1;
342    }
343
344    Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function);
345    if (!Args[1])
346    {
347        Status = AE_NO_MEMORY;
348        goto Cleanup2;
349    }
350
351    Args[2] = NULL; /* Terminate list */
352
353    /* Execute the method, no return value */
354
355    ACPI_DEBUG_EXEC (
356        AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL));
357
358    Status = AcpiNsEvaluate (Info);
359    AcpiUtRemoveReference (Args[1]);
360
361Cleanup2:
362    AcpiUtRemoveReference (Args[0]);
363
364Cleanup1:
365    ACPI_FREE (Info);
366    return_ACPI_STATUS (Status);
367}
368
369
370/*******************************************************************************
371 *
372 * FUNCTION:    AcpiEvAddressSpaceDispatch
373 *
374 * PARAMETERS:  RegionObj           - Internal region object
375 *              Function            - Read or Write operation
376 *              RegionOffset        - Where in the region to read or write
377 *              BitWidth            - Field width in bits (8, 16, 32, or 64)
378 *              Value               - Pointer to in or out value, must be
379 *                                    a full 64-bit integer
380 *
381 * RETURN:      Status
382 *
383 * DESCRIPTION: Dispatch an address space or operation region access to
384 *              a previously installed handler.
385 *
386 ******************************************************************************/
387
388ACPI_STATUS
389AcpiEvAddressSpaceDispatch (
390    ACPI_OPERAND_OBJECT     *RegionObj,
391    UINT32                  Function,
392    UINT32                  RegionOffset,
393    UINT32                  BitWidth,
394    UINT64                  *Value)
395{
396    ACPI_STATUS             Status;
397    ACPI_ADR_SPACE_HANDLER  Handler;
398    ACPI_ADR_SPACE_SETUP    RegionSetup;
399    ACPI_OPERAND_OBJECT     *HandlerDesc;
400    ACPI_OPERAND_OBJECT     *RegionObj2;
401    void                    *RegionContext = NULL;
402
403
404    ACPI_FUNCTION_TRACE (EvAddressSpaceDispatch);
405
406
407    RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
408    if (!RegionObj2)
409    {
410        return_ACPI_STATUS (AE_NOT_EXIST);
411    }
412
413    /* Ensure that there is a handler associated with this region */
414
415    HandlerDesc = RegionObj->Region.Handler;
416    if (!HandlerDesc)
417    {
418        ACPI_ERROR ((AE_INFO,
419            "No handler for Region [%4.4s] (%p) [%s]",
420            AcpiUtGetNodeName (RegionObj->Region.Node),
421            RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
422
423        return_ACPI_STATUS (AE_NOT_EXIST);
424    }
425
426    /*
427     * It may be the case that the region has never been initialized.
428     * Some types of regions require special init code
429     */
430    if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE))
431    {
432        /* This region has not been initialized yet, do it */
433
434        RegionSetup = HandlerDesc->AddressSpace.Setup;
435        if (!RegionSetup)
436        {
437            /* No initialization routine, exit with error */
438
439            ACPI_ERROR ((AE_INFO,
440                "No init routine for region(%p) [%s]",
441                RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
442            return_ACPI_STATUS (AE_NOT_EXIST);
443        }
444
445        /*
446         * We must exit the interpreter because the region setup will
447         * potentially execute control methods (for example, the _REG method
448         * for this region)
449         */
450        AcpiExExitInterpreter ();
451
452        Status = RegionSetup (RegionObj, ACPI_REGION_ACTIVATE,
453                    HandlerDesc->AddressSpace.Context, &RegionContext);
454
455        /* Re-enter the interpreter */
456
457        AcpiExEnterInterpreter ();
458
459        /* Check for failure of the Region Setup */
460
461        if (ACPI_FAILURE (Status))
462        {
463            ACPI_EXCEPTION ((AE_INFO, Status,
464                "During region initialization: [%s]",
465                AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
466            return_ACPI_STATUS (Status);
467        }
468
469        /* Region initialization may have been completed by RegionSetup */
470
471        if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE))
472        {
473            RegionObj->Region.Flags |= AOPOBJ_SETUP_COMPLETE;
474
475            if (RegionObj2->Extra.RegionContext)
476            {
477                /* The handler for this region was already installed */
478
479                ACPI_FREE (RegionContext);
480            }
481            else
482            {
483                /*
484                 * Save the returned context for use in all accesses to
485                 * this particular region
486                 */
487                RegionObj2->Extra.RegionContext = RegionContext;
488            }
489        }
490    }
491
492    /* We have everything we need, we can invoke the address space handler */
493
494    Handler = HandlerDesc->AddressSpace.Handler;
495
496    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
497        "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
498        &RegionObj->Region.Handler->AddressSpace, Handler,
499        ACPI_FORMAT_NATIVE_UINT (RegionObj->Region.Address + RegionOffset),
500        AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
501
502    if (!(HandlerDesc->AddressSpace.HandlerFlags &
503            ACPI_ADDR_HANDLER_DEFAULT_INSTALLED))
504    {
505        /*
506         * For handlers other than the default (supplied) handlers, we must
507         * exit the interpreter because the handler *might* block -- we don't
508         * know what it will do, so we can't hold the lock on the intepreter.
509         */
510        AcpiExExitInterpreter();
511    }
512
513    /* Call the handler */
514
515    Status = Handler (Function,
516        (RegionObj->Region.Address + RegionOffset), BitWidth, Value,
517        HandlerDesc->AddressSpace.Context, RegionObj2->Extra.RegionContext);
518
519    if (ACPI_FAILURE (Status))
520    {
521        ACPI_EXCEPTION ((AE_INFO, Status, "Returned by Handler for [%s]",
522            AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
523    }
524
525    if (!(HandlerDesc->AddressSpace.HandlerFlags &
526            ACPI_ADDR_HANDLER_DEFAULT_INSTALLED))
527    {
528        /*
529         * We just returned from a non-default handler, we must re-enter the
530         * interpreter
531         */
532       AcpiExEnterInterpreter ();
533    }
534
535    return_ACPI_STATUS (Status);
536}
537
538
539/*******************************************************************************
540 *
541 * FUNCTION:    AcpiEvDetachRegion
542 *
543 * PARAMETERS:  RegionObj           - Region Object
544 *              AcpiNsIsLocked      - Namespace Region Already Locked?
545 *
546 * RETURN:      None
547 *
548 * DESCRIPTION: Break the association between the handler and the region
549 *              this is a two way association.
550 *
551 ******************************************************************************/
552
553void
554AcpiEvDetachRegion(
555    ACPI_OPERAND_OBJECT     *RegionObj,
556    BOOLEAN                 AcpiNsIsLocked)
557{
558    ACPI_OPERAND_OBJECT     *HandlerObj;
559    ACPI_OPERAND_OBJECT     *ObjDesc;
560    ACPI_OPERAND_OBJECT     **LastObjPtr;
561    ACPI_ADR_SPACE_SETUP    RegionSetup;
562    void                    **RegionContext;
563    ACPI_OPERAND_OBJECT     *RegionObj2;
564    ACPI_STATUS             Status;
565
566
567    ACPI_FUNCTION_TRACE (EvDetachRegion);
568
569
570    RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
571    if (!RegionObj2)
572    {
573        return_VOID;
574    }
575    RegionContext = &RegionObj2->Extra.RegionContext;
576
577    /* Get the address handler from the region object */
578
579    HandlerObj = RegionObj->Region.Handler;
580    if (!HandlerObj)
581    {
582        /* This region has no handler, all done */
583
584        return_VOID;
585    }
586
587    /* Find this region in the handler's list */
588
589    ObjDesc = HandlerObj->AddressSpace.RegionList;
590    LastObjPtr = &HandlerObj->AddressSpace.RegionList;
591
592    while (ObjDesc)
593    {
594        /* Is this the correct Region? */
595
596        if (ObjDesc == RegionObj)
597        {
598            ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
599                "Removing Region %p from address handler %p\n",
600                RegionObj, HandlerObj));
601
602            /* This is it, remove it from the handler's list */
603
604            *LastObjPtr = ObjDesc->Region.Next;
605            ObjDesc->Region.Next = NULL;        /* Must clear field */
606
607            if (AcpiNsIsLocked)
608            {
609                Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
610                if (ACPI_FAILURE (Status))
611                {
612                    return_VOID;
613                }
614            }
615
616            /* Now stop region accesses by executing the _REG method */
617
618            Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_DISCONNECT);
619            if (ACPI_FAILURE (Status))
620            {
621                ACPI_EXCEPTION ((AE_INFO, Status, "from region _REG, [%s]",
622                    AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
623            }
624
625            if (AcpiNsIsLocked)
626            {
627                Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
628                if (ACPI_FAILURE (Status))
629                {
630                    return_VOID;
631                }
632            }
633
634            /*
635             * If the region has been activated, call the setup handler with
636             * the deactivate notification
637             */
638            if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)
639            {
640                RegionSetup = HandlerObj->AddressSpace.Setup;
641                Status = RegionSetup (RegionObj, ACPI_REGION_DEACTIVATE,
642                    HandlerObj->AddressSpace.Context, RegionContext);
643
644                /* Init routine may fail, Just ignore errors */
645
646                if (ACPI_FAILURE (Status))
647                {
648                    ACPI_EXCEPTION ((AE_INFO, Status,
649                        "from region handler - deactivate, [%s]",
650                        AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
651                }
652
653                RegionObj->Region.Flags &= ~(AOPOBJ_SETUP_COMPLETE);
654            }
655
656            /*
657             * Remove handler reference in the region
658             *
659             * NOTE: this doesn't mean that the region goes away, the region
660             * is just inaccessible as indicated to the _REG method
661             *
662             * If the region is on the handler's list, this must be the
663             * region's handler
664             */
665            RegionObj->Region.Handler = NULL;
666            AcpiUtRemoveReference (HandlerObj);
667
668            return_VOID;
669        }
670
671        /* Walk the linked list of handlers */
672
673        LastObjPtr = &ObjDesc->Region.Next;
674        ObjDesc = ObjDesc->Region.Next;
675    }
676
677    /* If we get here, the region was not in the handler's region list */
678
679    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
680        "Cannot remove region %p from address handler %p\n",
681        RegionObj, HandlerObj));
682
683    return_VOID;
684}
685
686
687/*******************************************************************************
688 *
689 * FUNCTION:    AcpiEvAttachRegion
690 *
691 * PARAMETERS:  HandlerObj          - Handler Object
692 *              RegionObj           - Region Object
693 *              AcpiNsIsLocked      - Namespace Region Already Locked?
694 *
695 * RETURN:      None
696 *
697 * DESCRIPTION: Create the association between the handler and the region
698 *              this is a two way association.
699 *
700 ******************************************************************************/
701
702ACPI_STATUS
703AcpiEvAttachRegion (
704    ACPI_OPERAND_OBJECT     *HandlerObj,
705    ACPI_OPERAND_OBJECT     *RegionObj,
706    BOOLEAN                 AcpiNsIsLocked)
707{
708
709    ACPI_FUNCTION_TRACE (EvAttachRegion);
710
711
712    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
713        "Adding Region [%4.4s] %p to address handler %p [%s]\n",
714        AcpiUtGetNodeName (RegionObj->Region.Node),
715        RegionObj, HandlerObj,
716        AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
717
718    /* Link this region to the front of the handler's list */
719
720    RegionObj->Region.Next = HandlerObj->AddressSpace.RegionList;
721    HandlerObj->AddressSpace.RegionList = RegionObj;
722
723    /* Install the region's handler */
724
725    if (RegionObj->Region.Handler)
726    {
727        return_ACPI_STATUS (AE_ALREADY_EXISTS);
728    }
729
730    RegionObj->Region.Handler = HandlerObj;
731    AcpiUtAddReference (HandlerObj);
732
733    return_ACPI_STATUS (AE_OK);
734}
735
736
737/*******************************************************************************
738 *
739 * FUNCTION:    AcpiEvInstallHandler
740 *
741 * PARAMETERS:  WalkNamespace callback
742 *
743 * DESCRIPTION: This routine installs an address handler into objects that are
744 *              of type Region or Device.
745 *
746 *              If the Object is a Device, and the device has a handler of
747 *              the same type then the search is terminated in that branch.
748 *
749 *              This is because the existing handler is closer in proximity
750 *              to any more regions than the one we are trying to install.
751 *
752 ******************************************************************************/
753
754static ACPI_STATUS
755AcpiEvInstallHandler (
756    ACPI_HANDLE             ObjHandle,
757    UINT32                  Level,
758    void                    *Context,
759    void                    **ReturnValue)
760{
761    ACPI_OPERAND_OBJECT     *HandlerObj;
762    ACPI_OPERAND_OBJECT     *NextHandlerObj;
763    ACPI_OPERAND_OBJECT     *ObjDesc;
764    ACPI_NAMESPACE_NODE     *Node;
765    ACPI_STATUS             Status;
766
767
768    ACPI_FUNCTION_NAME (EvInstallHandler);
769
770
771    HandlerObj = (ACPI_OPERAND_OBJECT  *) Context;
772
773    /* Parameter validation */
774
775    if (!HandlerObj)
776    {
777        return (AE_OK);
778    }
779
780    /* Convert and validate the device handle */
781
782    Node = AcpiNsValidateHandle (ObjHandle);
783    if (!Node)
784    {
785        return (AE_BAD_PARAMETER);
786    }
787
788    /*
789     * We only care about regions and objects that are allowed to have
790     * address space handlers
791     */
792    if ((Node->Type != ACPI_TYPE_DEVICE) &&
793        (Node->Type != ACPI_TYPE_REGION) &&
794        (Node != AcpiGbl_RootNode))
795    {
796        return (AE_OK);
797    }
798
799    /* Check for an existing internal object */
800
801    ObjDesc = AcpiNsGetAttachedObject (Node);
802    if (!ObjDesc)
803    {
804        /* No object, just exit */
805
806        return (AE_OK);
807    }
808
809    /* Devices are handled different than regions */
810
811    if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE)
812    {
813        /* Check if this Device already has a handler for this address space */
814
815        NextHandlerObj = ObjDesc->Device.Handler;
816        while (NextHandlerObj)
817        {
818            /* Found a handler, is it for the same address space? */
819
820            if (NextHandlerObj->AddressSpace.SpaceId ==
821                    HandlerObj->AddressSpace.SpaceId)
822            {
823                ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
824                    "Found handler for region [%s] in device %p(%p) "
825                    "handler %p\n",
826                    AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId),
827                    ObjDesc, NextHandlerObj, HandlerObj));
828
829                /*
830                 * Since the object we found it on was a device, then it
831                 * means that someone has already installed a handler for
832                 * the branch of the namespace from this device on. Just
833                 * bail out telling the walk routine to not traverse this
834                 * branch. This preserves the scoping rule for handlers.
835                 */
836                return (AE_CTRL_DEPTH);
837            }
838
839            /* Walk the linked list of handlers attached to this device */
840
841            NextHandlerObj = NextHandlerObj->AddressSpace.Next;
842        }
843
844        /*
845         * As long as the device didn't have a handler for this space we
846         * don't care about it. We just ignore it and proceed.
847         */
848        return (AE_OK);
849    }
850
851    /* Object is a Region */
852
853    if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId)
854    {
855        /* This region is for a different address space, just ignore it */
856
857        return (AE_OK);
858    }
859
860    /*
861     * Now we have a region and it is for the handler's address space type.
862     *
863     * First disconnect region for any previous handler (if any)
864     */
865    AcpiEvDetachRegion (ObjDesc, FALSE);
866
867    /* Connect the region to the new handler */
868
869    Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE);
870    return (Status);
871}
872
873
874/*******************************************************************************
875 *
876 * FUNCTION:    AcpiEvInstallSpaceHandler
877 *
878 * PARAMETERS:  Node            - Namespace node for the device
879 *              SpaceId         - The address space ID
880 *              Handler         - Address of the handler
881 *              Setup           - Address of the setup function
882 *              Context         - Value passed to the handler on each access
883 *
884 * RETURN:      Status
885 *
886 * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId.
887 *              Assumes namespace is locked
888 *
889 ******************************************************************************/
890
891ACPI_STATUS
892AcpiEvInstallSpaceHandler (
893    ACPI_NAMESPACE_NODE     *Node,
894    ACPI_ADR_SPACE_TYPE     SpaceId,
895    ACPI_ADR_SPACE_HANDLER  Handler,
896    ACPI_ADR_SPACE_SETUP    Setup,
897    void                    *Context)
898{
899    ACPI_OPERAND_OBJECT     *ObjDesc;
900    ACPI_OPERAND_OBJECT     *HandlerObj;
901    ACPI_STATUS             Status;
902    ACPI_OBJECT_TYPE        Type;
903    UINT8                  Flags = 0;
904
905
906    ACPI_FUNCTION_TRACE (EvInstallSpaceHandler);
907
908
909    /*
910     * This registration is valid for only the types below and the root. This
911     * is where the default handlers get placed.
912     */
913    if ((Node->Type != ACPI_TYPE_DEVICE)     &&
914        (Node->Type != ACPI_TYPE_PROCESSOR)  &&
915        (Node->Type != ACPI_TYPE_THERMAL)    &&
916        (Node != AcpiGbl_RootNode))
917    {
918        Status = AE_BAD_PARAMETER;
919        goto UnlockAndExit;
920    }
921
922    if (Handler == ACPI_DEFAULT_HANDLER)
923    {
924        Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
925
926        switch (SpaceId)
927        {
928        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
929            Handler = AcpiExSystemMemorySpaceHandler;
930            Setup   = AcpiEvSystemMemoryRegionSetup;
931            break;
932
933        case ACPI_ADR_SPACE_SYSTEM_IO:
934            Handler = AcpiExSystemIoSpaceHandler;
935            Setup   = AcpiEvIoSpaceRegionSetup;
936            break;
937
938        case ACPI_ADR_SPACE_PCI_CONFIG:
939            Handler = AcpiExPciConfigSpaceHandler;
940            Setup   = AcpiEvPciConfigRegionSetup;
941            break;
942
943        case ACPI_ADR_SPACE_CMOS:
944            Handler = AcpiExCmosSpaceHandler;
945            Setup   = AcpiEvCmosRegionSetup;
946            break;
947
948        case ACPI_ADR_SPACE_PCI_BAR_TARGET:
949            Handler = AcpiExPciBarSpaceHandler;
950            Setup   = AcpiEvPciBarRegionSetup;
951            break;
952
953        case ACPI_ADR_SPACE_DATA_TABLE:
954            Handler = AcpiExDataTableSpaceHandler;
955            Setup   = NULL;
956            break;
957
958        default:
959            Status = AE_BAD_PARAMETER;
960            goto UnlockAndExit;
961        }
962    }
963
964    /* If the caller hasn't specified a setup routine, use the default */
965
966    if (!Setup)
967    {
968        Setup = AcpiEvDefaultRegionSetup;
969    }
970
971    /* Check for an existing internal object */
972
973    ObjDesc = AcpiNsGetAttachedObject (Node);
974    if (ObjDesc)
975    {
976        /*
977         * The attached device object already exists. Make sure the handler
978         * is not already installed.
979         */
980        HandlerObj = ObjDesc->Device.Handler;
981
982        /* Walk the handler list for this device */
983
984        while (HandlerObj)
985        {
986            /* Same SpaceId indicates a handler already installed */
987
988            if (HandlerObj->AddressSpace.SpaceId == SpaceId)
989            {
990                if (HandlerObj->AddressSpace.Handler == Handler)
991                {
992                    /*
993                     * It is (relatively) OK to attempt to install the SAME
994                     * handler twice. This can easily happen with the
995                     * PCI_Config space.
996                     */
997                    Status = AE_SAME_HANDLER;
998                    goto UnlockAndExit;
999                }
1000                else
1001                {
1002                    /* A handler is already installed */
1003
1004                    Status = AE_ALREADY_EXISTS;
1005                }
1006                goto UnlockAndExit;
1007            }
1008
1009            /* Walk the linked list of handlers */
1010
1011            HandlerObj = HandlerObj->AddressSpace.Next;
1012        }
1013    }
1014    else
1015    {
1016        ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
1017            "Creating object on Device %p while installing handler\n", Node));
1018
1019        /* ObjDesc does not exist, create one */
1020
1021        if (Node->Type == ACPI_TYPE_ANY)
1022        {
1023            Type = ACPI_TYPE_DEVICE;
1024        }
1025        else
1026        {
1027            Type = Node->Type;
1028        }
1029
1030        ObjDesc = AcpiUtCreateInternalObject (Type);
1031        if (!ObjDesc)
1032        {
1033            Status = AE_NO_MEMORY;
1034            goto UnlockAndExit;
1035        }
1036
1037        /* Init new descriptor */
1038
1039        ObjDesc->Common.Type = (UINT8) Type;
1040
1041        /* Attach the new object to the Node */
1042
1043        Status = AcpiNsAttachObject (Node, ObjDesc, Type);
1044
1045        /* Remove local reference to the object */
1046
1047        AcpiUtRemoveReference (ObjDesc);
1048
1049        if (ACPI_FAILURE (Status))
1050        {
1051            goto UnlockAndExit;
1052        }
1053    }
1054
1055    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
1056        "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
1057        AcpiUtGetRegionName (SpaceId), SpaceId,
1058        AcpiUtGetNodeName (Node), Node, ObjDesc));
1059
1060    /*
1061     * Install the handler
1062     *
1063     * At this point there is no existing handler. Just allocate the object
1064     * for the handler and link it into the list.
1065     */
1066    HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
1067    if (!HandlerObj)
1068    {
1069        Status = AE_NO_MEMORY;
1070        goto UnlockAndExit;
1071    }
1072
1073    /* Init handler obj */
1074
1075    HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId;
1076    HandlerObj->AddressSpace.HandlerFlags = Flags;
1077    HandlerObj->AddressSpace.RegionList = NULL;
1078    HandlerObj->AddressSpace.Node = Node;
1079    HandlerObj->AddressSpace.Handler = Handler;
1080    HandlerObj->AddressSpace.Context = Context;
1081    HandlerObj->AddressSpace.Setup  = Setup;
1082
1083    /* Install at head of Device.AddressSpace list */
1084
1085    HandlerObj->AddressSpace.Next = ObjDesc->Device.Handler;
1086
1087    /*
1088     * The Device object is the first reference on the HandlerObj.
1089     * Each region that uses the handler adds a reference.
1090     */
1091    ObjDesc->Device.Handler = HandlerObj;
1092
1093    /*
1094     * Walk the namespace finding all of the regions this
1095     * handler will manage.
1096     *
1097     * Start at the device and search the branch toward
1098     * the leaf nodes until either the leaf is encountered or
1099     * a device is detected that has an address handler of the
1100     * same type.
1101     *
1102     * In either case, back up and search down the remainder
1103     * of the branch
1104     */
1105    Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
1106                ACPI_NS_WALK_UNLOCK, AcpiEvInstallHandler, NULL,
1107                HandlerObj, NULL);
1108
1109UnlockAndExit:
1110    return_ACPI_STATUS (Status);
1111}
1112
1113
1114/*******************************************************************************
1115 *
1116 * FUNCTION:    AcpiEvExecuteRegMethods
1117 *
1118 * PARAMETERS:  Node            - Namespace node for the device
1119 *              SpaceId         - The address space ID
1120 *
1121 * RETURN:      Status
1122 *
1123 * DESCRIPTION: Run all _REG methods for the input Space ID;
1124 *              Note: assumes namespace is locked, or system init time.
1125 *
1126 ******************************************************************************/
1127
1128ACPI_STATUS
1129AcpiEvExecuteRegMethods (
1130    ACPI_NAMESPACE_NODE     *Node,
1131    ACPI_ADR_SPACE_TYPE     SpaceId)
1132{
1133    ACPI_STATUS             Status;
1134
1135
1136    ACPI_FUNCTION_TRACE (EvExecuteRegMethods);
1137
1138
1139    /*
1140     * Run all _REG methods for all Operation Regions for this space ID. This
1141     * is a separate walk in order to handle any interdependencies between
1142     * regions and _REG methods. (i.e. handlers must be installed for all
1143     * regions of this Space ID before we can run any _REG methods)
1144     */
1145    Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
1146                ACPI_NS_WALK_UNLOCK, AcpiEvRegRun, NULL,
1147                &SpaceId, NULL);
1148
1149    /* Special case for EC: handle "orphan" _REG methods with no region */
1150
1151    if (SpaceId == ACPI_ADR_SPACE_EC)
1152    {
1153        AcpiEvOrphanEcRegMethod ();
1154    }
1155
1156    return_ACPI_STATUS (Status);
1157}
1158
1159
1160/*******************************************************************************
1161 *
1162 * FUNCTION:    AcpiEvRegRun
1163 *
1164 * PARAMETERS:  WalkNamespace callback
1165 *
1166 * DESCRIPTION: Run _REG method for region objects of the requested spaceID
1167 *
1168 ******************************************************************************/
1169
1170static ACPI_STATUS
1171AcpiEvRegRun (
1172    ACPI_HANDLE             ObjHandle,
1173    UINT32                  Level,
1174    void                    *Context,
1175    void                    **ReturnValue)
1176{
1177    ACPI_OPERAND_OBJECT     *ObjDesc;
1178    ACPI_NAMESPACE_NODE     *Node;
1179    ACPI_ADR_SPACE_TYPE     SpaceId;
1180    ACPI_STATUS             Status;
1181
1182
1183    SpaceId = *ACPI_CAST_PTR (ACPI_ADR_SPACE_TYPE, Context);
1184
1185    /* Convert and validate the device handle */
1186
1187    Node = AcpiNsValidateHandle (ObjHandle);
1188    if (!Node)
1189    {
1190        return (AE_BAD_PARAMETER);
1191    }
1192
1193    /*
1194     * We only care about regions.and objects that are allowed to have address
1195     * space handlers
1196     */
1197    if ((Node->Type != ACPI_TYPE_REGION) &&
1198        (Node != AcpiGbl_RootNode))
1199    {
1200        return (AE_OK);
1201    }
1202
1203    /* Check for an existing internal object */
1204
1205    ObjDesc = AcpiNsGetAttachedObject (Node);
1206    if (!ObjDesc)
1207    {
1208        /* No object, just exit */
1209
1210        return (AE_OK);
1211    }
1212
1213    /* Object is a Region */
1214
1215    if (ObjDesc->Region.SpaceId != SpaceId)
1216    {
1217        /* This region is for a different address space, just ignore it */
1218
1219        return (AE_OK);
1220    }
1221
1222    Status = AcpiEvExecuteRegMethod (ObjDesc, ACPI_REG_CONNECT);
1223    return (Status);
1224}
1225
1226
1227/*******************************************************************************
1228 *
1229 * FUNCTION:    AcpiEvOrphanEcRegMethod
1230 *
1231 * PARAMETERS:  None
1232 *
1233 * RETURN:      None
1234 *
1235 * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
1236 *              device. This is a _REG method that has no corresponding region
1237 *              within the EC device scope. The orphan _REG method appears to
1238 *              have been enabled by the description of the ECDT in the ACPI
1239 *              specification: "The availability of the region space can be
1240 *              detected by providing a _REG method object underneath the
1241 *              Embedded Controller device."
1242 *
1243 *              To quickly access the EC device, we use the EC_ID that appears
1244 *              within the ECDT. Otherwise, we would need to perform a time-
1245 *              consuming namespace walk, executing _HID methods to find the
1246 *              EC device.
1247 *
1248 ******************************************************************************/
1249
1250static void
1251AcpiEvOrphanEcRegMethod (
1252    void)
1253{
1254    ACPI_TABLE_ECDT         *Table;
1255    ACPI_STATUS             Status;
1256    ACPI_OBJECT_LIST        Args;
1257    ACPI_OBJECT             Objects[2];
1258    ACPI_NAMESPACE_NODE     *EcDeviceNode;
1259    ACPI_NAMESPACE_NODE     *RegMethod;
1260    ACPI_NAMESPACE_NODE     *NextNode;
1261
1262
1263    ACPI_FUNCTION_TRACE (EvOrphanEcRegMethod);
1264
1265
1266    /* Get the ECDT (if present in system) */
1267
1268    Status = AcpiGetTable (ACPI_SIG_ECDT, 0,
1269        ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Table));
1270    if (ACPI_FAILURE (Status))
1271    {
1272        return_VOID;
1273    }
1274
1275    /* We need a valid EC_ID string */
1276
1277    if (!(*Table->Id))
1278    {
1279        return_VOID;
1280    }
1281
1282    /* Namespace is currently locked, must release */
1283
1284    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
1285
1286    /* Get a handle to the EC device referenced in the ECDT */
1287
1288    Status = AcpiGetHandle (NULL,
1289        ACPI_CAST_PTR (char, Table->Id),
1290        ACPI_CAST_PTR (ACPI_HANDLE, &EcDeviceNode));
1291    if (ACPI_FAILURE (Status))
1292    {
1293        goto Exit;
1294    }
1295
1296    /* Get a handle to a _REG method immediately under the EC device */
1297
1298    Status = AcpiGetHandle (EcDeviceNode,
1299        METHOD_NAME__REG, ACPI_CAST_PTR (ACPI_HANDLE, &RegMethod));
1300    if (ACPI_FAILURE (Status))
1301    {
1302        goto Exit;
1303    }
1304
1305    /*
1306     * Execute the _REG method only if there is no Operation Region in
1307     * this scope with the Embedded Controller space ID. Otherwise, it
1308     * will already have been executed. Note, this allows for Regions
1309     * with other space IDs to be present; but the code below will then
1310     * execute the _REG method with the EC space ID argument.
1311     */
1312    NextNode = AcpiNsGetNextNode (EcDeviceNode, NULL);
1313    while (NextNode)
1314    {
1315        if ((NextNode->Type == ACPI_TYPE_REGION) &&
1316            (NextNode->Object) &&
1317            (NextNode->Object->Region.SpaceId == ACPI_ADR_SPACE_EC))
1318        {
1319            goto Exit; /* Do not execute _REG */
1320        }
1321        NextNode = AcpiNsGetNextNode (EcDeviceNode, NextNode);
1322    }
1323
1324    /* Evaluate the _REG(EC,Connect) method */
1325
1326    Args.Count = 2;
1327    Args.Pointer = Objects;
1328    Objects[0].Type = ACPI_TYPE_INTEGER;
1329    Objects[0].Integer.Value = ACPI_ADR_SPACE_EC;
1330    Objects[1].Type = ACPI_TYPE_INTEGER;
1331    Objects[1].Integer.Value = ACPI_REG_CONNECT;
1332
1333    Status = AcpiEvaluateObject (RegMethod, NULL, &Args, NULL);
1334
1335Exit:
1336    /* We ignore all errors from above, don't care */
1337
1338    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
1339    return_VOID;
1340}
1341