diff options
Diffstat (limited to 'drivers/acpi/namespace/nsinit.c')
-rw-r--r-- | drivers/acpi/namespace/nsinit.c | 265 |
1 files changed, 187 insertions, 78 deletions
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 57b2537643c7..bf1d8dbc0b86 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,28 +146,29 @@ 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 | ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
150 | } | 158 | } |
151 | 159 | ||
152 | /* Walk namespace for all objects */ | 160 | /* Walk namespace to execute all _INIs on present devices */ |
153 | 161 | ||
154 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, | 162 | status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
155 | ACPI_UINT32_MAX, TRUE, | 163 | ACPI_UINT32_MAX, FALSE, |
156 | acpi_ns_init_one_device, &info, NULL); | 164 | acpi_ns_init_one_device, &info, NULL); |
157 | |||
158 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
159 | |||
160 | if (ACPI_FAILURE(status)) { | 165 | if (ACPI_FAILURE(status)) { |
161 | ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace")); | 166 | ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
162 | } | 167 | } |
163 | 168 | ||
164 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, | 169 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, |
165 | "\n%hd Devices found - executed %hd _STA, %hd _INI methods\n", | 170 | "\nExecuted %hd _INI methods requiring %hd _STA executions (examined %hd objects)\n", |
166 | info.device_count, info.num_STA, info.num_INI)); | 171 | info.num_INI, info.num_STA, info.device_count)); |
167 | 172 | ||
168 | return_ACPI_STATUS(status); | 173 | return_ACPI_STATUS(status); |
169 | } | 174 | } |
@@ -200,7 +205,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, | |||
200 | (struct acpi_namespace_node *)obj_handle; | 205 | (struct acpi_namespace_node *)obj_handle; |
201 | union acpi_operand_object *obj_desc; | 206 | union acpi_operand_object *obj_desc; |
202 | 207 | ||
203 | ACPI_FUNCTION_NAME("ns_init_one_object"); | 208 | ACPI_FUNCTION_NAME(ns_init_one_object); |
204 | 209 | ||
205 | info->object_count++; | 210 | info->object_count++; |
206 | 211 | ||
@@ -311,6 +316,72 @@ acpi_ns_init_one_object(acpi_handle obj_handle, | |||
311 | 316 | ||
312 | /******************************************************************************* | 317 | /******************************************************************************* |
313 | * | 318 | * |
319 | * FUNCTION: acpi_ns_find_ini_methods | ||
320 | * | ||
321 | * PARAMETERS: acpi_walk_callback | ||
322 | * | ||
323 | * RETURN: acpi_status | ||
324 | * | ||
325 | * DESCRIPTION: Called during namespace walk. Finds objects named _INI under | ||
326 | * device/processor/thermal objects, and marks the entire subtree | ||
327 | * with a SUBTREE_HAS_INI flag. This flag is used during the | ||
328 | * subsequent device initialization walk to avoid entire subtrees | ||
329 | * that do not contain an _INI. | ||
330 | * | ||
331 | ******************************************************************************/ | ||
332 | |||
333 | static acpi_status | ||
334 | acpi_ns_find_ini_methods(acpi_handle obj_handle, | ||
335 | u32 nesting_level, void *context, void **return_value) | ||
336 | { | ||
337 | struct acpi_device_walk_info *info = | ||
338 | ACPI_CAST_PTR(struct acpi_device_walk_info, context); | ||
339 | struct acpi_namespace_node *node; | ||
340 | struct acpi_namespace_node *parent_node; | ||
341 | |||
342 | /* Keep count of device/processor/thermal objects */ | ||
343 | |||
344 | node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); | ||
345 | if ((node->type == ACPI_TYPE_DEVICE) || | ||
346 | (node->type == ACPI_TYPE_PROCESSOR) || | ||
347 | (node->type == ACPI_TYPE_THERMAL)) { | ||
348 | info->device_count++; | ||
349 | return (AE_OK); | ||
350 | } | ||
351 | |||
352 | /* We are only looking for methods named _INI */ | ||
353 | |||
354 | if (!ACPI_COMPARE_NAME(node->name.ascii, METHOD_NAME__INI)) { | ||
355 | return (AE_OK); | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * The only _INI methods that we care about are those that are | ||
360 | * present under Device, Processor, and Thermal objects. | ||
361 | */ | ||
362 | parent_node = acpi_ns_get_parent_node(node); | ||
363 | switch (parent_node->type) { | ||
364 | case ACPI_TYPE_DEVICE: | ||
365 | case ACPI_TYPE_PROCESSOR: | ||
366 | case ACPI_TYPE_THERMAL: | ||
367 | |||
368 | /* Mark parent and bubble up the INI present flag to the root */ | ||
369 | |||
370 | while (parent_node) { | ||
371 | parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; | ||
372 | parent_node = acpi_ns_get_parent_node(parent_node); | ||
373 | } | ||
374 | break; | ||
375 | |||
376 | default: | ||
377 | break; | ||
378 | } | ||
379 | |||
380 | return (AE_OK); | ||
381 | } | ||
382 | |||
383 | /******************************************************************************* | ||
384 | * | ||
314 | * FUNCTION: acpi_ns_init_one_device | 385 | * FUNCTION: acpi_ns_init_one_device |
315 | * | 386 | * |
316 | * PARAMETERS: acpi_walk_callback | 387 | * PARAMETERS: acpi_walk_callback |
@@ -328,64 +399,49 @@ acpi_ns_init_one_device(acpi_handle obj_handle, | |||
328 | u32 nesting_level, void *context, void **return_value) | 399 | u32 nesting_level, void *context, void **return_value) |
329 | { | 400 | { |
330 | struct acpi_device_walk_info *info = | 401 | struct acpi_device_walk_info *info = |
331 | (struct acpi_device_walk_info *)context; | 402 | ACPI_CAST_PTR(struct acpi_device_walk_info, context); |
332 | struct acpi_parameter_info pinfo; | 403 | struct acpi_parameter_info pinfo; |
333 | u32 flags; | 404 | u32 flags; |
334 | acpi_status status; | 405 | acpi_status status; |
335 | struct acpi_namespace_node *ini_node; | ||
336 | struct acpi_namespace_node *device_node; | 406 | struct acpi_namespace_node *device_node; |
337 | 407 | ||
338 | ACPI_FUNCTION_TRACE("ns_init_one_device"); | 408 | ACPI_FUNCTION_TRACE(ns_init_one_device); |
339 | 409 | ||
340 | device_node = acpi_ns_map_handle_to_node(obj_handle); | 410 | /* We are interested in Devices, Processors and thermal_zones only */ |
341 | if (!device_node) { | ||
342 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
343 | } | ||
344 | 411 | ||
345 | /* | 412 | 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) && | 413 | if ((device_node->type != ACPI_TYPE_DEVICE) && |
349 | (device_node->type != ACPI_TYPE_PROCESSOR) && | 414 | (device_node->type != ACPI_TYPE_PROCESSOR) && |
350 | (device_node->type != ACPI_TYPE_THERMAL)) { | 415 | (device_node->type != ACPI_TYPE_THERMAL)) { |
351 | return_ACPI_STATUS(AE_OK); | 416 | return_ACPI_STATUS(AE_OK); |
352 | } | 417 | } |
353 | 418 | ||
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 | /* | 419 | /* |
362 | * Check if the _INI method exists for this device - | 420 | * Because of an earlier namespace analysis, all subtrees that contain an |
363 | * if _INI does not exist, there is no need to run _STA | 421 | * _INI method are tagged. |
364 | * No _INI means device requires no initialization | 422 | * |
423 | * If this device subtree does not contain any _INI methods, we | ||
424 | * can exit now and stop traversing this entire subtree. | ||
365 | */ | 425 | */ |
366 | status = acpi_ns_search_node(*ACPI_CAST_PTR(u32, METHOD_NAME__INI), | 426 | if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) { |
367 | device_node, ACPI_TYPE_METHOD, &ini_node); | 427 | return_ACPI_STATUS(AE_CTRL_DEPTH); |
368 | if (ACPI_FAILURE(status)) { | ||
369 | |||
370 | /* No _INI method found - move on to next device */ | ||
371 | |||
372 | return_ACPI_STATUS(AE_OK); | ||
373 | } | 428 | } |
374 | 429 | ||
375 | /* | 430 | /* |
376 | * Run _STA to determine if we can run _INI on the device - | 431 | * Run _STA to determine if this device is present and functioning. We |
377 | * the device must be present before _INI can be run. | 432 | * must know this information for two important reasons (from ACPI spec): |
378 | * However, _STA is not required - assume device present if no _STA | 433 | * |
434 | * 1) We can only run _INI if the device is present. | ||
435 | * 2) We must abort the device tree walk on this subtree if the device is | ||
436 | * not present and is not functional (we will not examine the children) | ||
437 | * | ||
438 | * The _STA method is not required to be present under the device, we | ||
439 | * assume the device is present if _STA does not exist. | ||
379 | */ | 440 | */ |
380 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD, | 441 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
381 | device_node, | 442 | (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA)); |
382 | METHOD_NAME__STA)); | ||
383 | 443 | ||
384 | pinfo.node = device_node; | 444 | status = acpi_ut_execute_STA(device_node, &flags); |
385 | pinfo.parameters = NULL; | ||
386 | pinfo.parameter_type = ACPI_PARAM_ARGS; | ||
387 | |||
388 | status = acpi_ut_execute_STA(pinfo.node, &flags); | ||
389 | if (ACPI_FAILURE(status)) { | 445 | if (ACPI_FAILURE(status)) { |
390 | 446 | ||
391 | /* Ignore error and move on to next device */ | 447 | /* Ignore error and move on to next device */ |
@@ -393,55 +449,108 @@ acpi_ns_init_one_device(acpi_handle obj_handle, | |||
393 | return_ACPI_STATUS(AE_OK); | 449 | return_ACPI_STATUS(AE_OK); |
394 | } | 450 | } |
395 | 451 | ||
452 | /* | ||
453 | * Flags == -1 means that _STA was not found. In this case, we assume that | ||
454 | * the device is both present and functional. | ||
455 | * | ||
456 | * From the ACPI spec, description of _STA: | ||
457 | * | ||
458 | * "If a device object (including the processor object) does not have an | ||
459 | * _STA object, then OSPM assumes that all of the above bits are set (in | ||
460 | * other words, the device is present, ..., and functioning)" | ||
461 | */ | ||
396 | if (flags != ACPI_UINT32_MAX) { | 462 | if (flags != ACPI_UINT32_MAX) { |
397 | info->num_STA++; | 463 | info->num_STA++; |
398 | } | 464 | } |
399 | 465 | ||
466 | /* | ||
467 | * Examine the PRESENT and FUNCTIONING status bits | ||
468 | * | ||
469 | * Note: ACPI spec does not seem to specify behavior for the present but | ||
470 | * not functioning case, so we assume functioning if present. | ||
471 | */ | ||
400 | if (!(flags & ACPI_STA_DEVICE_PRESENT)) { | 472 | if (!(flags & ACPI_STA_DEVICE_PRESENT)) { |
401 | 473 | ||
402 | /* Don't look at children of a not present device */ | 474 | /* Device is not present, we must examine the Functioning bit */ |
403 | 475 | ||
404 | return_ACPI_STATUS(AE_CTRL_DEPTH); | 476 | if (flags & ACPI_STA_DEVICE_FUNCTIONING) { |
477 | /* | ||
478 | * Device is not present but is "functioning". In this case, | ||
479 | * we will not run _INI, but we continue to examine the children | ||
480 | * of this device. | ||
481 | * | ||
482 | * From the ACPI spec, description of _STA: (Note - no mention | ||
483 | * of whether to run _INI or not on the device in question) | ||
484 | * | ||
485 | * "_STA may return bit 0 clear (not present) with bit 3 set | ||
486 | * (device is functional). This case is used to indicate a valid | ||
487 | * device for which no device driver should be loaded (for example, | ||
488 | * a bridge device.) Children of this device may be present and | ||
489 | * valid. OSPM should continue enumeration below a device whose | ||
490 | * _STA returns this bit combination" | ||
491 | */ | ||
492 | return_ACPI_STATUS(AE_OK); | ||
493 | } else { | ||
494 | /* | ||
495 | * Device is not present and is not functioning. We must abort the | ||
496 | * walk of this subtree immediately -- don't look at the children | ||
497 | * of such a device. | ||
498 | * | ||
499 | * From the ACPI spec, description of _INI: | ||
500 | * | ||
501 | * "If the _STA method indicates that the device is not present, | ||
502 | * OSPM will not run the _INI and will not examine the children | ||
503 | * of the device for _INI methods" | ||
504 | */ | ||
505 | return_ACPI_STATUS(AE_CTRL_DEPTH); | ||
506 | } | ||
405 | } | 507 | } |
406 | 508 | ||
407 | /* | 509 | /* |
408 | * The device is present and _INI exists. Run the _INI method. | 510 | * The device is present or is assumed present if no _STA exists. |
409 | * (We already have the _INI node from above) | 511 | * Run the _INI if it exists (not required to exist) |
512 | * | ||
513 | * Note: We know there is an _INI within this subtree, but it may not be | ||
514 | * under this particular device, it may be lower in the branch. | ||
410 | */ | 515 | */ |
411 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD, | 516 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname |
412 | pinfo.node, | 517 | (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); |
413 | METHOD_NAME__INI)); | ||
414 | 518 | ||
415 | pinfo.node = ini_node; | 519 | pinfo.node = device_node; |
416 | status = acpi_ns_evaluate_by_handle(&pinfo); | 520 | pinfo.parameters = NULL; |
417 | if (ACPI_FAILURE(status)) { | 521 | pinfo.parameter_type = ACPI_PARAM_ARGS; |
418 | |||
419 | /* Ignore error and move on to next device */ | ||
420 | |||
421 | #ifdef ACPI_DEBUG_OUTPUT | ||
422 | char *scope_name = acpi_ns_get_external_pathname(ini_node); | ||
423 | 522 | ||
424 | ACPI_WARNING((AE_INFO, "%s._INI failed: %s", | 523 | status = acpi_ns_evaluate_relative(METHOD_NAME__INI, &pinfo); |
425 | scope_name, acpi_format_exception(status))); | 524 | if (ACPI_SUCCESS(status)) { |
426 | 525 | ||
427 | ACPI_FREE(scope_name); | ||
428 | #endif | ||
429 | } else { | ||
430 | /* Delete any return object (especially if implicit_return is enabled) */ | 526 | /* Delete any return object (especially if implicit_return is enabled) */ |
431 | 527 | ||
432 | if (pinfo.return_object) { | 528 | if (pinfo.return_object) { |
433 | acpi_ut_remove_reference(pinfo.return_object); | 529 | acpi_ut_remove_reference(pinfo.return_object); |
434 | } | 530 | } |
435 | 531 | ||
436 | /* Count of successful INIs */ | ||
437 | |||
438 | info->num_INI++; | 532 | info->num_INI++; |
533 | if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && | ||
534 | (!(acpi_dbg_level & ACPI_LV_INFO))) { | ||
535 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); | ||
536 | } | ||
439 | } | 537 | } |
538 | #ifdef ACPI_DEBUG_OUTPUT | ||
539 | else if (status != AE_NOT_FOUND) { | ||
440 | 540 | ||
441 | if (acpi_gbl_init_handler) { | 541 | /* Ignore error and move on to next device */ |
542 | |||
543 | char *scope_name = acpi_ns_get_external_pathname(pinfo.node); | ||
442 | 544 | ||
443 | /* External initialization handler is present, call it */ | 545 | ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", |
546 | scope_name)); | ||
547 | ACPI_FREE(scope_name); | ||
548 | } | ||
549 | #endif | ||
444 | 550 | ||
551 | /* If an external initialization handler is present, call it */ | ||
552 | |||
553 | if (acpi_gbl_init_handler) { | ||
445 | status = | 554 | status = |
446 | acpi_gbl_init_handler(pinfo.node, ACPI_INIT_DEVICE_INI); | 555 | acpi_gbl_init_handler(pinfo.node, ACPI_INIT_DEVICE_INI); |
447 | } | 556 | } |