xref: /freebsd/sys/contrib/dev/acpica/components/events/evregion.c (revision 147972555f2c70f64cc54182dc18326456e46b92)
1 /******************************************************************************
2  *
3  * Module Name: evregion - ACPI AddressSpace (OpRegion) handler dispatch
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2012, 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 
59 static BOOLEAN
60 AcpiEvHasDefaultHandler (
61     ACPI_NAMESPACE_NODE     *Node,
62     ACPI_ADR_SPACE_TYPE     SpaceId);
63 
64 static void
65 AcpiEvOrphanEcRegMethod (
66     void);
67 
68 static ACPI_STATUS
69 AcpiEvRegRun (
70     ACPI_HANDLE             ObjHandle,
71     UINT32                  Level,
72     void                    *Context,
73     void                    **ReturnValue);
74 
75 static ACPI_STATUS
76 AcpiEvInstallHandler (
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 
86 static 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 
107 ACPI_STATUS
108 AcpiEvInstallRegionHandlers (
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 
165 UnlockAndExit:
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 
185 static BOOLEAN
186 AcpiEvHasDefaultHandler (
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 
235 ACPI_STATUS
236 AcpiEvInitializeOpRegions (
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 
289 ACPI_STATUS
290 AcpiEvExecuteRegMethod (
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 
361 Cleanup2:
362     AcpiUtRemoveReference (Args[0]);
363 
364 Cleanup1:
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  *              FieldObj            - Corresponding field. Can be NULL.
376  *              Function            - Read or Write operation
377  *              RegionOffset        - Where in the region to read or write
378  *              BitWidth            - Field width in bits (8, 16, 32, or 64)
379  *              Value               - Pointer to in or out value, must be
380  *                                    a full 64-bit integer
381  *
382  * RETURN:      Status
383  *
384  * DESCRIPTION: Dispatch an address space or operation region access to
385  *              a previously installed handler.
386  *
387  ******************************************************************************/
388 
389 ACPI_STATUS
390 AcpiEvAddressSpaceDispatch (
391     ACPI_OPERAND_OBJECT     *RegionObj,
392     ACPI_OPERAND_OBJECT     *FieldObj,
393     UINT32                  Function,
394     UINT32                  RegionOffset,
395     UINT32                  BitWidth,
396     UINT64                  *Value)
397 {
398     ACPI_STATUS             Status;
399     ACPI_ADR_SPACE_HANDLER  Handler;
400     ACPI_ADR_SPACE_SETUP    RegionSetup;
401     ACPI_OPERAND_OBJECT     *HandlerDesc;
402     ACPI_OPERAND_OBJECT     *RegionObj2;
403     void                    *RegionContext = NULL;
404     ACPI_CONNECTION_INFO    *Context;
405 
406 
407     ACPI_FUNCTION_TRACE (EvAddressSpaceDispatch);
408 
409 
410     RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
411     if (!RegionObj2)
412     {
413         return_ACPI_STATUS (AE_NOT_EXIST);
414     }
415 
416     /* Ensure that there is a handler associated with this region */
417 
418     HandlerDesc = RegionObj->Region.Handler;
419     if (!HandlerDesc)
420     {
421         ACPI_ERROR ((AE_INFO,
422             "No handler for Region [%4.4s] (%p) [%s]",
423             AcpiUtGetNodeName (RegionObj->Region.Node),
424             RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
425 
426         return_ACPI_STATUS (AE_NOT_EXIST);
427     }
428 
429     Context = HandlerDesc->AddressSpace.Context;
430 
431     /*
432      * It may be the case that the region has never been initialized.
433      * Some types of regions require special init code
434      */
435     if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE))
436     {
437         /* This region has not been initialized yet, do it */
438 
439         RegionSetup = HandlerDesc->AddressSpace.Setup;
440         if (!RegionSetup)
441         {
442             /* No initialization routine, exit with error */
443 
444             ACPI_ERROR ((AE_INFO,
445                 "No init routine for region(%p) [%s]",
446                 RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
447             return_ACPI_STATUS (AE_NOT_EXIST);
448         }
449 
450         /*
451          * We must exit the interpreter because the region setup will
452          * potentially execute control methods (for example, the _REG method
453          * for this region)
454          */
455         AcpiExExitInterpreter ();
456 
457         Status = RegionSetup (RegionObj, ACPI_REGION_ACTIVATE,
458                     Context, &RegionContext);
459 
460         /* Re-enter the interpreter */
461 
462         AcpiExEnterInterpreter ();
463 
464         /* Check for failure of the Region Setup */
465 
466         if (ACPI_FAILURE (Status))
467         {
468             ACPI_EXCEPTION ((AE_INFO, Status,
469                 "During region initialization: [%s]",
470                 AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
471             return_ACPI_STATUS (Status);
472         }
473 
474         /* Region initialization may have been completed by RegionSetup */
475 
476         if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE))
477         {
478             RegionObj->Region.Flags |= AOPOBJ_SETUP_COMPLETE;
479 
480             if (RegionObj2->Extra.RegionContext)
481             {
482                 /* The handler for this region was already installed */
483 
484                 ACPI_FREE (RegionContext);
485             }
486             else
487             {
488                 /*
489                  * Save the returned context for use in all accesses to
490                  * this particular region
491                  */
492                 RegionObj2->Extra.RegionContext = RegionContext;
493             }
494         }
495     }
496 
497     /* We have everything we need, we can invoke the address space handler */
498 
499     Handler = HandlerDesc->AddressSpace.Handler;
500 
501     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
502         "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
503         &RegionObj->Region.Handler->AddressSpace, Handler,
504         ACPI_FORMAT_NATIVE_UINT (RegionObj->Region.Address + RegionOffset),
505         AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
506 
507 
508     /*
509      * Special handling for GenericSerialBus and GeneralPurposeIo:
510      * There are three extra parameters that must be passed to the
511      * handler via the context:
512      *   1) Connection buffer, a resource template from Connection() op.
513      *   2) Length of the above buffer.
514      *   3) Actual access length from the AccessAs() op.
515      */
516     if (((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) ||
517             (RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO)) &&
518         Context &&
519         FieldObj)
520     {
521         /* Get the Connection (ResourceTemplate) buffer */
522 
523         Context->Connection = FieldObj->Field.ResourceBuffer;
524         Context->Length = FieldObj->Field.ResourceLength;
525         Context->AccessLength = FieldObj->Field.AccessLength;
526     }
527 
528     if (!(HandlerDesc->AddressSpace.HandlerFlags &
529             ACPI_ADDR_HANDLER_DEFAULT_INSTALLED))
530     {
531         /*
532          * For handlers other than the default (supplied) handlers, we must
533          * exit the interpreter because the handler *might* block -- we don't
534          * know what it will do, so we can't hold the lock on the intepreter.
535          */
536         AcpiExExitInterpreter();
537     }
538 
539     /* Call the handler */
540 
541     Status = Handler (Function,
542         (RegionObj->Region.Address + RegionOffset), BitWidth, Value,
543         Context, RegionObj2->Extra.RegionContext);
544 
545     if (ACPI_FAILURE (Status))
546     {
547         ACPI_EXCEPTION ((AE_INFO, Status, "Returned by Handler for [%s]",
548             AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
549     }
550 
551     if (!(HandlerDesc->AddressSpace.HandlerFlags &
552             ACPI_ADDR_HANDLER_DEFAULT_INSTALLED))
553     {
554         /*
555          * We just returned from a non-default handler, we must re-enter the
556          * interpreter
557          */
558        AcpiExEnterInterpreter ();
559     }
560 
561     return_ACPI_STATUS (Status);
562 }
563 
564 
565 /*******************************************************************************
566  *
567  * FUNCTION:    AcpiEvDetachRegion
568  *
569  * PARAMETERS:  RegionObj           - Region Object
570  *              AcpiNsIsLocked      - Namespace Region Already Locked?
571  *
572  * RETURN:      None
573  *
574  * DESCRIPTION: Break the association between the handler and the region
575  *              this is a two way association.
576  *
577  ******************************************************************************/
578 
579 void
580 AcpiEvDetachRegion(
581     ACPI_OPERAND_OBJECT     *RegionObj,
582     BOOLEAN                 AcpiNsIsLocked)
583 {
584     ACPI_OPERAND_OBJECT     *HandlerObj;
585     ACPI_OPERAND_OBJECT     *ObjDesc;
586     ACPI_OPERAND_OBJECT     **LastObjPtr;
587     ACPI_ADR_SPACE_SETUP    RegionSetup;
588     void                    **RegionContext;
589     ACPI_OPERAND_OBJECT     *RegionObj2;
590     ACPI_STATUS             Status;
591 
592 
593     ACPI_FUNCTION_TRACE (EvDetachRegion);
594 
595 
596     RegionObj2 = AcpiNsGetSecondaryObject (RegionObj);
597     if (!RegionObj2)
598     {
599         return_VOID;
600     }
601     RegionContext = &RegionObj2->Extra.RegionContext;
602 
603     /* Get the address handler from the region object */
604 
605     HandlerObj = RegionObj->Region.Handler;
606     if (!HandlerObj)
607     {
608         /* This region has no handler, all done */
609 
610         return_VOID;
611     }
612 
613     /* Find this region in the handler's list */
614 
615     ObjDesc = HandlerObj->AddressSpace.RegionList;
616     LastObjPtr = &HandlerObj->AddressSpace.RegionList;
617 
618     while (ObjDesc)
619     {
620         /* Is this the correct Region? */
621 
622         if (ObjDesc == RegionObj)
623         {
624             ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
625                 "Removing Region %p from address handler %p\n",
626                 RegionObj, HandlerObj));
627 
628             /* This is it, remove it from the handler's list */
629 
630             *LastObjPtr = ObjDesc->Region.Next;
631             ObjDesc->Region.Next = NULL;        /* Must clear field */
632 
633             if (AcpiNsIsLocked)
634             {
635                 Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
636                 if (ACPI_FAILURE (Status))
637                 {
638                     return_VOID;
639                 }
640             }
641 
642             /* Now stop region accesses by executing the _REG method */
643 
644             Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_DISCONNECT);
645             if (ACPI_FAILURE (Status))
646             {
647                 ACPI_EXCEPTION ((AE_INFO, Status, "from region _REG, [%s]",
648                     AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
649             }
650 
651             if (AcpiNsIsLocked)
652             {
653                 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
654                 if (ACPI_FAILURE (Status))
655                 {
656                     return_VOID;
657                 }
658             }
659 
660             /*
661              * If the region has been activated, call the setup handler with
662              * the deactivate notification
663              */
664             if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)
665             {
666                 RegionSetup = HandlerObj->AddressSpace.Setup;
667                 Status = RegionSetup (RegionObj, ACPI_REGION_DEACTIVATE,
668                     HandlerObj->AddressSpace.Context, RegionContext);
669 
670                 /* Init routine may fail, Just ignore errors */
671 
672                 if (ACPI_FAILURE (Status))
673                 {
674                     ACPI_EXCEPTION ((AE_INFO, Status,
675                         "from region handler - deactivate, [%s]",
676                         AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
677                 }
678 
679                 RegionObj->Region.Flags &= ~(AOPOBJ_SETUP_COMPLETE);
680             }
681 
682             /*
683              * Remove handler reference in the region
684              *
685              * NOTE: this doesn't mean that the region goes away, the region
686              * is just inaccessible as indicated to the _REG method
687              *
688              * If the region is on the handler's list, this must be the
689              * region's handler
690              */
691             RegionObj->Region.Handler = NULL;
692             AcpiUtRemoveReference (HandlerObj);
693 
694             return_VOID;
695         }
696 
697         /* Walk the linked list of handlers */
698 
699         LastObjPtr = &ObjDesc->Region.Next;
700         ObjDesc = ObjDesc->Region.Next;
701     }
702 
703     /* If we get here, the region was not in the handler's region list */
704 
705     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
706         "Cannot remove region %p from address handler %p\n",
707         RegionObj, HandlerObj));
708 
709     return_VOID;
710 }
711 
712 
713 /*******************************************************************************
714  *
715  * FUNCTION:    AcpiEvAttachRegion
716  *
717  * PARAMETERS:  HandlerObj          - Handler Object
718  *              RegionObj           - Region Object
719  *              AcpiNsIsLocked      - Namespace Region Already Locked?
720  *
721  * RETURN:      None
722  *
723  * DESCRIPTION: Create the association between the handler and the region
724  *              this is a two way association.
725  *
726  ******************************************************************************/
727 
728 ACPI_STATUS
729 AcpiEvAttachRegion (
730     ACPI_OPERAND_OBJECT     *HandlerObj,
731     ACPI_OPERAND_OBJECT     *RegionObj,
732     BOOLEAN                 AcpiNsIsLocked)
733 {
734 
735     ACPI_FUNCTION_TRACE (EvAttachRegion);
736 
737 
738     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
739         "Adding Region [%4.4s] %p to address handler %p [%s]\n",
740         AcpiUtGetNodeName (RegionObj->Region.Node),
741         RegionObj, HandlerObj,
742         AcpiUtGetRegionName (RegionObj->Region.SpaceId)));
743 
744     /* Link this region to the front of the handler's list */
745 
746     RegionObj->Region.Next = HandlerObj->AddressSpace.RegionList;
747     HandlerObj->AddressSpace.RegionList = RegionObj;
748 
749     /* Install the region's handler */
750 
751     if (RegionObj->Region.Handler)
752     {
753         return_ACPI_STATUS (AE_ALREADY_EXISTS);
754     }
755 
756     RegionObj->Region.Handler = HandlerObj;
757     AcpiUtAddReference (HandlerObj);
758 
759     return_ACPI_STATUS (AE_OK);
760 }
761 
762 
763 /*******************************************************************************
764  *
765  * FUNCTION:    AcpiEvInstallHandler
766  *
767  * PARAMETERS:  WalkNamespace callback
768  *
769  * DESCRIPTION: This routine installs an address handler into objects that are
770  *              of type Region or Device.
771  *
772  *              If the Object is a Device, and the device has a handler of
773  *              the same type then the search is terminated in that branch.
774  *
775  *              This is because the existing handler is closer in proximity
776  *              to any more regions than the one we are trying to install.
777  *
778  ******************************************************************************/
779 
780 static ACPI_STATUS
781 AcpiEvInstallHandler (
782     ACPI_HANDLE             ObjHandle,
783     UINT32                  Level,
784     void                    *Context,
785     void                    **ReturnValue)
786 {
787     ACPI_OPERAND_OBJECT     *HandlerObj;
788     ACPI_OPERAND_OBJECT     *NextHandlerObj;
789     ACPI_OPERAND_OBJECT     *ObjDesc;
790     ACPI_NAMESPACE_NODE     *Node;
791     ACPI_STATUS             Status;
792 
793 
794     ACPI_FUNCTION_NAME (EvInstallHandler);
795 
796 
797     HandlerObj = (ACPI_OPERAND_OBJECT  *) Context;
798 
799     /* Parameter validation */
800 
801     if (!HandlerObj)
802     {
803         return (AE_OK);
804     }
805 
806     /* Convert and validate the device handle */
807 
808     Node = AcpiNsValidateHandle (ObjHandle);
809     if (!Node)
810     {
811         return (AE_BAD_PARAMETER);
812     }
813 
814     /*
815      * We only care about regions and objects that are allowed to have
816      * address space handlers
817      */
818     if ((Node->Type != ACPI_TYPE_DEVICE) &&
819         (Node->Type != ACPI_TYPE_REGION) &&
820         (Node != AcpiGbl_RootNode))
821     {
822         return (AE_OK);
823     }
824 
825     /* Check for an existing internal object */
826 
827     ObjDesc = AcpiNsGetAttachedObject (Node);
828     if (!ObjDesc)
829     {
830         /* No object, just exit */
831 
832         return (AE_OK);
833     }
834 
835     /* Devices are handled different than regions */
836 
837     if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE)
838     {
839         /* Check if this Device already has a handler for this address space */
840 
841         NextHandlerObj = ObjDesc->Device.Handler;
842         while (NextHandlerObj)
843         {
844             /* Found a handler, is it for the same address space? */
845 
846             if (NextHandlerObj->AddressSpace.SpaceId ==
847                     HandlerObj->AddressSpace.SpaceId)
848             {
849                 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
850                     "Found handler for region [%s] in device %p(%p) "
851                     "handler %p\n",
852                     AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId),
853                     ObjDesc, NextHandlerObj, HandlerObj));
854 
855                 /*
856                  * Since the object we found it on was a device, then it
857                  * means that someone has already installed a handler for
858                  * the branch of the namespace from this device on. Just
859                  * bail out telling the walk routine to not traverse this
860                  * branch. This preserves the scoping rule for handlers.
861                  */
862                 return (AE_CTRL_DEPTH);
863             }
864 
865             /* Walk the linked list of handlers attached to this device */
866 
867             NextHandlerObj = NextHandlerObj->AddressSpace.Next;
868         }
869 
870         /*
871          * As long as the device didn't have a handler for this space we
872          * don't care about it. We just ignore it and proceed.
873          */
874         return (AE_OK);
875     }
876 
877     /* Object is a Region */
878 
879     if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId)
880     {
881         /* This region is for a different address space, just ignore it */
882 
883         return (AE_OK);
884     }
885 
886     /*
887      * Now we have a region and it is for the handler's address space type.
888      *
889      * First disconnect region for any previous handler (if any)
890      */
891     AcpiEvDetachRegion (ObjDesc, FALSE);
892 
893     /* Connect the region to the new handler */
894 
895     Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE);
896     return (Status);
897 }
898 
899 
900 /*******************************************************************************
901  *
902  * FUNCTION:    AcpiEvInstallSpaceHandler
903  *
904  * PARAMETERS:  Node            - Namespace node for the device
905  *              SpaceId         - The address space ID
906  *              Handler         - Address of the handler
907  *              Setup           - Address of the setup function
908  *              Context         - Value passed to the handler on each access
909  *
910  * RETURN:      Status
911  *
912  * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId.
913  *              Assumes namespace is locked
914  *
915  ******************************************************************************/
916 
917 ACPI_STATUS
918 AcpiEvInstallSpaceHandler (
919     ACPI_NAMESPACE_NODE     *Node,
920     ACPI_ADR_SPACE_TYPE     SpaceId,
921     ACPI_ADR_SPACE_HANDLER  Handler,
922     ACPI_ADR_SPACE_SETUP    Setup,
923     void                    *Context)
924 {
925     ACPI_OPERAND_OBJECT     *ObjDesc;
926     ACPI_OPERAND_OBJECT     *HandlerObj;
927     ACPI_STATUS             Status;
928     ACPI_OBJECT_TYPE        Type;
929     UINT8                  Flags = 0;
930 
931 
932     ACPI_FUNCTION_TRACE (EvInstallSpaceHandler);
933 
934 
935     /*
936      * This registration is valid for only the types below and the root. This
937      * is where the default handlers get placed.
938      */
939     if ((Node->Type != ACPI_TYPE_DEVICE)     &&
940         (Node->Type != ACPI_TYPE_PROCESSOR)  &&
941         (Node->Type != ACPI_TYPE_THERMAL)    &&
942         (Node != AcpiGbl_RootNode))
943     {
944         Status = AE_BAD_PARAMETER;
945         goto UnlockAndExit;
946     }
947 
948     if (Handler == ACPI_DEFAULT_HANDLER)
949     {
950         Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
951 
952         switch (SpaceId)
953         {
954         case ACPI_ADR_SPACE_SYSTEM_MEMORY:
955             Handler = AcpiExSystemMemorySpaceHandler;
956             Setup   = AcpiEvSystemMemoryRegionSetup;
957             break;
958 
959         case ACPI_ADR_SPACE_SYSTEM_IO:
960             Handler = AcpiExSystemIoSpaceHandler;
961             Setup   = AcpiEvIoSpaceRegionSetup;
962             break;
963 
964         case ACPI_ADR_SPACE_PCI_CONFIG:
965             Handler = AcpiExPciConfigSpaceHandler;
966             Setup   = AcpiEvPciConfigRegionSetup;
967             break;
968 
969         case ACPI_ADR_SPACE_CMOS:
970             Handler = AcpiExCmosSpaceHandler;
971             Setup   = AcpiEvCmosRegionSetup;
972             break;
973 
974         case ACPI_ADR_SPACE_PCI_BAR_TARGET:
975             Handler = AcpiExPciBarSpaceHandler;
976             Setup   = AcpiEvPciBarRegionSetup;
977             break;
978 
979         case ACPI_ADR_SPACE_DATA_TABLE:
980             Handler = AcpiExDataTableSpaceHandler;
981             Setup   = NULL;
982             break;
983 
984         default:
985             Status = AE_BAD_PARAMETER;
986             goto UnlockAndExit;
987         }
988     }
989 
990     /* If the caller hasn't specified a setup routine, use the default */
991 
992     if (!Setup)
993     {
994         Setup = AcpiEvDefaultRegionSetup;
995     }
996 
997     /* Check for an existing internal object */
998 
999     ObjDesc = AcpiNsGetAttachedObject (Node);
1000     if (ObjDesc)
1001     {
1002         /*
1003          * The attached device object already exists. Make sure the handler
1004          * is not already installed.
1005          */
1006         HandlerObj = ObjDesc->Device.Handler;
1007 
1008         /* Walk the handler list for this device */
1009 
1010         while (HandlerObj)
1011         {
1012             /* Same SpaceId indicates a handler already installed */
1013 
1014             if (HandlerObj->AddressSpace.SpaceId == SpaceId)
1015             {
1016                 if (HandlerObj->AddressSpace.Handler == Handler)
1017                 {
1018                     /*
1019                      * It is (relatively) OK to attempt to install the SAME
1020                      * handler twice. This can easily happen with the
1021                      * PCI_Config space.
1022                      */
1023                     Status = AE_SAME_HANDLER;
1024                     goto UnlockAndExit;
1025                 }
1026                 else
1027                 {
1028                     /* A handler is already installed */
1029 
1030                     Status = AE_ALREADY_EXISTS;
1031                 }
1032                 goto UnlockAndExit;
1033             }
1034 
1035             /* Walk the linked list of handlers */
1036 
1037             HandlerObj = HandlerObj->AddressSpace.Next;
1038         }
1039     }
1040     else
1041     {
1042         ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
1043             "Creating object on Device %p while installing handler\n", Node));
1044 
1045         /* ObjDesc does not exist, create one */
1046 
1047         if (Node->Type == ACPI_TYPE_ANY)
1048         {
1049             Type = ACPI_TYPE_DEVICE;
1050         }
1051         else
1052         {
1053             Type = Node->Type;
1054         }
1055 
1056         ObjDesc = AcpiUtCreateInternalObject (Type);
1057         if (!ObjDesc)
1058         {
1059             Status = AE_NO_MEMORY;
1060             goto UnlockAndExit;
1061         }
1062 
1063         /* Init new descriptor */
1064 
1065         ObjDesc->Common.Type = (UINT8) Type;
1066 
1067         /* Attach the new object to the Node */
1068 
1069         Status = AcpiNsAttachObject (Node, ObjDesc, Type);
1070 
1071         /* Remove local reference to the object */
1072 
1073         AcpiUtRemoveReference (ObjDesc);
1074 
1075         if (ACPI_FAILURE (Status))
1076         {
1077             goto UnlockAndExit;
1078         }
1079     }
1080 
1081     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
1082         "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
1083         AcpiUtGetRegionName (SpaceId), SpaceId,
1084         AcpiUtGetNodeName (Node), Node, ObjDesc));
1085 
1086     /*
1087      * Install the handler
1088      *
1089      * At this point there is no existing handler. Just allocate the object
1090      * for the handler and link it into the list.
1091      */
1092     HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
1093     if (!HandlerObj)
1094     {
1095         Status = AE_NO_MEMORY;
1096         goto UnlockAndExit;
1097     }
1098 
1099     /* Init handler obj */
1100 
1101     HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId;
1102     HandlerObj->AddressSpace.HandlerFlags = Flags;
1103     HandlerObj->AddressSpace.RegionList = NULL;
1104     HandlerObj->AddressSpace.Node = Node;
1105     HandlerObj->AddressSpace.Handler = Handler;
1106     HandlerObj->AddressSpace.Context = Context;
1107     HandlerObj->AddressSpace.Setup  = Setup;
1108 
1109     /* Install at head of Device.AddressSpace list */
1110 
1111     HandlerObj->AddressSpace.Next = ObjDesc->Device.Handler;
1112 
1113     /*
1114      * The Device object is the first reference on the HandlerObj.
1115      * Each region that uses the handler adds a reference.
1116      */
1117     ObjDesc->Device.Handler = HandlerObj;
1118 
1119     /*
1120      * Walk the namespace finding all of the regions this
1121      * handler will manage.
1122      *
1123      * Start at the device and search the branch toward
1124      * the leaf nodes until either the leaf is encountered or
1125      * a device is detected that has an address handler of the
1126      * same type.
1127      *
1128      * In either case, back up and search down the remainder
1129      * of the branch
1130      */
1131     Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
1132                 ACPI_NS_WALK_UNLOCK, AcpiEvInstallHandler, NULL,
1133                 HandlerObj, NULL);
1134 
1135 UnlockAndExit:
1136     return_ACPI_STATUS (Status);
1137 }
1138 
1139 
1140 /*******************************************************************************
1141  *
1142  * FUNCTION:    AcpiEvExecuteRegMethods
1143  *
1144  * PARAMETERS:  Node            - Namespace node for the device
1145  *              SpaceId         - The address space ID
1146  *
1147  * RETURN:      Status
1148  *
1149  * DESCRIPTION: Run all _REG methods for the input Space ID;
1150  *              Note: assumes namespace is locked, or system init time.
1151  *
1152  ******************************************************************************/
1153 
1154 ACPI_STATUS
1155 AcpiEvExecuteRegMethods (
1156     ACPI_NAMESPACE_NODE     *Node,
1157     ACPI_ADR_SPACE_TYPE     SpaceId)
1158 {
1159     ACPI_STATUS             Status;
1160 
1161 
1162     ACPI_FUNCTION_TRACE (EvExecuteRegMethods);
1163 
1164 
1165     /*
1166      * Run all _REG methods for all Operation Regions for this space ID. This
1167      * is a separate walk in order to handle any interdependencies between
1168      * regions and _REG methods. (i.e. handlers must be installed for all
1169      * regions of this Space ID before we can run any _REG methods)
1170      */
1171     Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
1172                 ACPI_NS_WALK_UNLOCK, AcpiEvRegRun, NULL,
1173                 &SpaceId, NULL);
1174 
1175     /* Special case for EC: handle "orphan" _REG methods with no region */
1176 
1177     if (SpaceId == ACPI_ADR_SPACE_EC)
1178     {
1179         AcpiEvOrphanEcRegMethod ();
1180     }
1181 
1182     return_ACPI_STATUS (Status);
1183 }
1184 
1185 
1186 /*******************************************************************************
1187  *
1188  * FUNCTION:    AcpiEvRegRun
1189  *
1190  * PARAMETERS:  WalkNamespace callback
1191  *
1192  * DESCRIPTION: Run _REG method for region objects of the requested spaceID
1193  *
1194  ******************************************************************************/
1195 
1196 static ACPI_STATUS
1197 AcpiEvRegRun (
1198     ACPI_HANDLE             ObjHandle,
1199     UINT32                  Level,
1200     void                    *Context,
1201     void                    **ReturnValue)
1202 {
1203     ACPI_OPERAND_OBJECT     *ObjDesc;
1204     ACPI_NAMESPACE_NODE     *Node;
1205     ACPI_ADR_SPACE_TYPE     SpaceId;
1206     ACPI_STATUS             Status;
1207 
1208 
1209     SpaceId = *ACPI_CAST_PTR (ACPI_ADR_SPACE_TYPE, Context);
1210 
1211     /* Convert and validate the device handle */
1212 
1213     Node = AcpiNsValidateHandle (ObjHandle);
1214     if (!Node)
1215     {
1216         return (AE_BAD_PARAMETER);
1217     }
1218 
1219     /*
1220      * We only care about regions.and objects that are allowed to have address
1221      * space handlers
1222      */
1223     if ((Node->Type != ACPI_TYPE_REGION) &&
1224         (Node != AcpiGbl_RootNode))
1225     {
1226         return (AE_OK);
1227     }
1228 
1229     /* Check for an existing internal object */
1230 
1231     ObjDesc = AcpiNsGetAttachedObject (Node);
1232     if (!ObjDesc)
1233     {
1234         /* No object, just exit */
1235 
1236         return (AE_OK);
1237     }
1238 
1239     /* Object is a Region */
1240 
1241     if (ObjDesc->Region.SpaceId != SpaceId)
1242     {
1243         /* This region is for a different address space, just ignore it */
1244 
1245         return (AE_OK);
1246     }
1247 
1248     Status = AcpiEvExecuteRegMethod (ObjDesc, ACPI_REG_CONNECT);
1249     return (Status);
1250 }
1251 
1252 
1253 /*******************************************************************************
1254  *
1255  * FUNCTION:    AcpiEvOrphanEcRegMethod
1256  *
1257  * PARAMETERS:  None
1258  *
1259  * RETURN:      None
1260  *
1261  * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
1262  *              device. This is a _REG method that has no corresponding region
1263  *              within the EC device scope. The orphan _REG method appears to
1264  *              have been enabled by the description of the ECDT in the ACPI
1265  *              specification: "The availability of the region space can be
1266  *              detected by providing a _REG method object underneath the
1267  *              Embedded Controller device."
1268  *
1269  *              To quickly access the EC device, we use the EC_ID that appears
1270  *              within the ECDT. Otherwise, we would need to perform a time-
1271  *              consuming namespace walk, executing _HID methods to find the
1272  *              EC device.
1273  *
1274  ******************************************************************************/
1275 
1276 static void
1277 AcpiEvOrphanEcRegMethod (
1278     void)
1279 {
1280     ACPI_TABLE_ECDT         *Table;
1281     ACPI_STATUS             Status;
1282     ACPI_OBJECT_LIST        Args;
1283     ACPI_OBJECT             Objects[2];
1284     ACPI_NAMESPACE_NODE     *EcDeviceNode;
1285     ACPI_NAMESPACE_NODE     *RegMethod;
1286     ACPI_NAMESPACE_NODE     *NextNode;
1287 
1288 
1289     ACPI_FUNCTION_TRACE (EvOrphanEcRegMethod);
1290 
1291 
1292     /* Get the ECDT (if present in system) */
1293 
1294     Status = AcpiGetTable (ACPI_SIG_ECDT, 0,
1295         ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Table));
1296     if (ACPI_FAILURE (Status))
1297     {
1298         return_VOID;
1299     }
1300 
1301     /* We need a valid EC_ID string */
1302 
1303     if (!(*Table->Id))
1304     {
1305         return_VOID;
1306     }
1307 
1308     /* Namespace is currently locked, must release */
1309 
1310     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
1311 
1312     /* Get a handle to the EC device referenced in the ECDT */
1313 
1314     Status = AcpiGetHandle (NULL,
1315         ACPI_CAST_PTR (char, Table->Id),
1316         ACPI_CAST_PTR (ACPI_HANDLE, &EcDeviceNode));
1317     if (ACPI_FAILURE (Status))
1318     {
1319         goto Exit;
1320     }
1321 
1322     /* Get a handle to a _REG method immediately under the EC device */
1323 
1324     Status = AcpiGetHandle (EcDeviceNode,
1325         METHOD_NAME__REG, ACPI_CAST_PTR (ACPI_HANDLE, &RegMethod));
1326     if (ACPI_FAILURE (Status))
1327     {
1328         goto Exit;
1329     }
1330 
1331     /*
1332      * Execute the _REG method only if there is no Operation Region in
1333      * this scope with the Embedded Controller space ID. Otherwise, it
1334      * will already have been executed. Note, this allows for Regions
1335      * with other space IDs to be present; but the code below will then
1336      * execute the _REG method with the EC space ID argument.
1337      */
1338     NextNode = AcpiNsGetNextNode (EcDeviceNode, NULL);
1339     while (NextNode)
1340     {
1341         if ((NextNode->Type == ACPI_TYPE_REGION) &&
1342             (NextNode->Object) &&
1343             (NextNode->Object->Region.SpaceId == ACPI_ADR_SPACE_EC))
1344         {
1345             goto Exit; /* Do not execute _REG */
1346         }
1347         NextNode = AcpiNsGetNextNode (EcDeviceNode, NextNode);
1348     }
1349 
1350     /* Evaluate the _REG(EC,Connect) method */
1351 
1352     Args.Count = 2;
1353     Args.Pointer = Objects;
1354     Objects[0].Type = ACPI_TYPE_INTEGER;
1355     Objects[0].Integer.Value = ACPI_ADR_SPACE_EC;
1356     Objects[1].Type = ACPI_TYPE_INTEGER;
1357     Objects[1].Integer.Value = ACPI_REG_CONNECT;
1358 
1359     Status = AcpiEvaluateObject (RegMethod, NULL, &Args, NULL);
1360 
1361 Exit:
1362     /* We ignore all errors from above, don't care */
1363 
1364     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
1365     return_VOID;
1366 }
1367