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