1/******************************************************************************
2 *
3 * Module Name: evregion - Operation Region support
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2016, 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#include <contrib/dev/acpica/include/acpi.h>
45#include <contrib/dev/acpica/include/accommon.h>
46#include <contrib/dev/acpica/include/acevents.h>
47#include <contrib/dev/acpica/include/acnamesp.h>
48#include <contrib/dev/acpica/include/acinterp.h>
49
50#define _COMPONENT          ACPI_EVENTS
51        ACPI_MODULE_NAME    ("evregion")
52
53
54extern UINT8        AcpiGbl_DefaultAddressSpaces[];
55
56/* Local prototypes */
57
58static void
59AcpiEvOrphanEcRegMethod (
60    ACPI_NAMESPACE_NODE     *EcDeviceNode);
61
62static ACPI_STATUS
63AcpiEvRegRun (
64    ACPI_HANDLE             ObjHandle,
65    UINT32                  Level,
66    void                    *Context,
67    void                    **ReturnValue);
68
69
70/*******************************************************************************
71 *
72 * FUNCTION:    AcpiEvInitializeOpRegions
73 *
74 * PARAMETERS:  None
75 *
76 * RETURN:      Status
77 *
78 * DESCRIPTION: Execute _REG methods for all Operation Regions that have
79 *              an installed default region handler.
80 *
81 ******************************************************************************/
82
83ACPI_STATUS
84AcpiEvInitializeOpRegions (
85    void)
86{
87    ACPI_STATUS             Status;
88    UINT32                  i;
89
90
91    ACPI_FUNCTION_TRACE (EvInitializeOpRegions);
92
93
94    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
95    if (ACPI_FAILURE (Status))
96    {
97        return_ACPI_STATUS (Status);
98    }
99
100    /* Run the _REG methods for OpRegions in each default address space */
101
102    for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++)
103    {
104        /*
105         * Make sure the installed handler is the DEFAULT handler. If not the
106         * default, the _REG methods will have already been run (when the
107         * handler was installed)
108         */
109        if (AcpiEvHasDefaultHandler (AcpiGbl_RootNode,
110               AcpiGbl_DefaultAddressSpaces[i]))
111        {
112            AcpiEvExecuteRegMethods (AcpiGbl_RootNode,
113                AcpiGbl_DefaultAddressSpaces[i], ACPI_REG_CONNECT);
114        }
115    }
116
117    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
118    return_ACPI_STATUS (Status);
119}
120
121
122/*******************************************************************************
123 *
124 * FUNCTION:    AcpiEvAddressSpaceDispatch
125 *
126 * PARAMETERS:  RegionObj           - Internal region object
127 *              FieldObj            - Corresponding field. Can be NULL.
128 *              Function            - Read or Write operation
129 *              RegionOffset        - Where in the region to read or write
130 *              BitWidth            - Field width in bits (8, 16, 32, or 64)
131 *              Value               - Pointer to in or out value, must be
132 *                                    a full 64-bit integer
133 *
134 * RETURN:      Status
135 *
136 * DESCRIPTION: Dispatch an address space or operation region access to
137 *              a previously installed handler.
138 *
139 * NOTE: During early initialization, we always install the default region
140 * handlers for Memory, I/O and PCI_Config. This ensures that these operation
141 * region address spaces are always available as per the ACPI specification.
142 * This is especially needed in order to support the execution of
143 * module-level AML code during loading of the ACPI tables.
144 *
145 ******************************************************************************/
146
147ACPI_STATUS
148AcpiEvAddressSpaceDispatch (
149    ACPI_OPERAND_OBJECT     *RegionObj,
150    ACPI_OPERAND_OBJECT     *FieldObj,
151    UINT32                  Function,
152    UINT32                  RegionOffset,
153    UINT32                  BitWidth,
154    UINT64                  *Value)
155{
156    ACPI_STATUS             Status;
157    ACPI_ADR_SPACE_HANDLER  Handler;
158    ACPI_ADR_SPACE_SETUP    RegionSetup;
159    ACPI_OPERAND_OBJECT     *HandlerDesc;
160    ACPI_OPERAND_OBJECT     *RegionObj2;
161    void                    *RegionContext = NULL;
162    ACPI_CONNECTION_INFO    *Context;
163    ACPI_PHYSICAL_ADDRESS   Address;
164
165
166    ACPI_FUNCTION_TRACE (EvAddressSpaceDispatch);
167
168
169    RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
170    if (!RegionObj2)
171    {
172        return_ACPI_STATUS (AE_NOT_EXIST);
173    }
174
175    /* Ensure that there is a handler associated with this region */
176
177    HandlerDesc = RegionObj->Region.Handler;
178    if (!HandlerDesc)
179    {
180        ACPI_ERROR ((AE_INFO,
181            "No handler for Region [%4.4s] (%p) [%s]",
182            AcpiUtGetNodeName (RegionObj->Region.Node),
183            RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
184
185        return_ACPI_STATUS (AE_NOT_EXIST);
186    }
187
188    Context = HandlerDesc->AddressSpace.Context;
189
190    /*
191     * It may be the case that the region has never been initialized.
192     * Some types of regions require special init code
193     */
194    if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE))
195    {
196        /* This region has not been initialized yet, do it */
197
198        RegionSetup = HandlerDesc->AddressSpace.Setup;
199        if (!RegionSetup)
200        {
201            /* No initialization routine, exit with error */
202
203            ACPI_ERROR ((AE_INFO,
204                "No init routine for region(%p) [%s]",
205                RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
206            return_ACPI_STATUS (AE_NOT_EXIST);
207        }
208
209        /*
210         * We must exit the interpreter because the region setup will
211         * potentially execute control methods (for example, the _REG method
212         * for this region)
213         */
214        AcpiExExitInterpreter ();
215
216        Status = RegionSetup (RegionObj, ACPI_REGION_ACTIVATE,
217            Context, &RegionContext);
218
219        /* Re-enter the interpreter */
220
221        AcpiExEnterInterpreter ();
222
223        /* Check for failure of the Region Setup */
224
225        if (ACPI_FAILURE (Status))
226        {
227            ACPI_EXCEPTION ((AE_INFO, Status,
228                "During region initialization: [%s]",
229                AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
230            return_ACPI_STATUS (Status);
231        }
232
233        /* Region initialization may have been completed by RegionSetup */
234
235        if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE))
236        {
237            RegionObj->Region.Flags |= AOPOBJ_SETUP_COMPLETE;
238
239            /*
240             * Save the returned context for use in all accesses to
241             * the handler for this particular region
242             */
243            if (!(RegionObj2->Extra.RegionContext))
244            {
245                RegionObj2->Extra.RegionContext = RegionContext;
246            }
247        }
248    }
249
250    /* We have everything we need, we can invoke the address space handler */
251
252    Handler = HandlerDesc->AddressSpace.Handler;
253    Address = (RegionObj->Region.Address + RegionOffset);
254
255    /*
256     * Special handling for GenericSerialBus and GeneralPurposeIo:
257     * There are three extra parameters that must be passed to the
258     * handler via the context:
259     *   1) Connection buffer, a resource template from Connection() op
260     *   2) Length of the above buffer
261     *   3) Actual access length from the AccessAs() op
262     *
263     * In addition, for GeneralPurposeIo, the Address and BitWidth fields
264     * are defined as follows:
265     *   1) Address is the pin number index of the field (bit offset from
266     *      the previous Connection)
267     *   2) BitWidth is the actual bit length of the field (number of pins)
268     */
269    if ((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) &&
270        Context &&
271        FieldObj)
272    {
273        /* Get the Connection (ResourceTemplate) buffer */
274
275        Context->Connection = FieldObj->Field.ResourceBuffer;
276        Context->Length = FieldObj->Field.ResourceLength;
277        Context->AccessLength = FieldObj->Field.AccessLength;
278    }
279    if ((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO) &&
280        Context &&
281        FieldObj)
282    {
283        /* Get the Connection (ResourceTemplate) buffer */
284
285        Context->Connection = FieldObj->Field.ResourceBuffer;
286        Context->Length = FieldObj->Field.ResourceLength;
287        Context->AccessLength = FieldObj->Field.AccessLength;
288        Address = FieldObj->Field.PinNumberIndex;
289        BitWidth = FieldObj->Field.BitLength;
290    }
291
292    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
293        "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
294        &RegionObj->Region.Handler->AddressSpace, Handler,
295        ACPI_FORMAT_UINT64 (Address),
296        AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
297
298    if (!(HandlerDesc->AddressSpace.HandlerFlags &
299        ACPI_ADDR_HANDLER_DEFAULT_INSTALLED))
300    {
301        /*
302         * For handlers other than the default (supplied) handlers, we must
303         * exit the interpreter because the handler *might* block -- we don't
304         * know what it will do, so we can't hold the lock on the intepreter.
305         */
306        AcpiExExitInterpreter();
307    }
308
309    /* Call the handler */
310
311    Status = Handler (Function, Address, BitWidth, Value, Context,
312        RegionObj2->Extra.RegionContext);
313
314    if (ACPI_FAILURE (Status))
315    {
316        ACPI_EXCEPTION ((AE_INFO, Status, "Returned by Handler for [%s]",
317            AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
318    }
319
320    if (!(HandlerDesc->AddressSpace.HandlerFlags &
321        ACPI_ADDR_HANDLER_DEFAULT_INSTALLED))
322    {
323        /*
324         * We just returned from a non-default handler, we must re-enter the
325         * interpreter
326         */
327        AcpiExEnterInterpreter ();
328    }
329
330    return_ACPI_STATUS (Status);
331}
332
333
334/*******************************************************************************
335 *
336 * FUNCTION:    AcpiEvDetachRegion
337 *
338 * PARAMETERS:  RegionObj           - Region Object
339 *              AcpiNsIsLocked      - Namespace Region Already Locked?
340 *
341 * RETURN:      None
342 *
343 * DESCRIPTION: Break the association between the handler and the region
344 *              this is a two way association.
345 *
346 ******************************************************************************/
347
348void
349AcpiEvDetachRegion (
350    ACPI_OPERAND_OBJECT     *RegionObj,
351    BOOLEAN                 AcpiNsIsLocked)
352{
353    ACPI_OPERAND_OBJECT     *HandlerObj;
354    ACPI_OPERAND_OBJECT     *ObjDesc;
355    ACPI_OPERAND_OBJECT     *StartDesc;
356    ACPI_OPERAND_OBJECT     **LastObjPtr;
357    ACPI_ADR_SPACE_SETUP    RegionSetup;
358    void                    **RegionContext;
359    ACPI_OPERAND_OBJECT     *RegionObj2;
360    ACPI_STATUS             Status;
361
362
363    ACPI_FUNCTION_TRACE (EvDetachRegion);
364
365
366    RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
367    if (!RegionObj2)
368    {
369        return_VOID;
370    }
371    RegionContext = &RegionObj2->Extra.RegionContext;
372
373    /* Get the address handler from the region object */
374
375    HandlerObj = RegionObj->Region.Handler;
376    if (!HandlerObj)
377    {
378        /* This region has no handler, all done */
379
380        return_VOID;
381    }
382
383    /* Find this region in the handler's list */
384
385    ObjDesc = HandlerObj->AddressSpace.RegionList;
386    StartDesc = ObjDesc;
387    LastObjPtr = &HandlerObj->AddressSpace.RegionList;
388
389    while (ObjDesc)
390    {
391        /* Is this the correct Region? */
392
393        if (ObjDesc == RegionObj)
394        {
395            ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
396                "Removing Region %p from address handler %p\n",
397                RegionObj, HandlerObj));
398
399            /* This is it, remove it from the handler's list */
400
401            *LastObjPtr = ObjDesc->Region.Next;
402            ObjDesc->Region.Next = NULL;        /* Must clear field */
403
404            if (AcpiNsIsLocked)
405            {
406                Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
407                if (ACPI_FAILURE (Status))
408                {
409                    return_VOID;
410                }
411            }
412
413            /* Now stop region accesses by executing the _REG method */
414
415            Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_DISCONNECT);
416            if (ACPI_FAILURE (Status))
417            {
418                ACPI_EXCEPTION ((AE_INFO, Status, "from region _REG, [%s]",
419                    AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
420            }
421
422            if (AcpiNsIsLocked)
423            {
424                Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
425                if (ACPI_FAILURE (Status))
426                {
427                    return_VOID;
428                }
429            }
430
431            /*
432             * If the region has been activated, call the setup handler with
433             * the deactivate notification
434             */
435            if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)
436            {
437                RegionSetup = HandlerObj->AddressSpace.Setup;
438                Status = RegionSetup (RegionObj, ACPI_REGION_DEACTIVATE,
439                    HandlerObj->AddressSpace.Context, RegionContext);
440
441                /*
442                 * RegionContext should have been released by the deactivate
443                 * operation. We don't need access to it anymore here.
444                 */
445                if (RegionContext)
446                {
447                    *RegionContext = NULL;
448                }
449
450                /* Init routine may fail, Just ignore errors */
451
452                if (ACPI_FAILURE (Status))
453                {
454                    ACPI_EXCEPTION ((AE_INFO, Status,
455                        "from region handler - deactivate, [%s]",
456                        AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
457                }
458
459                RegionObj->Region.Flags &= ~(AOPOBJ_SETUP_COMPLETE);
460            }
461
462            /*
463             * Remove handler reference in the region
464             *
465             * NOTE: this doesn't mean that the region goes away, the region
466             * is just inaccessible as indicated to the _REG method
467             *
468             * If the region is on the handler's list, this must be the
469             * region's handler
470             */
471            RegionObj->Region.Handler = NULL;
472            AcpiUtRemoveReference (HandlerObj);
473
474            return_VOID;
475        }
476
477        /* Walk the linked list of handlers */
478
479        LastObjPtr = &ObjDesc->Region.Next;
480        ObjDesc = ObjDesc->Region.Next;
481
482        /* Prevent infinite loop if list is corrupted */
483
484        if (ObjDesc == StartDesc)
485        {
486            ACPI_ERROR ((AE_INFO,
487                "Circular handler list in region object %p",
488                RegionObj));
489            return_VOID;
490        }
491    }
492
493    /* If we get here, the region was not in the handler's region list */
494
495    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
496        "Cannot remove region %p from address handler %p\n",
497        RegionObj, HandlerObj));
498
499    return_VOID;
500}
501
502
503/*******************************************************************************
504 *
505 * FUNCTION:    AcpiEvAttachRegion
506 *
507 * PARAMETERS:  HandlerObj          - Handler Object
508 *              RegionObj           - Region Object
509 *              AcpiNsIsLocked      - Namespace Region Already Locked?
510 *
511 * RETURN:      None
512 *
513 * DESCRIPTION: Create the association between the handler and the region
514 *              this is a two way association.
515 *
516 ******************************************************************************/
517
518ACPI_STATUS
519AcpiEvAttachRegion (
520    ACPI_OPERAND_OBJECT     *HandlerObj,
521    ACPI_OPERAND_OBJECT     *RegionObj,
522    BOOLEAN                 AcpiNsIsLocked)
523{
524
525    ACPI_FUNCTION_TRACE (EvAttachRegion);
526
527
528    /* Install the region's handler */
529
530    if (RegionObj->Region.Handler)
531    {
532        return_ACPI_STATUS (AE_ALREADY_EXISTS);
533    }
534
535    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
536        "Adding Region [%4.4s] %p to address handler %p [%s]\n",
537        AcpiUtGetNodeName (RegionObj->Region.Node),
538        RegionObj, HandlerObj,
539        AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
540
541    /* Link this region to the front of the handler's list */
542
543    RegionObj->Region.Next = HandlerObj->AddressSpace.RegionList;
544    HandlerObj->AddressSpace.RegionList = RegionObj;
545    RegionObj->Region.Handler = HandlerObj;
546    AcpiUtAddReference (HandlerObj);
547
548    return_ACPI_STATUS (AE_OK);
549}
550
551
552/*******************************************************************************
553 *
554 * FUNCTION:    AcpiEvExecuteRegMethod
555 *
556 * PARAMETERS:  RegionObj           - Region object
557 *              Function            - Passed to _REG: On (1) or Off (0)
558 *
559 * RETURN:      Status
560 *
561 * DESCRIPTION: Execute _REG method for a region
562 *
563 ******************************************************************************/
564
565ACPI_STATUS
566AcpiEvExecuteRegMethod (
567    ACPI_OPERAND_OBJECT     *RegionObj,
568    UINT32                  Function)
569{
570    ACPI_EVALUATE_INFO      *Info;
571    ACPI_OPERAND_OBJECT     *Args[3];
572    ACPI_OPERAND_OBJECT     *RegionObj2;
573    const ACPI_NAME         *RegNamePtr = ACPI_CAST_PTR (ACPI_NAME, METHOD_NAME__REG);
574    ACPI_NAMESPACE_NODE     *MethodNode;
575    ACPI_NAMESPACE_NODE     *Node;
576    ACPI_STATUS             Status;
577
578
579    ACPI_FUNCTION_TRACE (EvExecuteRegMethod);
580
581
582    if (!AcpiGbl_NamespaceInitialized ||
583        RegionObj->Region.Handler == NULL)
584    {
585        return_ACPI_STATUS (AE_OK);
586    }
587
588    RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
589    if (!RegionObj2)
590    {
591        return_ACPI_STATUS (AE_NOT_EXIST);
592    }
593
594    /*
595     * Find any "_REG" method associated with this region definition.
596     * The method should always be updated as this function may be
597     * invoked after a namespace change.
598     */
599    Node = RegionObj->Region.Node->Parent;
600    Status = AcpiNsSearchOneScope (
601        *RegNamePtr, Node, ACPI_TYPE_METHOD, &MethodNode);
602    if (ACPI_SUCCESS (Status))
603    {
604        /*
605         * The _REG method is optional and there can be only one per
606         * region definition. This will be executed when the handler is
607         * attached or removed.
608         */
609        RegionObj2->Extra.Method_REG = MethodNode;
610    }
611    if (RegionObj2->Extra.Method_REG == NULL)
612    {
613        return_ACPI_STATUS (AE_OK);
614    }
615
616    /* _REG(DISCONNECT) should be paired with _REG(CONNECT) */
617
618    if ((Function == ACPI_REG_CONNECT &&
619        RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED) ||
620        (Function == ACPI_REG_DISCONNECT &&
621         !(RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED)))
622    {
623        return_ACPI_STATUS (AE_OK);
624    }
625
626    /* Allocate and initialize the evaluation information block */
627
628    Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
629    if (!Info)
630    {
631        return_ACPI_STATUS (AE_NO_MEMORY);
632    }
633
634    Info->PrefixNode = RegionObj2->Extra.Method_REG;
635    Info->RelativePathname = NULL;
636    Info->Parameters = Args;
637    Info->Flags = ACPI_IGNORE_RETURN_VALUE;
638
639    /*
640     * The _REG method has two arguments:
641     *
642     * Arg0 - Integer:
643     *  Operation region space ID Same value as RegionObj->Region.SpaceId
644     *
645     * Arg1 - Integer:
646     *  connection status 1 for connecting the handler, 0 for disconnecting
647     *  the handler (Passed as a parameter)
648     */
649    Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId);
650    if (!Args[0])
651    {
652        Status = AE_NO_MEMORY;
653        goto Cleanup1;
654    }
655
656    Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function);
657    if (!Args[1])
658    {
659        Status = AE_NO_MEMORY;
660        goto Cleanup2;
661    }
662
663    Args[2] = NULL; /* Terminate list */
664
665    /* Execute the method, no return value */
666
667    ACPI_DEBUG_EXEC (
668        AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL));
669
670    Status = AcpiNsEvaluate (Info);
671    AcpiUtRemoveReference (Args[1]);
672
673    if (ACPI_FAILURE (Status))
674    {
675        goto Cleanup2;
676    }
677
678    if (Function == ACPI_REG_CONNECT)
679    {
680        RegionObj->Common.Flags |= AOPOBJ_REG_CONNECTED;
681    }
682    else
683    {
684        RegionObj->Common.Flags &= ~AOPOBJ_REG_CONNECTED;
685    }
686
687Cleanup2:
688    AcpiUtRemoveReference (Args[0]);
689
690Cleanup1:
691    ACPI_FREE (Info);
692    return_ACPI_STATUS (Status);
693}
694
695
696/*******************************************************************************
697 *
698 * FUNCTION:    AcpiEvExecuteRegMethods
699 *
700 * PARAMETERS:  Node            - Namespace node for the device
701 *              SpaceId         - The address space ID
702 *              Function        - Passed to _REG: On (1) or Off (0)
703 *
704 * RETURN:      None
705 *
706 * DESCRIPTION: Run all _REG methods for the input Space ID;
707 *              Note: assumes namespace is locked, or system init time.
708 *
709 ******************************************************************************/
710
711void
712AcpiEvExecuteRegMethods (
713    ACPI_NAMESPACE_NODE     *Node,
714    ACPI_ADR_SPACE_TYPE     SpaceId,
715    UINT32                  Function)
716{
717    ACPI_REG_WALK_INFO      Info;
718
719
720    ACPI_FUNCTION_TRACE (EvExecuteRegMethods);
721
722    Info.SpaceId = SpaceId;
723    Info.Function = Function;
724    Info.RegRunCount = 0;
725
726    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES,
727        "    Running _REG methods for SpaceId %s\n",
728        AcpiUtGetRegionName (Info.SpaceId)));
729
730    /*
731     * Run all _REG methods for all Operation Regions for this space ID. This
732     * is a separate walk in order to handle any interdependencies between
733     * regions and _REG methods. (i.e. handlers must be installed for all
734     * regions of this Space ID before we can run any _REG methods)
735     */
736    (void) AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
737        ACPI_NS_WALK_UNLOCK, AcpiEvRegRun, NULL, &Info, NULL);
738
739    /* Special case for EC: handle "orphan" _REG methods with no region */
740
741    if (SpaceId == ACPI_ADR_SPACE_EC)
742    {
743        AcpiEvOrphanEcRegMethod (Node);
744    }
745
746    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_NAMES,
747        "    Executed %u _REG methods for SpaceId %s\n",
748        Info.RegRunCount, AcpiUtGetRegionName (Info.SpaceId)));
749
750    return_VOID;
751}
752
753
754/*******************************************************************************
755 *
756 * FUNCTION:    AcpiEvRegRun
757 *
758 * PARAMETERS:  WalkNamespace callback
759 *
760 * DESCRIPTION: Run _REG method for region objects of the requested spaceID
761 *
762 ******************************************************************************/
763
764static ACPI_STATUS
765AcpiEvRegRun (
766    ACPI_HANDLE             ObjHandle,
767    UINT32                  Level,
768    void                    *Context,
769    void                    **ReturnValue)
770{
771    ACPI_OPERAND_OBJECT     *ObjDesc;
772    ACPI_NAMESPACE_NODE     *Node;
773    ACPI_STATUS             Status;
774    ACPI_REG_WALK_INFO      *Info;
775
776
777    Info = ACPI_CAST_PTR (ACPI_REG_WALK_INFO, Context);
778
779    /* Convert and validate the device handle */
780
781    Node = AcpiNsValidateHandle (ObjHandle);
782    if (!Node)
783    {
784        return (AE_BAD_PARAMETER);
785    }
786
787    /*
788     * We only care about regions.and objects that are allowed to have address
789     * space handlers
790     */
791    if ((Node->Type != ACPI_TYPE_REGION) &&
792        (Node != AcpiGbl_RootNode))
793    {
794        return (AE_OK);
795    }
796
797    /* Check for an existing internal object */
798
799    ObjDesc = AcpiNsGetAttachedObject (Node);
800    if (!ObjDesc)
801    {
802        /* No object, just exit */
803
804        return (AE_OK);
805    }
806
807    /* Object is a Region */
808
809    if (ObjDesc->Region.SpaceId != Info->SpaceId)
810    {
811        /* This region is for a different address space, just ignore it */
812
813        return (AE_OK);
814    }
815
816    Info->RegRunCount++;
817    Status = AcpiEvExecuteRegMethod (ObjDesc, Info->Function);
818    return (Status);
819}
820
821
822/*******************************************************************************
823 *
824 * FUNCTION:    AcpiEvOrphanEcRegMethod
825 *
826 * PARAMETERS:  EcDeviceNode        - Namespace node for an EC device
827 *
828 * RETURN:      None
829 *
830 * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
831 *              device. This is a _REG method that has no corresponding region
832 *              within the EC device scope. The orphan _REG method appears to
833 *              have been enabled by the description of the ECDT in the ACPI
834 *              specification: "The availability of the region space can be
835 *              detected by providing a _REG method object underneath the
836 *              Embedded Controller device."
837 *
838 *              To quickly access the EC device, we use the EcDeviceNode used
839 *              during EC handler installation. Otherwise, we would need to
840 *              perform a time consuming namespace walk, executing _HID
841 *              methods to find the EC device.
842 *
843 *  MUTEX:      Assumes the namespace is locked
844 *
845 ******************************************************************************/
846
847static void
848AcpiEvOrphanEcRegMethod (
849    ACPI_NAMESPACE_NODE     *EcDeviceNode)
850{
851    ACPI_HANDLE             RegMethod;
852    ACPI_NAMESPACE_NODE     *NextNode;
853    ACPI_STATUS             Status;
854    ACPI_OBJECT_LIST        Args;
855    ACPI_OBJECT             Objects[2];
856
857
858    ACPI_FUNCTION_TRACE (EvOrphanEcRegMethod);
859
860
861    if (!EcDeviceNode)
862    {
863        return_VOID;
864    }
865
866    /* Namespace is currently locked, must release */
867
868    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
869
870    /* Get a handle to a _REG method immediately under the EC device */
871
872    Status = AcpiGetHandle (EcDeviceNode, METHOD_NAME__REG, &RegMethod);
873    if (ACPI_FAILURE (Status))
874    {
875        goto Exit; /* There is no _REG method present */
876    }
877
878    /*
879     * Execute the _REG method only if there is no Operation Region in
880     * this scope with the Embedded Controller space ID. Otherwise, it
881     * will already have been executed. Note, this allows for Regions
882     * with other space IDs to be present; but the code below will then
883     * execute the _REG method with the EmbeddedControl SpaceID argument.
884     */
885    NextNode = AcpiNsGetNextNode (EcDeviceNode, NULL);
886    while (NextNode)
887    {
888        if ((NextNode->Type == ACPI_TYPE_REGION) &&
889            (NextNode->Object) &&
890            (NextNode->Object->Region.SpaceId == ACPI_ADR_SPACE_EC))
891        {
892            goto Exit; /* Do not execute the _REG */
893        }
894
895        NextNode = AcpiNsGetNextNode (EcDeviceNode, NextNode);
896    }
897
898    /* Evaluate the _REG(EmbeddedControl,Connect) method */
899
900    Args.Count = 2;
901    Args.Pointer = Objects;
902    Objects[0].Type = ACPI_TYPE_INTEGER;
903    Objects[0].Integer.Value = ACPI_ADR_SPACE_EC;
904    Objects[1].Type = ACPI_TYPE_INTEGER;
905    Objects[1].Integer.Value = ACPI_REG_CONNECT;
906
907    Status = AcpiEvaluateObject (RegMethod, NULL, &Args, NULL);
908
909Exit:
910    /* We ignore all errors from above, don't care */
911
912    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
913    return_VOID;
914}
915