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