xref: /titanic_44/usr/src/uts/intel/io/acpica/namespace/nsinit.c (revision 5fd03bc0f2e00e7ba02316c2e08f45d52aab15db)
1 /******************************************************************************
2  *
3  * Module Name: nsinit - namespace initialization
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 __NSXFINIT_C__
46 
47 #include "acpi.h"
48 #include "accommon.h"
49 #include "acnamesp.h"
50 #include "acdispat.h"
51 #include "acinterp.h"
52 
53 #define _COMPONENT          ACPI_NAMESPACE
54         ACPI_MODULE_NAME    ("nsinit")
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 AcpiNsInitOneObject (
60     ACPI_HANDLE             ObjHandle,
61     UINT32                  Level,
62     void                    *Context,
63     void                    **ReturnValue);
64 
65 static ACPI_STATUS
66 AcpiNsInitOneDevice (
67     ACPI_HANDLE             ObjHandle,
68     UINT32                  NestingLevel,
69     void                    *Context,
70     void                    **ReturnValue);
71 
72 static ACPI_STATUS
73 AcpiNsFindIniMethods (
74     ACPI_HANDLE             ObjHandle,
75     UINT32                  NestingLevel,
76     void                    *Context,
77     void                    **ReturnValue);
78 
79 
80 /*******************************************************************************
81  *
82  * FUNCTION:    AcpiNsInitializeObjects
83  *
84  * PARAMETERS:  None
85  *
86  * RETURN:      Status
87  *
88  * DESCRIPTION: Walk the entire namespace and perform any necessary
89  *              initialization on the objects found therein
90  *
91  ******************************************************************************/
92 
93 ACPI_STATUS
94 AcpiNsInitializeObjects (
95     void)
96 {
97     ACPI_STATUS             Status;
98     ACPI_INIT_WALK_INFO     Info;
99 
100 
101     ACPI_FUNCTION_TRACE (NsInitializeObjects);
102 
103 
104     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
105         "**** Starting initialization of namespace objects ****\n"));
106     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
107         "Completing Region/Field/Buffer/Package initialization:"));
108 
109     /* Set all init info to zero */
110 
111     ACPI_MEMSET (&Info, 0, sizeof (ACPI_INIT_WALK_INFO));
112 
113     /* Walk entire namespace from the supplied root */
114 
115     Status = AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
116                 ACPI_UINT32_MAX, AcpiNsInitOneObject, NULL,
117                 &Info, NULL);
118     if (ACPI_FAILURE (Status))
119     {
120         ACPI_EXCEPTION ((AE_INFO, Status, "During WalkNamespace"));
121     }
122 
123     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
124         "\nInitialized %u/%u Regions %u/%u Fields %u/%u "
125         "Buffers %u/%u Packages (%u nodes)\n",
126         Info.OpRegionInit,  Info.OpRegionCount,
127         Info.FieldInit,     Info.FieldCount,
128         Info.BufferInit,    Info.BufferCount,
129         Info.PackageInit,   Info.PackageCount, Info.ObjectCount));
130 
131     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
132         "%u Control Methods found\n", Info.MethodCount));
133     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
134         "%u Op Regions found\n", Info.OpRegionCount));
135 
136     return_ACPI_STATUS (AE_OK);
137 }
138 
139 
140 /*******************************************************************************
141  *
142  * FUNCTION:    AcpiNsInitializeDevices
143  *
144  * PARAMETERS:  None
145  *
146  * RETURN:      ACPI_STATUS
147  *
148  * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices.
149  *              This means running _INI on all present devices.
150  *
151  *              Note: We install PCI config space handler on region access,
152  *              not here.
153  *
154  ******************************************************************************/
155 
156 ACPI_STATUS
157 AcpiNsInitializeDevices (
158     void)
159 {
160     ACPI_STATUS             Status;
161     ACPI_DEVICE_WALK_INFO   Info;
162 
163 
164     ACPI_FUNCTION_TRACE (NsInitializeDevices);
165 
166 
167     /* Init counters */
168 
169     Info.DeviceCount = 0;
170     Info.Num_STA = 0;
171     Info.Num_INI = 0;
172 
173     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
174         "Initializing Device/Processor/Thermal objects "
175         "by executing _INI methods:"));
176 
177     /* Tree analysis: find all subtrees that contain _INI methods */
178 
179     Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
180                 ACPI_UINT32_MAX, FALSE, AcpiNsFindIniMethods, NULL, &Info, NULL);
181     if (ACPI_FAILURE (Status))
182     {
183         goto ErrorExit;
184     }
185 
186     /* Allocate the evaluation information block */
187 
188     Info.EvaluateInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
189     if (!Info.EvaluateInfo)
190     {
191         Status = AE_NO_MEMORY;
192         goto ErrorExit;
193     }
194 
195     /*
196      * Execute the "global" _INI method that may appear at the root. This
197      * support is provided for Windows compatibility (Vista+) and is not
198      * part of the ACPI specification.
199      */
200     Info.EvaluateInfo->PrefixNode = AcpiGbl_RootNode;
201     Info.EvaluateInfo->Pathname = METHOD_NAME__INI;
202     Info.EvaluateInfo->Parameters = NULL;
203     Info.EvaluateInfo->Flags = ACPI_IGNORE_RETURN_VALUE;
204 
205     Status = AcpiNsEvaluate (Info.EvaluateInfo);
206     if (ACPI_SUCCESS (Status))
207     {
208         Info.Num_INI++;
209     }
210 
211     /* Walk namespace to execute all _INIs on present devices */
212 
213     Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
214                 ACPI_UINT32_MAX, FALSE, AcpiNsInitOneDevice, NULL, &Info, NULL);
215 
216     /*
217      * Any _OSI requests should be completed by now. If the BIOS has
218      * requested any Windows OSI strings, we will always truncate
219      * I/O addresses to 16 bits -- for Windows compatibility.
220      */
221     if (AcpiGbl_OsiData >= ACPI_OSI_WIN_2000)
222     {
223         AcpiGbl_TruncateIoAddresses = TRUE;
224     }
225 
226     ACPI_FREE (Info.EvaluateInfo);
227     if (ACPI_FAILURE (Status))
228     {
229         goto ErrorExit;
230     }
231 
232     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
233         "\nExecuted %u _INI methods requiring %u _STA executions "
234         "(examined %u objects)\n",
235         Info.Num_INI, Info.Num_STA, Info.DeviceCount));
236 
237     return_ACPI_STATUS (Status);
238 
239 
240 ErrorExit:
241     ACPI_EXCEPTION ((AE_INFO, Status, "During device initialization"));
242     return_ACPI_STATUS (Status);
243 }
244 
245 
246 /*******************************************************************************
247  *
248  * FUNCTION:    AcpiNsInitOneObject
249  *
250  * PARAMETERS:  ObjHandle       - Node
251  *              Level           - Current nesting level
252  *              Context         - Points to a init info struct
253  *              ReturnValue     - Not used
254  *
255  * RETURN:      Status
256  *
257  * DESCRIPTION: Callback from AcpiWalkNamespace.  Invoked for every object
258  *              within the  namespace.
259  *
260  *              Currently, the only objects that require initialization are:
261  *              1) Methods
262  *              2) Op Regions
263  *
264  ******************************************************************************/
265 
266 static ACPI_STATUS
267 AcpiNsInitOneObject (
268     ACPI_HANDLE             ObjHandle,
269     UINT32                  Level,
270     void                    *Context,
271     void                    **ReturnValue)
272 {
273     ACPI_OBJECT_TYPE        Type;
274     ACPI_STATUS             Status = AE_OK;
275     ACPI_INIT_WALK_INFO     *Info = (ACPI_INIT_WALK_INFO *) Context;
276     ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
277     ACPI_OPERAND_OBJECT     *ObjDesc;
278 
279 
280     ACPI_FUNCTION_NAME (NsInitOneObject);
281 
282 
283     Info->ObjectCount++;
284 
285     /* And even then, we are only interested in a few object types */
286 
287     Type = AcpiNsGetType (ObjHandle);
288     ObjDesc = AcpiNsGetAttachedObject (Node);
289     if (!ObjDesc)
290     {
291         return (AE_OK);
292     }
293 
294     /* Increment counters for object types we are looking for */
295 
296     switch (Type)
297     {
298     case ACPI_TYPE_REGION:
299         Info->OpRegionCount++;
300         break;
301 
302     case ACPI_TYPE_BUFFER_FIELD:
303         Info->FieldCount++;
304         break;
305 
306     case ACPI_TYPE_LOCAL_BANK_FIELD:
307         Info->FieldCount++;
308         break;
309 
310     case ACPI_TYPE_BUFFER:
311         Info->BufferCount++;
312         break;
313 
314     case ACPI_TYPE_PACKAGE:
315         Info->PackageCount++;
316         break;
317 
318     default:
319 
320         /* No init required, just exit now */
321         return (AE_OK);
322     }
323 
324     /* If the object is already initialized, nothing else to do */
325 
326     if (ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)
327     {
328         return (AE_OK);
329     }
330 
331     /* Must lock the interpreter before executing AML code */
332 
333     AcpiExEnterInterpreter ();
334 
335     /*
336      * Each of these types can contain executable AML code within the
337      * declaration.
338      */
339     switch (Type)
340     {
341     case ACPI_TYPE_REGION:
342 
343         Info->OpRegionInit++;
344         Status = AcpiDsGetRegionArguments (ObjDesc);
345         break;
346 
347     case ACPI_TYPE_BUFFER_FIELD:
348 
349         Info->FieldInit++;
350         Status = AcpiDsGetBufferFieldArguments (ObjDesc);
351         break;
352 
353     case ACPI_TYPE_LOCAL_BANK_FIELD:
354 
355         Info->FieldInit++;
356         Status = AcpiDsGetBankFieldArguments (ObjDesc);
357         break;
358 
359     case ACPI_TYPE_BUFFER:
360 
361         Info->BufferInit++;
362         Status = AcpiDsGetBufferArguments (ObjDesc);
363         break;
364 
365     case ACPI_TYPE_PACKAGE:
366 
367         Info->PackageInit++;
368         Status = AcpiDsGetPackageArguments (ObjDesc);
369         break;
370 
371     default:
372         /* No other types can get here */
373         break;
374     }
375 
376     if (ACPI_FAILURE (Status))
377     {
378         ACPI_EXCEPTION ((AE_INFO, Status,
379             "Could not execute arguments for [%4.4s] (%s)",
380             AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Type)));
381     }
382 
383     /*
384      * Print a dot for each object unless we are going to print the entire
385      * pathname
386      */
387     if (!(AcpiDbgLevel & ACPI_LV_INIT_NAMES))
388     {
389         ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
390     }
391 
392     /*
393      * We ignore errors from above, and always return OK, since we don't want
394      * to abort the walk on any single error.
395      */
396     AcpiExExitInterpreter ();
397     return (AE_OK);
398 }
399 
400 
401 /*******************************************************************************
402  *
403  * FUNCTION:    AcpiNsFindIniMethods
404  *
405  * PARAMETERS:  ACPI_WALK_CALLBACK
406  *
407  * RETURN:      ACPI_STATUS
408  *
409  * DESCRIPTION: Called during namespace walk. Finds objects named _INI under
410  *              device/processor/thermal objects, and marks the entire subtree
411  *              with a SUBTREE_HAS_INI flag. This flag is used during the
412  *              subsequent device initialization walk to avoid entire subtrees
413  *              that do not contain an _INI.
414  *
415  ******************************************************************************/
416 
417 static ACPI_STATUS
418 AcpiNsFindIniMethods (
419     ACPI_HANDLE             ObjHandle,
420     UINT32                  NestingLevel,
421     void                    *Context,
422     void                    **ReturnValue)
423 {
424     ACPI_DEVICE_WALK_INFO   *Info = ACPI_CAST_PTR (ACPI_DEVICE_WALK_INFO, Context);
425     ACPI_NAMESPACE_NODE     *Node;
426     ACPI_NAMESPACE_NODE     *ParentNode;
427 
428 
429     /* Keep count of device/processor/thermal objects */
430 
431     Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
432     if ((Node->Type == ACPI_TYPE_DEVICE)    ||
433         (Node->Type == ACPI_TYPE_PROCESSOR) ||
434         (Node->Type == ACPI_TYPE_THERMAL))
435     {
436         Info->DeviceCount++;
437         return (AE_OK);
438     }
439 
440     /* We are only looking for methods named _INI */
441 
442     if (!ACPI_COMPARE_NAME (Node->Name.Ascii, METHOD_NAME__INI))
443     {
444         return (AE_OK);
445     }
446 
447     /*
448      * The only _INI methods that we care about are those that are
449      * present under Device, Processor, and Thermal objects.
450      */
451     ParentNode = Node->Parent;
452     switch (ParentNode->Type)
453     {
454     case ACPI_TYPE_DEVICE:
455     case ACPI_TYPE_PROCESSOR:
456     case ACPI_TYPE_THERMAL:
457 
458         /* Mark parent and bubble up the INI present flag to the root */
459 
460         while (ParentNode)
461         {
462             ParentNode->Flags |= ANOBJ_SUBTREE_HAS_INI;
463             ParentNode = ParentNode->Parent;
464         }
465         break;
466 
467     default:
468         break;
469     }
470 
471     return (AE_OK);
472 }
473 
474 
475 /*******************************************************************************
476  *
477  * FUNCTION:    AcpiNsInitOneDevice
478  *
479  * PARAMETERS:  ACPI_WALK_CALLBACK
480  *
481  * RETURN:      ACPI_STATUS
482  *
483  * DESCRIPTION: This is called once per device soon after ACPI is enabled
484  *              to initialize each device. It determines if the device is
485  *              present, and if so, calls _INI.
486  *
487  ******************************************************************************/
488 
489 static ACPI_STATUS
490 AcpiNsInitOneDevice (
491     ACPI_HANDLE             ObjHandle,
492     UINT32                  NestingLevel,
493     void                    *Context,
494     void                    **ReturnValue)
495 {
496     ACPI_DEVICE_WALK_INFO   *WalkInfo = ACPI_CAST_PTR (ACPI_DEVICE_WALK_INFO, Context);
497     ACPI_EVALUATE_INFO      *Info = WalkInfo->EvaluateInfo;
498     UINT32                  Flags;
499     ACPI_STATUS             Status;
500     ACPI_NAMESPACE_NODE     *DeviceNode;
501 
502 
503     ACPI_FUNCTION_TRACE (NsInitOneDevice);
504 
505 
506     /* We are interested in Devices, Processors and ThermalZones only */
507 
508     DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
509     if ((DeviceNode->Type != ACPI_TYPE_DEVICE)    &&
510         (DeviceNode->Type != ACPI_TYPE_PROCESSOR) &&
511         (DeviceNode->Type != ACPI_TYPE_THERMAL))
512     {
513         return_ACPI_STATUS (AE_OK);
514     }
515 
516     /*
517      * Because of an earlier namespace analysis, all subtrees that contain an
518      * _INI method are tagged.
519      *
520      * If this device subtree does not contain any _INI methods, we
521      * can exit now and stop traversing this entire subtree.
522      */
523     if (!(DeviceNode->Flags & ANOBJ_SUBTREE_HAS_INI))
524     {
525         return_ACPI_STATUS (AE_CTRL_DEPTH);
526     }
527 
528     /*
529      * Run _STA to determine if this device is present and functioning. We
530      * must know this information for two important reasons (from ACPI spec):
531      *
532      * 1) We can only run _INI if the device is present.
533      * 2) We must abort the device tree walk on this subtree if the device is
534      *    not present and is not functional (we will not examine the children)
535      *
536      * The _STA method is not required to be present under the device, we
537      * assume the device is present if _STA does not exist.
538      */
539     ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname (
540         ACPI_TYPE_METHOD, DeviceNode, METHOD_NAME__STA));
541 
542     Status = AcpiUtExecute_STA (DeviceNode, &Flags);
543     if (ACPI_FAILURE (Status))
544     {
545         /* Ignore error and move on to next device */
546 
547         return_ACPI_STATUS (AE_OK);
548     }
549 
550     /*
551      * Flags == -1 means that _STA was not found. In this case, we assume that
552      * the device is both present and functional.
553      *
554      * From the ACPI spec, description of _STA:
555      *
556      * "If a device object (including the processor object) does not have an
557      * _STA object, then OSPM assumes that all of the above bits are set (in
558      * other words, the device is present, ..., and functioning)"
559      */
560     if (Flags != ACPI_UINT32_MAX)
561     {
562         WalkInfo->Num_STA++;
563     }
564 
565     /*
566      * Examine the PRESENT and FUNCTIONING status bits
567      *
568      * Note: ACPI spec does not seem to specify behavior for the present but
569      * not functioning case, so we assume functioning if present.
570      */
571     if (!(Flags & ACPI_STA_DEVICE_PRESENT))
572     {
573         /* Device is not present, we must examine the Functioning bit */
574 
575         if (Flags & ACPI_STA_DEVICE_FUNCTIONING)
576         {
577             /*
578              * Device is not present but is "functioning". In this case,
579              * we will not run _INI, but we continue to examine the children
580              * of this device.
581              *
582              * From the ACPI spec, description of _STA: (Note - no mention
583              * of whether to run _INI or not on the device in question)
584              *
585              * "_STA may return bit 0 clear (not present) with bit 3 set
586              * (device is functional). This case is used to indicate a valid
587              * device for which no device driver should be loaded (for example,
588              * a bridge device.) Children of this device may be present and
589              * valid. OSPM should continue enumeration below a device whose
590              * _STA returns this bit combination"
591              */
592             return_ACPI_STATUS (AE_OK);
593         }
594         else
595         {
596             /*
597              * Device is not present and is not functioning. We must abort the
598              * walk of this subtree immediately -- don't look at the children
599              * of such a device.
600              *
601              * From the ACPI spec, description of _INI:
602              *
603              * "If the _STA method indicates that the device is not present,
604              * OSPM will not run the _INI and will not examine the children
605              * of the device for _INI methods"
606              */
607             return_ACPI_STATUS (AE_CTRL_DEPTH);
608         }
609     }
610 
611     /*
612      * The device is present or is assumed present if no _STA exists.
613      * Run the _INI if it exists (not required to exist)
614      *
615      * Note: We know there is an _INI within this subtree, but it may not be
616      * under this particular device, it may be lower in the branch.
617      */
618     ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname (
619         ACPI_TYPE_METHOD, DeviceNode, METHOD_NAME__INI));
620 
621     Info->PrefixNode = DeviceNode;
622     Info->Pathname = METHOD_NAME__INI;
623     Info->Parameters = NULL;
624     Info->Flags = ACPI_IGNORE_RETURN_VALUE;
625 
626     Status = AcpiNsEvaluate (Info);
627     if (ACPI_SUCCESS (Status))
628     {
629         WalkInfo->Num_INI++;
630 
631         if ((AcpiDbgLevel <= ACPI_LV_ALL_EXCEPTIONS) &&
632             (!(AcpiDbgLevel & ACPI_LV_INFO)))
633         {
634             ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
635         }
636     }
637 
638 #ifdef ACPI_DEBUG_OUTPUT
639     else if (Status != AE_NOT_FOUND)
640     {
641         /* Ignore error and move on to next device */
642 
643         char *ScopeName = AcpiNsGetExternalPathname (Info->ResolvedNode);
644 
645         ACPI_EXCEPTION ((AE_INFO, Status, "during %s._INI execution",
646             ScopeName));
647         ACPI_FREE (ScopeName);
648     }
649 #endif
650 
651     /* Ignore errors from above */
652 
653     Status = AE_OK;
654 
655     /*
656      * The _INI method has been run if present; call the Global Initialization
657      * Handler for this device.
658      */
659     if (AcpiGbl_InitHandler)
660     {
661         Status = AcpiGbl_InitHandler (DeviceNode, ACPI_INIT_DEVICE_INI);
662     }
663 
664     return_ACPI_STATUS (Status);
665 }
666