diff options
Diffstat (limited to 'drivers/acpi/namespace/nsinit.c')
-rw-r--r-- | drivers/acpi/namespace/nsinit.c | 298 |
1 files changed, 215 insertions, 83 deletions
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 9f929e479fd8..aec8488c0019 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c | |||
@@ -58,6 +58,10 @@ static acpi_status | |||
58 | acpi_ns_init_one_device(acpi_handle obj_handle, | 58 | acpi_ns_init_one_device(acpi_handle obj_handle, |
59 | u32 nesting_level, void *context, void **return_value); | 59 | u32 nesting_level, void *context, void **return_value); |
60 | 60 | ||
61 | static acpi_status | ||
62 | acpi_ns_find_ini_methods(acpi_handle obj_handle, | ||
63 | u32 nesting_level, void *context, void **return_value); | ||
64 | |||
61 | /******************************************************************************* | 65 | /******************************************************************************* |
62 | * | 66 | * |
63 | * FUNCTION: acpi_ns_initialize_objects | 67 | * FUNCTION: acpi_ns_initialize_objects |
@@ -76,7 +80,7 @@ acpi_status acpi_ns_initialize_objects(void) | |||
76 | acpi_status status; | 80 | acpi_status status; |
77 | struct acpi_init_walk_info info; | 81 | struct acpi_init_walk_info info; |
78 | 82 | ||
79 | ACPI_FUNCTION_TRACE("ns_initialize_objects"); | 83 | ACPI_FUNCTION_TRACE(ns_initialize_objects); |
80 | 84 | ||
81 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 85 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
82 | "**** Starting initialization of namespace objects ****\n")); | 86 | "**** Starting initialization of namespace objects ****\n")); |
@@ -93,7 +97,7 @@ acpi_status acpi_ns_initialize_objects(void) | |||
93 | ACPI_UINT32_MAX, acpi_ns_init_one_object, | 97 | ACPI_UINT32_MAX, acpi_ns_init_one_object, |
94 | &info, NULL); | 98 | &info, NULL); |
95 | if (ACPI_FAILURE(status)) { | 99 | if (ACPI_FAILURE(status)) { |
96 | ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace")); | 100 | ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
97 | } | 101 | } |
98 | 102 | ||
99 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | 103 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
@@ -133,7 +137,7 @@ acpi_status acpi_ns_initialize_devices(void) | |||
133 | acpi_status status; | 137 | acpi_status status; |
134 | struct acpi_device_walk_info info; | 138 | struct acpi_device_walk_info info; |
135 | 139 | ||
136 | ACPI_FUNCTION_TRACE("ns_initialize_devices"); | 140 | ACPI_FUNCTION_TRACE(ns_initialize_devices); |
137 | 141 | ||
138 | /* Init counters */ | 142 | /* Init counters */ |
139 | 143 | ||
@@ -142,30 +146,46 @@ acpi_status acpi_ns_initialize_devices(void) | |||
142 | info.num_INI = 0; | 146 | info.num_INI = 0; |
143 | 147 | ||
144 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | 148 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
145 | "Executing all Device _STA and_INI methods:")); | 149 | "Initializing Device/Processor/Thermal objects by executing _INI methods:")); |
150 | |||
151 | /* Tree analysis: find all subtrees that contain _INI methods */ | ||
146 | 152 | ||
147 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | 153 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
154 | ACPI_UINT32_MAX, FALSE, | ||
155 | acpi_ns_find_ini_methods, &info, NULL); | ||
148 | if (ACPI_FAILURE(status)) { | 156 | if (ACPI_FAILURE(status)) { |
149 | return_ACPI_STATUS(status); | 157 | goto error_exit; |
150 | } | 158 | } |
151 | 159 | ||
152 | /* Walk namespace for all objects */ | 160 | /* Allocate the evaluation information block */ |
161 | |||
162 | info.evaluate_info = | ||
163 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); | ||
164 | if (!info.evaluate_info) { | ||
165 | status = AE_NO_MEMORY; | ||
166 | goto error_exit; | ||
167 | } | ||
168 | |||
169 | /* Walk namespace to execute all _INIs on present devices */ | ||
153 | 170 | ||
154 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, | 171 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
155 | ACPI_UINT32_MAX, TRUE, | 172 | ACPI_UINT32_MAX, FALSE, |
156 | acpi_ns_init_one_device, &info, NULL); | 173 | acpi_ns_init_one_device, &info, NULL); |
157 | 174 | ||
158 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 175 | ACPI_FREE(info.evaluate_info); |
159 | |||
160 | if (ACPI_FAILURE(status)) { | 176 | if (ACPI_FAILURE(status)) { |
161 | ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace")); | 177 | goto error_exit; |
162 | } | 178 | } |
163 | 179 | ||
164 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | 180 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
165 | "\n%hd Devices found - executed %hd _STA, %hd _INI methods\n", | 181 | "\nExecuted %hd _INI methods requiring %hd _STA executions (examined %hd objects)\n", |
166 | info.device_count, info.num_STA, info.num_INI)); | 182 | info.num_INI, info.num_STA, info.device_count)); |
167 | 183 | ||
168 | return_ACPI_STATUS(status); | 184 | return_ACPI_STATUS(status); |
185 | |||
186 | error_exit: | ||
187 | ACPI_EXCEPTION((AE_INFO, status, "During device initialization")); | ||
188 | return_ACPI_STATUS(status); | ||
169 | } | 189 | } |
170 | 190 | ||
171 | /******************************************************************************* | 191 | /******************************************************************************* |
@@ -200,7 +220,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, | |||
200 | (struct acpi_namespace_node *)obj_handle; | 220 | (struct acpi_namespace_node *)obj_handle; |
201 | union acpi_operand_object *obj_desc; | 221 | union acpi_operand_object *obj_desc; |
202 | 222 | ||
203 | ACPI_FUNCTION_NAME("ns_init_one_object"); | 223 | ACPI_FUNCTION_NAME(ns_init_one_object); |
204 | 224 | ||
205 | info->object_count++; | 225 | info->object_count++; |
206 | 226 | ||
@@ -311,6 +331,72 @@ acpi_ns_init_one_object(acpi_handle obj_handle, | |||
311 | 331 | ||
312 | /******************************************************************************* | 332 | /******************************************************************************* |
313 | * | 333 | * |
334 | * FUNCTION: acpi_ns_find_ini_methods | ||
335 | * | ||
336 | * PARAMETERS: acpi_walk_callback | ||
337 | * | ||
338 | * RETURN: acpi_status | ||
339 | * | ||
340 | * DESCRIPTION: Called during namespace walk. Finds objects named _INI under | ||
341 | * device/processor/thermal objects, and marks the entire subtree | ||
342 | * with a SUBTREE_HAS_INI flag. This flag is used during the | ||
343 | * subsequent device initialization walk to avoid entire subtrees | ||
344 | * that do not contain an _INI. | ||
345 | * | ||
346 | ******************************************************************************/ | ||
347 | |||
348 | static acpi_status | ||
349 | acpi_ns_find_ini_methods(acpi_handle obj_handle, | ||
350 | u32 nesting_level, void *context, void **return_value) | ||
351 | { | ||
352 | struct acpi_device_walk_info *info = | ||
353 | ACPI_CAST_PTR(struct acpi_device_walk_info, context); | ||
354 | struct acpi_namespace_node *node; | ||
355 | struct acpi_namespace_node *parent_node; | ||
356 | |||
357 | /* Keep count of device/processor/thermal objects */ | ||
358 | |||
359 | node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); | ||
360 | if ((node->type == ACPI_TYPE_DEVICE) || | ||
361 | (node->type == ACPI_TYPE_PROCESSOR) || | ||
362 | (node->type == ACPI_TYPE_THERMAL)) { | ||
363 | info->device_count++; | ||
364 | return (AE_OK); | ||
365 | } | ||
366 | |||
367 | /* We are only looking for methods named _INI */ | ||
368 | |||
369 | if (!ACPI_COMPARE_NAME(node->name.ascii, METHOD_NAME__INI)) { | ||
370 | return (AE_OK); | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * The only _INI methods that we care about are those that are | ||
375 | * present under Device, Processor, and Thermal objects. | ||
376 | */ | ||
377 | parent_node = acpi_ns_get_parent_node(node); | ||
378 | switch (parent_node->type) { | ||
379 | case ACPI_TYPE_DEVICE: | ||
380 | case ACPI_TYPE_PROCESSOR: | ||
381 | case ACPI_TYPE_THERMAL: | ||
382 | |||
383 | /* Mark parent and bubble up the INI present flag to the root */ | ||
384 | |||
385 | while (parent_node) { | ||
386 | parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; | ||
387 | parent_node = acpi_ns_get_parent_node(parent_node); | ||
388 | } | ||
389 | break; | ||
390 | |||
391 | default: | ||
392 | break; | ||
393 | } | ||
394 | |||
395 | return (AE_OK); | ||
396 | } | ||
397 | |||
398 | /******************************************************************************* | ||
399 | * | ||
314 | * FUNCTION: acpi_ns_init_one_device | 400 | * FUNCTION: acpi_ns_init_one_device |
315 | * | 401 | * |
316 | * PARAMETERS: acpi_walk_callback | 402 | * PARAMETERS: acpi_walk_callback |
@@ -327,119 +413,165 @@ static acpi_status | |||
327 | acpi_ns_init_one_device(acpi_handle obj_handle, | 413 | acpi_ns_init_one_device(acpi_handle obj_handle, |
328 | u32 nesting_level, void *context, void **return_value) | 414 | u32 nesting_level, void *context, void **return_value) |
329 | { | 415 | { |
330 | struct acpi_device_walk_info *info = | 416 | struct acpi_device_walk_info *walk_info = |
331 | (struct acpi_device_walk_info *)context; | 417 | ACPI_CAST_PTR(struct acpi_device_walk_info, context); |
332 | struct acpi_parameter_info pinfo; | 418 | struct acpi_evaluate_info *info = walk_info->evaluate_info; |
333 | u32 flags; | 419 | u32 flags; |
334 | acpi_status status; | 420 | acpi_status status; |
335 | struct acpi_namespace_node *ini_node; | ||
336 | struct acpi_namespace_node *device_node; | 421 | struct acpi_namespace_node *device_node; |
337 | 422 | ||
338 | ACPI_FUNCTION_TRACE("ns_init_one_device"); | 423 | ACPI_FUNCTION_TRACE(ns_init_one_device); |
339 | 424 | ||
340 | device_node = acpi_ns_map_handle_to_node(obj_handle); | 425 | /* We are interested in Devices, Processors and thermal_zones only */ |
341 | if (!device_node) { | ||
342 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
343 | } | ||
344 | 426 | ||
345 | /* | 427 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); |
346 | * We will run _STA/_INI on Devices, Processors and thermal_zones only | ||
347 | */ | ||
348 | if ((device_node->type != ACPI_TYPE_DEVICE) && | 428 | if ((device_node->type != ACPI_TYPE_DEVICE) && |
349 | (device_node->type != ACPI_TYPE_PROCESSOR) && | 429 | (device_node->type != ACPI_TYPE_PROCESSOR) && |
350 | (device_node->type != ACPI_TYPE_THERMAL)) { | 430 | (device_node->type != ACPI_TYPE_THERMAL)) { |
351 | return_ACPI_STATUS(AE_OK); | 431 | return_ACPI_STATUS(AE_OK); |
352 | } | 432 | } |
353 | 433 | ||
354 | if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && | ||
355 | (!(acpi_dbg_level & ACPI_LV_INFO))) { | ||
356 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); | ||
357 | } | ||
358 | |||
359 | info->device_count++; | ||
360 | |||
361 | /* | 434 | /* |
362 | * Check if the _INI method exists for this device - | 435 | * Because of an earlier namespace analysis, all subtrees that contain an |
363 | * if _INI does not exist, there is no need to run _STA | 436 | * _INI method are tagged. |
364 | * No _INI means device requires no initialization | 437 | * |
438 | * If this device subtree does not contain any _INI methods, we | ||
439 | * can exit now and stop traversing this entire subtree. | ||
365 | */ | 440 | */ |
366 | status = acpi_ns_search_node(*ACPI_CAST_PTR(u32, METHOD_NAME__INI), | 441 | if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) { |
367 | device_node, ACPI_TYPE_METHOD, &ini_node); | 442 | return_ACPI_STATUS(AE_CTRL_DEPTH); |
368 | if (ACPI_FAILURE(status)) { | ||
369 | /* No _INI method found - move on to next device */ | ||
370 | |||
371 | return_ACPI_STATUS(AE_OK); | ||
372 | } | 443 | } |
373 | 444 | ||
374 | /* | 445 | /* |
375 | * Run _STA to determine if we can run _INI on the device - | 446 | * Run _STA to determine if this device is present and functioning. We |
376 | * the device must be present before _INI can be run. | 447 | * must know this information for two important reasons (from ACPI spec): |
377 | * However, _STA is not required - assume device present if no _STA | 448 | * |
449 | * 1) We can only run _INI if the device is present. | ||
450 | * 2) We must abort the device tree walk on this subtree if the device is | ||
451 | * not present and is not functional (we will not examine the children) | ||
452 | * | ||
453 | * The _STA method is not required to be present under the device, we | ||
454 | * assume the device is present if _STA does not exist. | ||
378 | */ | 455 | */ |
379 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD, | 456 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
380 | device_node, | 457 | (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA)); |
381 | METHOD_NAME__STA)); | ||
382 | |||
383 | pinfo.node = device_node; | ||
384 | pinfo.parameters = NULL; | ||
385 | pinfo.parameter_type = ACPI_PARAM_ARGS; | ||
386 | 458 | ||
387 | status = acpi_ut_execute_STA(pinfo.node, &flags); | 459 | status = acpi_ut_execute_STA(device_node, &flags); |
388 | if (ACPI_FAILURE(status)) { | 460 | if (ACPI_FAILURE(status)) { |
461 | |||
389 | /* Ignore error and move on to next device */ | 462 | /* Ignore error and move on to next device */ |
390 | 463 | ||
391 | return_ACPI_STATUS(AE_OK); | 464 | return_ACPI_STATUS(AE_OK); |
392 | } | 465 | } |
393 | 466 | ||
467 | /* | ||
468 | * Flags == -1 means that _STA was not found. In this case, we assume that | ||
469 | * the device is both present and functional. | ||
470 | * | ||
471 | * From the ACPI spec, description of _STA: | ||
472 | * | ||
473 | * "If a device object (including the processor object) does not have an | ||
474 | * _STA object, then OSPM assumes that all of the above bits are set (in | ||
475 | * other words, the device is present, ..., and functioning)" | ||
476 | */ | ||
394 | if (flags != ACPI_UINT32_MAX) { | 477 | if (flags != ACPI_UINT32_MAX) { |
395 | info->num_STA++; | 478 | walk_info->num_STA++; |
396 | } | 479 | } |
397 | 480 | ||
481 | /* | ||
482 | * Examine the PRESENT and FUNCTIONING status bits | ||
483 | * | ||
484 | * Note: ACPI spec does not seem to specify behavior for the present but | ||
485 | * not functioning case, so we assume functioning if present. | ||
486 | */ | ||
398 | if (!(flags & ACPI_STA_DEVICE_PRESENT)) { | 487 | if (!(flags & ACPI_STA_DEVICE_PRESENT)) { |
399 | /* Don't look at children of a not present device */ | ||
400 | 488 | ||
401 | return_ACPI_STATUS(AE_CTRL_DEPTH); | 489 | /* Device is not present, we must examine the Functioning bit */ |
490 | |||
491 | if (flags & ACPI_STA_DEVICE_FUNCTIONING) { | ||
492 | /* | ||
493 | * Device is not present but is "functioning". In this case, | ||
494 | * we will not run _INI, but we continue to examine the children | ||
495 | * of this device. | ||
496 | * | ||
497 | * From the ACPI spec, description of _STA: (Note - no mention | ||
498 | * of whether to run _INI or not on the device in question) | ||
499 | * | ||
500 | * "_STA may return bit 0 clear (not present) with bit 3 set | ||
501 | * (device is functional). This case is used to indicate a valid | ||
502 | * device for which no device driver should be loaded (for example, | ||
503 | * a bridge device.) Children of this device may be present and | ||
504 | * valid. OSPM should continue enumeration below a device whose | ||
505 | * _STA returns this bit combination" | ||
506 | */ | ||
507 | return_ACPI_STATUS(AE_OK); | ||
508 | } else { | ||
509 | /* | ||
510 | * Device is not present and is not functioning. We must abort the | ||
511 | * walk of this subtree immediately -- don't look at the children | ||
512 | * of such a device. | ||
513 | * | ||
514 | * From the ACPI spec, description of _INI: | ||
515 | * | ||
516 | * "If the _STA method indicates that the device is not present, | ||
517 | * OSPM will not run the _INI and will not examine the children | ||
518 | * of the device for _INI methods" | ||
519 | */ | ||
520 | return_ACPI_STATUS(AE_CTRL_DEPTH); | ||
521 | } | ||
402 | } | 522 | } |
403 | 523 | ||
404 | /* | 524 | /* |
405 | * The device is present and _INI exists. Run the _INI method. | 525 | * The device is present or is assumed present if no _STA exists. |
406 | * (We already have the _INI node from above) | 526 | * Run the _INI if it exists (not required to exist) |
527 | * | ||
528 | * Note: We know there is an _INI within this subtree, but it may not be | ||
529 | * under this particular device, it may be lower in the branch. | ||
407 | */ | 530 | */ |
408 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD, | 531 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
409 | pinfo.node, | 532 | (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); |
410 | METHOD_NAME__INI)); | 533 | |
534 | info->prefix_node = device_node; | ||
535 | info->pathname = METHOD_NAME__INI; | ||
536 | info->parameters = NULL; | ||
537 | info->parameter_type = ACPI_PARAM_ARGS; | ||
538 | info->flags = ACPI_IGNORE_RETURN_VALUE; | ||
539 | |||
540 | status = acpi_ns_evaluate(info); | ||
541 | if (ACPI_SUCCESS(status)) { | ||
542 | walk_info->num_INI++; | ||
543 | |||
544 | if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && | ||
545 | (!(acpi_dbg_level & ACPI_LV_INFO))) { | ||
546 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); | ||
547 | } | ||
548 | } | ||
549 | #ifdef ACPI_DEBUG_OUTPUT | ||
550 | else if (status != AE_NOT_FOUND) { | ||
411 | 551 | ||
412 | pinfo.node = ini_node; | ||
413 | status = acpi_ns_evaluate_by_handle(&pinfo); | ||
414 | if (ACPI_FAILURE(status)) { | ||
415 | /* Ignore error and move on to next device */ | 552 | /* Ignore error and move on to next device */ |
416 | 553 | ||
417 | #ifdef ACPI_DEBUG_OUTPUT | 554 | char *scope_name = |
418 | char *scope_name = acpi_ns_get_external_pathname(ini_node); | 555 | acpi_ns_get_external_pathname(info->resolved_node); |
419 | |||
420 | ACPI_WARNING((AE_INFO, "%s._INI failed: %s", | ||
421 | scope_name, acpi_format_exception(status))); | ||
422 | 556 | ||
423 | ACPI_MEM_FREE(scope_name); | 557 | ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", |
558 | scope_name)); | ||
559 | ACPI_FREE(scope_name); | ||
560 | } | ||
424 | #endif | 561 | #endif |
425 | } else { | ||
426 | /* Delete any return object (especially if implicit_return is enabled) */ | ||
427 | 562 | ||
428 | if (pinfo.return_object) { | 563 | /* Ignore errors from above */ |
429 | acpi_ut_remove_reference(pinfo.return_object); | ||
430 | } | ||
431 | 564 | ||
432 | /* Count of successful INIs */ | 565 | status = AE_OK; |
433 | |||
434 | info->num_INI++; | ||
435 | } | ||
436 | 566 | ||
567 | /* | ||
568 | * The _INI method has been run if present; call the Global Initialization | ||
569 | * Handler for this device. | ||
570 | */ | ||
437 | if (acpi_gbl_init_handler) { | 571 | if (acpi_gbl_init_handler) { |
438 | /* External initialization handler is present, call it */ | ||
439 | |||
440 | status = | 572 | status = |
441 | acpi_gbl_init_handler(pinfo.node, ACPI_INIT_DEVICE_INI); | 573 | acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI); |
442 | } | 574 | } |
443 | 575 | ||
444 | return_ACPI_STATUS(AE_OK); | 576 | return_ACPI_STATUS(status); |
445 | } | 577 | } |