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