]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
1da177e4 LT |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: nsinit - namespace initialization | |
5 | * | |
800ba7c5 | 6 | * Copyright (C) 2000 - 2020, Intel Corp. |
1da177e4 | 7 | * |
95857638 | 8 | *****************************************************************************/ |
1da177e4 | 9 | |
1da177e4 | 10 | #include <acpi/acpi.h> |
e2f7a777 LB |
11 | #include "accommon.h" |
12 | #include "acnamesp.h" | |
13 | #include "acdispat.h" | |
14 | #include "acinterp.h" | |
ced04366 | 15 | #include "acevents.h" |
1da177e4 LT |
16 | |
17 | #define _COMPONENT ACPI_NAMESPACE | |
4be44fcd | 18 | ACPI_MODULE_NAME("nsinit") |
1da177e4 | 19 | |
44f6c012 | 20 | /* Local prototypes */ |
44f6c012 | 21 | static acpi_status |
4be44fcd LB |
22 | acpi_ns_init_one_object(acpi_handle obj_handle, |
23 | u32 level, void *context, void **return_value); | |
44f6c012 RM |
24 | |
25 | static acpi_status | |
4be44fcd LB |
26 | acpi_ns_init_one_device(acpi_handle obj_handle, |
27 | u32 nesting_level, void *context, void **return_value); | |
1da177e4 | 28 | |
b229cf92 BM |
29 | static acpi_status |
30 | acpi_ns_find_ini_methods(acpi_handle obj_handle, | |
31 | u32 nesting_level, void *context, void **return_value); | |
32 | ||
1da177e4 LT |
33 | /******************************************************************************* |
34 | * | |
35 | * FUNCTION: acpi_ns_initialize_objects | |
36 | * | |
37 | * PARAMETERS: None | |
38 | * | |
39 | * RETURN: Status | |
40 | * | |
41 | * DESCRIPTION: Walk the entire namespace and perform any necessary | |
42 | * initialization on the objects found therein | |
43 | * | |
44 | ******************************************************************************/ | |
45 | ||
4be44fcd | 46 | acpi_status acpi_ns_initialize_objects(void) |
1da177e4 | 47 | { |
4be44fcd LB |
48 | acpi_status status; |
49 | struct acpi_init_walk_info info; | |
1da177e4 | 50 | |
b229cf92 | 51 | ACPI_FUNCTION_TRACE(ns_initialize_objects); |
1da177e4 | 52 | |
5508df89 LZ |
53 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
54 | "[Init] Completing Initialization of ACPI Objects\n")); | |
4be44fcd LB |
55 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
56 | "**** Starting initialization of namespace objects ****\n")); | |
57 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | |
86a33cf3 | 58 | "Final data object initialization: ")); |
1da177e4 | 59 | |
86a33cf3 | 60 | /* Clear the info block */ |
1da177e4 | 61 | |
4fa4616e | 62 | memset(&info, 0, sizeof(struct acpi_init_walk_info)); |
1da177e4 LT |
63 | |
64 | /* Walk entire namespace from the supplied root */ | |
65 | ||
86a33cf3 BM |
66 | /* |
67 | * TBD: will become ACPI_TYPE_PACKAGE as this type object | |
68 | * is now the only one that supports deferred initialization | |
69 | * (forward references). | |
70 | */ | |
4be44fcd | 71 | status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
1f86e8c1 LZ |
72 | ACPI_UINT32_MAX, acpi_ns_init_one_object, |
73 | NULL, &info, NULL); | |
4be44fcd | 74 | if (ACPI_FAILURE(status)) { |
b229cf92 | 75 | ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
1da177e4 LT |
76 | } |
77 | ||
4be44fcd | 78 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
86a33cf3 BM |
79 | "Namespace contains %u (0x%X) objects\n", |
80 | info.object_count, info.object_count)); | |
1da177e4 | 81 | |
4be44fcd | 82 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
22b5afce BM |
83 | "%u Control Methods found\n%u Op Regions found\n", |
84 | info.method_count, info.op_region_count)); | |
1da177e4 | 85 | |
4be44fcd | 86 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
87 | } |
88 | ||
1da177e4 LT |
89 | /******************************************************************************* |
90 | * | |
91 | * FUNCTION: acpi_ns_initialize_devices | |
92 | * | |
93 | * PARAMETERS: None | |
94 | * | |
95 | * RETURN: acpi_status | |
96 | * | |
97 | * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. | |
98 | * This means running _INI on all present devices. | |
99 | * | |
100 | * Note: We install PCI config space handler on region access, | |
101 | * not here. | |
102 | * | |
103 | ******************************************************************************/ | |
104 | ||
ced04366 | 105 | acpi_status acpi_ns_initialize_devices(u32 flags) |
1da177e4 | 106 | { |
ebc3c9bb | 107 | acpi_status status = AE_OK; |
4be44fcd | 108 | struct acpi_device_walk_info info; |
2d3349de | 109 | acpi_handle handle; |
1da177e4 | 110 | |
b229cf92 | 111 | ACPI_FUNCTION_TRACE(ns_initialize_devices); |
1da177e4 | 112 | |
ced04366 LZ |
113 | if (!(flags & ACPI_NO_DEVICE_INIT)) { |
114 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | |
115 | "[Init] Initializing ACPI Devices\n")); | |
116 | ||
117 | /* Init counters */ | |
118 | ||
119 | info.device_count = 0; | |
120 | info.num_STA = 0; | |
121 | info.num_INI = 0; | |
122 | ||
123 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | |
124 | "Initializing Device/Processor/Thermal objects " | |
125 | "and executing _INI/_STA methods:\n")); | |
126 | ||
127 | /* Tree analysis: find all subtrees that contain _INI methods */ | |
128 | ||
129 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, | |
130 | ACPI_UINT32_MAX, FALSE, | |
131 | acpi_ns_find_ini_methods, NULL, | |
132 | &info, NULL); | |
133 | if (ACPI_FAILURE(status)) { | |
134 | goto error_exit; | |
135 | } | |
136 | ||
137 | /* Allocate the evaluation information block */ | |
138 | ||
139 | info.evaluate_info = | |
140 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); | |
141 | if (!info.evaluate_info) { | |
142 | status = AE_NO_MEMORY; | |
143 | goto error_exit; | |
144 | } | |
145 | ||
146 | /* | |
147 | * Execute the "global" _INI method that may appear at the root. | |
148 | * This support is provided for Windows compatibility (Vista+) and | |
149 | * is not part of the ACPI specification. | |
150 | */ | |
151 | info.evaluate_info->prefix_node = acpi_gbl_root_node; | |
152 | info.evaluate_info->relative_pathname = METHOD_NAME__INI; | |
153 | info.evaluate_info->parameters = NULL; | |
154 | info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE; | |
155 | ||
156 | status = acpi_ns_evaluate(info.evaluate_info); | |
157 | if (ACPI_SUCCESS(status)) { | |
158 | info.num_INI++; | |
159 | } | |
2d3349de LZ |
160 | |
161 | /* | |
162 | * Execute \_SB._INI. | |
163 | * There appears to be a strict order requirement for \_SB._INI, | |
164 | * which should be evaluated before any _REG evaluations. | |
165 | */ | |
166 | status = acpi_get_handle(NULL, "\\_SB", &handle); | |
167 | if (ACPI_SUCCESS(status)) { | |
168 | memset(info.evaluate_info, 0, | |
169 | sizeof(struct acpi_evaluate_info)); | |
170 | info.evaluate_info->prefix_node = handle; | |
171 | info.evaluate_info->relative_pathname = | |
172 | METHOD_NAME__INI; | |
173 | info.evaluate_info->parameters = NULL; | |
174 | info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE; | |
175 | ||
176 | status = acpi_ns_evaluate(info.evaluate_info); | |
177 | if (ACPI_SUCCESS(status)) { | |
178 | info.num_INI++; | |
179 | } | |
180 | } | |
1da177e4 LT |
181 | } |
182 | ||
9e64155e | 183 | /* |
ced04366 LZ |
184 | * Run all _REG methods |
185 | * | |
186 | * Note: Any objects accessed by the _REG methods will be automatically | |
187 | * initialized, even if they contain executable AML (see the call to | |
188 | * acpi_ns_initialize_objects below). | |
2d3349de LZ |
189 | * |
190 | * Note: According to the ACPI specification, we actually needn't execute | |
191 | * _REG for system_memory/system_io operation regions, but for PCI_Config | |
192 | * operation regions, it is required to evaluate _REG for those on a PCI | |
193 | * root bus that doesn't contain _BBN object. So this code is kept here | |
194 | * in order not to break things. | |
9e64155e | 195 | */ |
ced04366 LZ |
196 | if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { |
197 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | |
198 | "[Init] Executing _REG OpRegion methods\n")); | |
199 | ||
200 | status = acpi_ev_initialize_op_regions(); | |
201 | if (ACPI_FAILURE(status)) { | |
202 | goto error_exit; | |
203 | } | |
9e64155e BM |
204 | } |
205 | ||
ced04366 LZ |
206 | if (!(flags & ACPI_NO_DEVICE_INIT)) { |
207 | ||
208 | /* Walk namespace to execute all _INIs on present devices */ | |
209 | ||
210 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, | |
211 | ACPI_UINT32_MAX, FALSE, | |
212 | acpi_ns_init_one_device, NULL, | |
213 | &info, NULL); | |
214 | ||
215 | /* | |
216 | * Any _OSI requests should be completed by now. If the BIOS has | |
217 | * requested any Windows OSI strings, we will always truncate | |
218 | * I/O addresses to 16 bits -- for Windows compatibility. | |
219 | */ | |
220 | if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) { | |
221 | acpi_gbl_truncate_io_addresses = TRUE; | |
222 | } | |
223 | ||
224 | ACPI_FREE(info.evaluate_info); | |
225 | if (ACPI_FAILURE(status)) { | |
226 | goto error_exit; | |
227 | } | |
228 | ||
229 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | |
230 | " Executed %u _INI methods requiring %u _STA executions " | |
231 | "(examined %u objects)\n", | |
232 | info.num_INI, info.num_STA, | |
233 | info.device_count)); | |
b681f7d9 MG |
234 | } |
235 | ||
4be44fcd | 236 | return_ACPI_STATUS(status); |
4119532c | 237 | |
10622bf8 | 238 | error_exit: |
4119532c BM |
239 | ACPI_EXCEPTION((AE_INFO, status, "During device initialization")); |
240 | return_ACPI_STATUS(status); | |
1da177e4 LT |
241 | } |
242 | ||
7b34c0fb BM |
243 | /******************************************************************************* |
244 | * | |
245 | * FUNCTION: acpi_ns_init_one_package | |
246 | * | |
247 | * PARAMETERS: obj_handle - Node | |
248 | * level - Current nesting level | |
249 | * context - Not used | |
250 | * return_value - Not used | |
251 | * | |
252 | * RETURN: Status | |
253 | * | |
254 | * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every package | |
255 | * within the namespace. Used during dynamic load of an SSDT. | |
256 | * | |
257 | ******************************************************************************/ | |
258 | ||
259 | acpi_status | |
260 | acpi_ns_init_one_package(acpi_handle obj_handle, | |
261 | u32 level, void *context, void **return_value) | |
262 | { | |
263 | acpi_status status; | |
264 | union acpi_operand_object *obj_desc; | |
265 | struct acpi_namespace_node *node = | |
266 | (struct acpi_namespace_node *)obj_handle; | |
267 | ||
268 | obj_desc = acpi_ns_get_attached_object(node); | |
269 | if (!obj_desc) { | |
270 | return (AE_OK); | |
271 | } | |
272 | ||
273 | /* Exit if package is already initialized */ | |
274 | ||
275 | if (obj_desc->package.flags & AOPOBJ_DATA_VALID) { | |
276 | return (AE_OK); | |
277 | } | |
278 | ||
279 | status = acpi_ds_get_package_arguments(obj_desc); | |
280 | if (ACPI_FAILURE(status)) { | |
281 | return (AE_OK); | |
282 | } | |
283 | ||
284 | status = | |
285 | acpi_ut_walk_package_tree(obj_desc, NULL, | |
286 | acpi_ds_init_package_element, NULL); | |
287 | if (ACPI_FAILURE(status)) { | |
288 | return (AE_OK); | |
289 | } | |
290 | ||
291 | obj_desc->package.flags |= AOPOBJ_DATA_VALID; | |
292 | return (AE_OK); | |
293 | } | |
294 | ||
1da177e4 LT |
295 | /******************************************************************************* |
296 | * | |
297 | * FUNCTION: acpi_ns_init_one_object | |
298 | * | |
299 | * PARAMETERS: obj_handle - Node | |
ba494bee BM |
300 | * level - Current nesting level |
301 | * context - Points to a init info struct | |
1da177e4 LT |
302 | * return_value - Not used |
303 | * | |
304 | * RETURN: Status | |
305 | * | |
306 | * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object | |
1ef63231 | 307 | * within the namespace. |
1da177e4 LT |
308 | * |
309 | * Currently, the only objects that require initialization are: | |
310 | * 1) Methods | |
311 | * 2) Op Regions | |
312 | * | |
313 | ******************************************************************************/ | |
314 | ||
44f6c012 | 315 | static acpi_status |
4be44fcd LB |
316 | acpi_ns_init_one_object(acpi_handle obj_handle, |
317 | u32 level, void *context, void **return_value) | |
1da177e4 | 318 | { |
4be44fcd | 319 | acpi_object_type type; |
4d2acd9e | 320 | acpi_status status = AE_OK; |
4be44fcd LB |
321 | struct acpi_init_walk_info *info = |
322 | (struct acpi_init_walk_info *)context; | |
323 | struct acpi_namespace_node *node = | |
324 | (struct acpi_namespace_node *)obj_handle; | |
325 | union acpi_operand_object *obj_desc; | |
1da177e4 | 326 | |
b229cf92 | 327 | ACPI_FUNCTION_NAME(ns_init_one_object); |
1da177e4 LT |
328 | |
329 | info->object_count++; | |
330 | ||
331 | /* And even then, we are only interested in a few object types */ | |
332 | ||
4be44fcd LB |
333 | type = acpi_ns_get_type(obj_handle); |
334 | obj_desc = acpi_ns_get_attached_object(node); | |
1da177e4 LT |
335 | if (!obj_desc) { |
336 | return (AE_OK); | |
337 | } | |
338 | ||
339 | /* Increment counters for object types we are looking for */ | |
340 | ||
341 | switch (type) { | |
342 | case ACPI_TYPE_REGION: | |
1d1ea1b7 | 343 | |
1da177e4 LT |
344 | info->op_region_count++; |
345 | break; | |
346 | ||
347 | case ACPI_TYPE_BUFFER_FIELD: | |
1d1ea1b7 | 348 | |
1da177e4 LT |
349 | info->field_count++; |
350 | break; | |
351 | ||
ef805d95 | 352 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
1d1ea1b7 | 353 | |
ef805d95 LM |
354 | info->field_count++; |
355 | break; | |
356 | ||
1da177e4 | 357 | case ACPI_TYPE_BUFFER: |
1d1ea1b7 | 358 | |
1da177e4 LT |
359 | info->buffer_count++; |
360 | break; | |
361 | ||
362 | case ACPI_TYPE_PACKAGE: | |
1d1ea1b7 | 363 | |
1da177e4 LT |
364 | info->package_count++; |
365 | break; | |
366 | ||
367 | default: | |
368 | ||
369 | /* No init required, just exit now */ | |
1d1ea1b7 | 370 | |
1da177e4 LT |
371 | return (AE_OK); |
372 | } | |
373 | ||
d4913dc6 BM |
374 | /* If the object is already initialized, nothing else to do */ |
375 | ||
1da177e4 LT |
376 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
377 | return (AE_OK); | |
378 | } | |
379 | ||
d4913dc6 BM |
380 | /* Must lock the interpreter before executing AML code */ |
381 | ||
4d2acd9e | 382 | acpi_ex_enter_interpreter(); |
1da177e4 LT |
383 | |
384 | /* | |
86a33cf3 BM |
385 | * Only initialization of Package objects can be deferred, in order |
386 | * to support forward references. | |
1da177e4 LT |
387 | */ |
388 | switch (type) { | |
ef805d95 LM |
389 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
390 | ||
86a33cf3 BM |
391 | /* TBD: bank_fields do not require deferred init, remove this code */ |
392 | ||
ef805d95 LM |
393 | info->field_init++; |
394 | status = acpi_ds_get_bank_field_arguments(obj_desc); | |
395 | break; | |
396 | ||
1da177e4 LT |
397 | case ACPI_TYPE_PACKAGE: |
398 | ||
7b34c0fb | 399 | /* Complete the initialization/resolution of the package object */ |
a62a7117 | 400 | |
7b34c0fb BM |
401 | info->package_init++; |
402 | status = | |
403 | acpi_ns_init_one_package(obj_handle, level, NULL, NULL); | |
1da177e4 LT |
404 | break; |
405 | ||
406 | default: | |
1d1ea1b7 | 407 | |
86a33cf3 | 408 | /* No other types should get here */ |
1d1ea1b7 | 409 | |
86a33cf3 BM |
410 | status = AE_TYPE; |
411 | ACPI_EXCEPTION((AE_INFO, status, | |
412 | "Opcode is not deferred [%4.4s] (%s)", | |
413 | acpi_ut_get_node_name(node), | |
414 | acpi_ut_get_type_name(type))); | |
1da177e4 LT |
415 | break; |
416 | } | |
417 | ||
4be44fcd | 418 | if (ACPI_FAILURE(status)) { |
b8e4d893 BM |
419 | ACPI_EXCEPTION((AE_INFO, status, |
420 | "Could not execute arguments for [%4.4s] (%s)", | |
421 | acpi_ut_get_node_name(node), | |
422 | acpi_ut_get_type_name(type))); | |
1da177e4 LT |
423 | } |
424 | ||
1da177e4 LT |
425 | /* |
426 | * We ignore errors from above, and always return OK, since we don't want | |
427 | * to abort the walk on any single error. | |
428 | */ | |
4be44fcd | 429 | acpi_ex_exit_interpreter(); |
1da177e4 LT |
430 | return (AE_OK); |
431 | } | |
432 | ||
b229cf92 BM |
433 | /******************************************************************************* |
434 | * | |
435 | * FUNCTION: acpi_ns_find_ini_methods | |
436 | * | |
437 | * PARAMETERS: acpi_walk_callback | |
438 | * | |
439 | * RETURN: acpi_status | |
440 | * | |
441 | * DESCRIPTION: Called during namespace walk. Finds objects named _INI under | |
442 | * device/processor/thermal objects, and marks the entire subtree | |
443 | * with a SUBTREE_HAS_INI flag. This flag is used during the | |
444 | * subsequent device initialization walk to avoid entire subtrees | |
445 | * that do not contain an _INI. | |
446 | * | |
447 | ******************************************************************************/ | |
448 | ||
449 | static acpi_status | |
450 | acpi_ns_find_ini_methods(acpi_handle obj_handle, | |
451 | u32 nesting_level, void *context, void **return_value) | |
452 | { | |
453 | struct acpi_device_walk_info *info = | |
454 | ACPI_CAST_PTR(struct acpi_device_walk_info, context); | |
455 | struct acpi_namespace_node *node; | |
456 | struct acpi_namespace_node *parent_node; | |
457 | ||
458 | /* Keep count of device/processor/thermal objects */ | |
459 | ||
460 | node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); | |
461 | if ((node->type == ACPI_TYPE_DEVICE) || | |
462 | (node->type == ACPI_TYPE_PROCESSOR) || | |
463 | (node->type == ACPI_TYPE_THERMAL)) { | |
464 | info->device_count++; | |
465 | return (AE_OK); | |
466 | } | |
467 | ||
468 | /* We are only looking for methods named _INI */ | |
469 | ||
5599fb69 | 470 | if (!ACPI_COMPARE_NAMESEG(node->name.ascii, METHOD_NAME__INI)) { |
b229cf92 BM |
471 | return (AE_OK); |
472 | } | |
473 | ||
474 | /* | |
475 | * The only _INI methods that we care about are those that are | |
476 | * present under Device, Processor, and Thermal objects. | |
477 | */ | |
c45b5c09 | 478 | parent_node = node->parent; |
b229cf92 BM |
479 | switch (parent_node->type) { |
480 | case ACPI_TYPE_DEVICE: | |
481 | case ACPI_TYPE_PROCESSOR: | |
482 | case ACPI_TYPE_THERMAL: | |
483 | ||
484 | /* Mark parent and bubble up the INI present flag to the root */ | |
485 | ||
486 | while (parent_node) { | |
487 | parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; | |
c45b5c09 | 488 | parent_node = parent_node->parent; |
b229cf92 BM |
489 | } |
490 | break; | |
491 | ||
492 | default: | |
1d1ea1b7 | 493 | |
b229cf92 BM |
494 | break; |
495 | } | |
496 | ||
497 | return (AE_OK); | |
498 | } | |
499 | ||
1da177e4 LT |
500 | /******************************************************************************* |
501 | * | |
502 | * FUNCTION: acpi_ns_init_one_device | |
503 | * | |
504 | * PARAMETERS: acpi_walk_callback | |
505 | * | |
506 | * RETURN: acpi_status | |
507 | * | |
508 | * DESCRIPTION: This is called once per device soon after ACPI is enabled | |
509 | * to initialize each device. It determines if the device is | |
510 | * present, and if so, calls _INI. | |
511 | * | |
512 | ******************************************************************************/ | |
513 | ||
44f6c012 | 514 | static acpi_status |
4be44fcd LB |
515 | acpi_ns_init_one_device(acpi_handle obj_handle, |
516 | u32 nesting_level, void *context, void **return_value) | |
1da177e4 | 517 | { |
4119532c | 518 | struct acpi_device_walk_info *walk_info = |
b229cf92 | 519 | ACPI_CAST_PTR(struct acpi_device_walk_info, context); |
4119532c | 520 | struct acpi_evaluate_info *info = walk_info->evaluate_info; |
4be44fcd LB |
521 | u32 flags; |
522 | acpi_status status; | |
defba1d8 | 523 | struct acpi_namespace_node *device_node; |
1da177e4 | 524 | |
b229cf92 | 525 | ACPI_FUNCTION_TRACE(ns_init_one_device); |
1da177e4 | 526 | |
b229cf92 | 527 | /* We are interested in Devices, Processors and thermal_zones only */ |
1da177e4 | 528 | |
b229cf92 | 529 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
defba1d8 BM |
530 | if ((device_node->type != ACPI_TYPE_DEVICE) && |
531 | (device_node->type != ACPI_TYPE_PROCESSOR) && | |
532 | (device_node->type != ACPI_TYPE_THERMAL)) { | |
4be44fcd | 533 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
534 | } |
535 | ||
1da177e4 | 536 | /* |
b229cf92 BM |
537 | * Because of an earlier namespace analysis, all subtrees that contain an |
538 | * _INI method are tagged. | |
539 | * | |
540 | * If this device subtree does not contain any _INI methods, we | |
541 | * can exit now and stop traversing this entire subtree. | |
defba1d8 | 542 | */ |
b229cf92 BM |
543 | if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) { |
544 | return_ACPI_STATUS(AE_CTRL_DEPTH); | |
defba1d8 BM |
545 | } |
546 | ||
547 | /* | |
b229cf92 BM |
548 | * Run _STA to determine if this device is present and functioning. We |
549 | * must know this information for two important reasons (from ACPI spec): | |
550 | * | |
551 | * 1) We can only run _INI if the device is present. | |
552 | * 2) We must abort the device tree walk on this subtree if the device is | |
553 | * not present and is not functional (we will not examine the children) | |
554 | * | |
555 | * The _STA method is not required to be present under the device, we | |
556 | * assume the device is present if _STA does not exist. | |
1da177e4 | 557 | */ |
b229cf92 BM |
558 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
559 | (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA)); | |
1da177e4 | 560 | |
b229cf92 | 561 | status = acpi_ut_execute_STA(device_node, &flags); |
4be44fcd | 562 | if (ACPI_FAILURE(status)) { |
52fc0b02 | 563 | |
defba1d8 | 564 | /* Ignore error and move on to next device */ |
1da177e4 | 565 | |
defba1d8 BM |
566 | return_ACPI_STATUS(AE_OK); |
567 | } | |
1da177e4 | 568 | |
b229cf92 BM |
569 | /* |
570 | * Flags == -1 means that _STA was not found. In this case, we assume that | |
571 | * the device is both present and functional. | |
572 | * | |
573 | * From the ACPI spec, description of _STA: | |
574 | * | |
575 | * "If a device object (including the processor object) does not have an | |
576 | * _STA object, then OSPM assumes that all of the above bits are set (in | |
577 | * other words, the device is present, ..., and functioning)" | |
578 | */ | |
defba1d8 | 579 | if (flags != ACPI_UINT32_MAX) { |
4119532c | 580 | walk_info->num_STA++; |
defba1d8 | 581 | } |
1da177e4 | 582 | |
b229cf92 BM |
583 | /* |
584 | * Examine the PRESENT and FUNCTIONING status bits | |
585 | * | |
586 | * Note: ACPI spec does not seem to specify behavior for the present but | |
587 | * not functioning case, so we assume functioning if present. | |
588 | */ | |
defba1d8 | 589 | if (!(flags & ACPI_STA_DEVICE_PRESENT)) { |
52fc0b02 | 590 | |
b229cf92 BM |
591 | /* Device is not present, we must examine the Functioning bit */ |
592 | ||
593 | if (flags & ACPI_STA_DEVICE_FUNCTIONING) { | |
594 | /* | |
595 | * Device is not present but is "functioning". In this case, | |
596 | * we will not run _INI, but we continue to examine the children | |
597 | * of this device. | |
598 | * | |
ba494bee | 599 | * From the ACPI spec, description of _STA: (note - no mention |
b229cf92 BM |
600 | * of whether to run _INI or not on the device in question) |
601 | * | |
602 | * "_STA may return bit 0 clear (not present) with bit 3 set | |
603 | * (device is functional). This case is used to indicate a valid | |
604 | * device for which no device driver should be loaded (for example, | |
605 | * a bridge device.) Children of this device may be present and | |
606 | * valid. OSPM should continue enumeration below a device whose | |
607 | * _STA returns this bit combination" | |
608 | */ | |
609 | return_ACPI_STATUS(AE_OK); | |
610 | } else { | |
611 | /* | |
612 | * Device is not present and is not functioning. We must abort the | |
613 | * walk of this subtree immediately -- don't look at the children | |
614 | * of such a device. | |
615 | * | |
616 | * From the ACPI spec, description of _INI: | |
617 | * | |
618 | * "If the _STA method indicates that the device is not present, | |
619 | * OSPM will not run the _INI and will not examine the children | |
620 | * of the device for _INI methods" | |
621 | */ | |
622 | return_ACPI_STATUS(AE_CTRL_DEPTH); | |
623 | } | |
1da177e4 LT |
624 | } |
625 | ||
626 | /* | |
b229cf92 BM |
627 | * The device is present or is assumed present if no _STA exists. |
628 | * Run the _INI if it exists (not required to exist) | |
629 | * | |
630 | * Note: We know there is an _INI within this subtree, but it may not be | |
631 | * under this particular device, it may be lower in the branch. | |
1da177e4 | 632 | */ |
5599fb69 | 633 | if (!ACPI_COMPARE_NAMESEG(device_node->name.ascii, "_SB_") || |
2d3349de LZ |
634 | device_node->parent != acpi_gbl_root_node) { |
635 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname | |
636 | (ACPI_TYPE_METHOD, device_node, | |
637 | METHOD_NAME__INI)); | |
638 | ||
639 | memset(info, 0, sizeof(struct acpi_evaluate_info)); | |
640 | info->prefix_node = device_node; | |
641 | info->relative_pathname = METHOD_NAME__INI; | |
642 | info->parameters = NULL; | |
643 | info->flags = ACPI_IGNORE_RETURN_VALUE; | |
644 | ||
645 | status = acpi_ns_evaluate(info); | |
646 | if (ACPI_SUCCESS(status)) { | |
647 | walk_info->num_INI++; | |
648 | } | |
b229cf92 | 649 | #ifdef ACPI_DEBUG_OUTPUT |
2d3349de | 650 | else if (status != AE_NOT_FOUND) { |
1da177e4 | 651 | |
2d3349de | 652 | /* Ignore error and move on to next device */ |
b229cf92 | 653 | |
2d3349de LZ |
654 | char *scope_name = |
655 | acpi_ns_get_normalized_pathname(device_node, TRUE); | |
52fc0b02 | 656 | |
2d3349de LZ |
657 | ACPI_EXCEPTION((AE_INFO, status, |
658 | "during %s._INI execution", | |
659 | scope_name)); | |
660 | ACPI_FREE(scope_name); | |
661 | } | |
b229cf92 | 662 | #endif |
2d3349de | 663 | } |
1da177e4 | 664 | |
4c90ece2 BM |
665 | /* Ignore errors from above */ |
666 | ||
667 | status = AE_OK; | |
668 | ||
4119532c BM |
669 | /* |
670 | * The _INI method has been run if present; call the Global Initialization | |
671 | * Handler for this device. | |
672 | */ | |
b229cf92 | 673 | if (acpi_gbl_init_handler) { |
4be44fcd | 674 | status = |
4119532c | 675 | acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI); |
1da177e4 LT |
676 | } |
677 | ||
4119532c | 678 | return_ACPI_STATUS(status); |
1da177e4 | 679 | } |