Commit 2263576c authored by Lin Ming's avatar Lin Ming Committed by Len Brown
Browse files

ACPICA: Add post-order callback to acpi_walk_namespace

The existing interface only has a pre-order callback. This change
adds an additional parameter for a post-order callback which will
be more useful for bus scans. ACPICA BZ 779.

Also update the external calls to acpi_walk_namespace.

http://www.acpica.org/bugzilla/show_bug.cgi?id=779

Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 7d5d05d0
......@@ -390,7 +390,7 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
pcidev_match.handle = NULL;
acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX,
find_matching_device, &pcidev_match, NULL);
find_matching_device, NULL, &pcidev_match, NULL);
if (!pcidev_match.handle) {
printk(KERN_ERR
......
......@@ -885,7 +885,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
/* Find ACPI data for processor */
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, &longhaul_walk_callback,
ACPI_UINT32_MAX, &longhaul_walk_callback, NULL,
NULL, (void *)&pr);
/* Check ACPI support for C3 state */
......
......@@ -537,7 +537,7 @@ static int __init acpi_memory_device_init(void)
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
acpi_memory_register_notify_handler,
acpi_memory_register_notify_handler, NULL,
NULL, NULL);
if (ACPI_FAILURE(status)) {
......@@ -561,7 +561,7 @@ static void __exit acpi_memory_device_exit(void)
*/
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
acpi_memory_deregister_notify_handler,
acpi_memory_deregister_notify_handler, NULL,
NULL, NULL);
if (ACPI_FAILURE(status))
......
......@@ -104,7 +104,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_object,
u32 max_depth,
u32 flags,
acpi_walk_callback user_function,
acpi_walk_callback pre_order_visit,
acpi_walk_callback post_order_visit,
void *context, void **return_value);
struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
......
......@@ -192,7 +192,7 @@ acpi_ds_initialize_objects(u32 table_index,
status =
acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
ACPI_NS_WALK_UNLOCK, acpi_ds_init_one_object,
&info, NULL);
NULL, &info, NULL);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
}
......
......@@ -945,8 +945,8 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
acpi_ev_save_method_info, gpe_block,
NULL);
acpi_ev_save_method_info, NULL,
gpe_block, NULL);
/* Return the new block */
......@@ -1022,8 +1022,8 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
status =
acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
acpi_ev_match_prw_and_gpe, &gpe_info,
NULL);
acpi_ev_match_prw_and_gpe, NULL,
&gpe_info, NULL);
}
/*
......
......@@ -1025,8 +1025,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
*/
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
ACPI_NS_WALK_UNLOCK,
acpi_ev_install_handler, handler_obj,
NULL);
acpi_ev_install_handler, NULL,
handler_obj, NULL);
unlock_and_exit:
return_ACPI_STATUS(status);
......@@ -1062,7 +1062,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
*/
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
&space_id, NULL);
NULL, &space_id, NULL);
return_ACPI_STATUS(status);
}
......
......@@ -634,8 +634,8 @@ acpi_ns_dump_objects(acpi_object_type type,
(void)acpi_ns_walk_namespace(type, start_handle, max_depth,
ACPI_NS_WALK_NO_UNLOCK |
ACPI_NS_WALK_TEMP_NODES,
acpi_ns_dump_one_object, (void *)&info,
NULL);
acpi_ns_dump_one_object, NULL,
(void *)&info, NULL);
}
#endif /* ACPI_FUTURE_USAGE */
......
......@@ -131,7 +131,8 @@ void acpi_ns_dump_root_devices(void)
status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, sys_bus_handle,
ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
acpi_ns_dump_one_device, NULL, NULL);
acpi_ns_dump_one_device, NULL, NULL,
NULL);
}
#endif
......
......@@ -96,7 +96,7 @@ acpi_status acpi_ns_initialize_objects(void)
/* Walk entire namespace from the supplied root */
status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, acpi_ns_init_one_object,
ACPI_UINT32_MAX, acpi_ns_init_one_object, NULL,
&info, NULL);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
......@@ -156,7 +156,8 @@ acpi_status acpi_ns_initialize_devices(void)
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, FALSE,
acpi_ns_find_ini_methods, &info, NULL);
acpi_ns_find_ini_methods, NULL, &info,
NULL);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
......@@ -189,7 +190,8 @@ acpi_status acpi_ns_initialize_devices(void)
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, FALSE,
acpi_ns_init_one_device, &info, NULL);
acpi_ns_init_one_device, NULL, &info,
NULL);
ACPI_FREE(info.evaluate_info);
if (ACPI_FAILURE(status)) {
......
......@@ -165,24 +165,27 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
* max_depth - Depth to which search is to reach
* Flags - Whether to unlock the NS before invoking
* the callback routine
* user_function - Called when an object of "Type" is found
* Context - Passed to user function
* return_value - from the user_function if terminated early.
* Otherwise, returns NULL.
* pre_order_visit - Called during tree pre-order visit
* when an object of "Type" is found
* post_order_visit - Called during tree post-order visit
* when an object of "Type" is found
* Context - Passed to user function(s) above
* return_value - from the user_function if terminated
* early. Otherwise, returns NULL.
* RETURNS: Status
*
* DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
* starting (and ending) at the node specified by start_handle.
* The user_function is called whenever a node that matches
* the type parameter is found. If the user function returns
* The callback function is called whenever a node that matches
* the type parameter is found. If the callback function returns
* a non-zero value, the search is terminated immediately and
* this value is returned to the caller.
*
* The point of this procedure is to provide a generic namespace
* walk routine that can be called from multiple places to
* provide multiple services; the User Function can be tailored
* to each task, whether it is a print function, a compare
* function, etc.
* provide multiple services; the callback function(s) can be
* tailored to each task, whether it is a print function,
* a compare function, etc.
*
******************************************************************************/
......@@ -191,7 +194,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_node,
u32 max_depth,
u32 flags,
acpi_walk_callback user_function,
acpi_walk_callback pre_order_visit,
acpi_walk_callback post_order_visit,
void *context, void **return_value)
{
acpi_status status;
......@@ -200,6 +204,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
struct acpi_namespace_node *parent_node;
acpi_object_type child_type;
u32 level;
u8 node_previously_visited = FALSE;
ACPI_FUNCTION_TRACE(ns_walk_namespace);
......@@ -212,7 +217,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
/* Null child means "get first node" */
parent_node = start_node;
child_node = NULL;
child_node = acpi_ns_get_next_node(parent_node, NULL);
child_type = ACPI_TYPE_ANY;
level = 1;
......@@ -221,102 +226,129 @@ acpi_ns_walk_namespace(acpi_object_type type,
* started. When Level is zero, the loop is done because we have
* bubbled up to (and passed) the original parent handle (start_entry)
*/
while (level > 0) {
while (level > 0 && child_node) {
status = AE_OK;
/* Get the next node in this scope. Null if not found */
/* Found next child, get the type if we are not searching for ANY */
status = AE_OK;
child_node = acpi_ns_get_next_node(parent_node, child_node);
if (child_node) {
if (type != ACPI_TYPE_ANY) {
child_type = child_node->type;
}
/* Found next child, get the type if we are not searching for ANY */
/*
* Ignore all temporary namespace nodes (created during control
* method execution) unless told otherwise. These temporary nodes
* can cause a race condition because they can be deleted during
* the execution of the user function (if the namespace is
* unlocked before invocation of the user function.) Only the
* debugger namespace dump will examine the temporary nodes.
*/
if ((child_node->flags & ANOBJ_TEMPORARY) &&
!(flags & ACPI_NS_WALK_TEMP_NODES)) {
status = AE_CTRL_DEPTH;
}
if (type != ACPI_TYPE_ANY) {
child_type = child_node->type;
}
/* Type must match requested type */
else if (child_type == type) {
/*
* Ignore all temporary namespace nodes (created during control
* method execution) unless told otherwise. These temporary nodes
* can cause a race condition because they can be deleted during
* the execution of the user function (if the namespace is
* unlocked before invocation of the user function.) Only the
* debugger namespace dump will examine the temporary nodes.
* Found a matching node, invoke the user callback function.
* Unlock the namespace if flag is set.
*/
if ((child_node->flags & ANOBJ_TEMPORARY) &&
!(flags & ACPI_NS_WALK_TEMP_NODES)) {
status = AE_CTRL_DEPTH;
if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(mutex_status)) {
return_ACPI_STATUS(mutex_status);
}
}
/* Type must match requested type */
else if (child_type == type) {
/*
* Found a matching node, invoke the user callback function.
* Unlock the namespace if flag is set.
*/
if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_release_mutex
(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(mutex_status)) {
return_ACPI_STATUS
(mutex_status);
}
/*
* Invoke the user function, either pre-order or post-order
* or both.
*/
if (!node_previously_visited) {
if (pre_order_visit) {
status =
pre_order_visit(child_node, level,
context,
return_value);
}
} else {
if (post_order_visit) {
status =
post_order_visit(child_node, level,
context,
return_value);
}
}
status =
user_function(child_node, level, context,
return_value);
if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_acquire_mutex
(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(mutex_status)) {
return_ACPI_STATUS
(mutex_status);
}
if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(mutex_status)) {
return_ACPI_STATUS(mutex_status);
}
}
switch (status) {
case AE_OK:
case AE_CTRL_DEPTH:
switch (status) {
case AE_OK:
case AE_CTRL_DEPTH:
/* Just keep going */
break;
/* Just keep going */
break;
case AE_CTRL_TERMINATE:
case AE_CTRL_TERMINATE:
/* Exit now, with OK status */
/* Exit now, with OK status */
return_ACPI_STATUS(AE_OK);
return_ACPI_STATUS(AE_OK);
default:
default:
/* All others are valid exceptions */
/* All others are valid exceptions */
return_ACPI_STATUS(status);
}
return_ACPI_STATUS(status);
}
}
/*
* Depth first search: Attempt to go down another level in the
* namespace if we are allowed to. Don't go any further if we have
* reached the caller specified maximum depth or if the user
* function has specified that the maximum depth has been reached.
*/
if (!node_previously_visited &&
(level < max_depth) && (status != AE_CTRL_DEPTH)) {
if (child_node->child) {
/* There is at least one child of this node, visit it */
level++;
parent_node = child_node;
child_node =
acpi_ns_get_next_node(parent_node, NULL);
continue;
}
}
/*
* Depth first search: Attempt to go down another level in the
* namespace if we are allowed to. Don't go any further if we have
* reached the caller specified maximum depth or if the user
* function has specified that the maximum depth has been reached.
*/
if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
if (child_node->child) {
/* No more children, re-visit this node */
/* There is at least one child of this node, visit it */
if (!node_previously_visited) {
node_previously_visited = TRUE;
continue;
}
level++;
parent_node = child_node;
child_node = NULL;
}
}
} else {
/* No more children, visit peers */
child_node = acpi_ns_get_next_node(parent_node, child_node);
if (child_node) {
node_previously_visited = FALSE;
}
/* No peers, re-visit parent */
else {
/*
* No more children of this node (acpi_ns_get_next_node failed), go
* back upwards in the namespace tree to the node's parent.
......@@ -324,6 +356,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
level--;
child_node = parent_node;
parent_node = acpi_ns_get_parent_node(parent_node);
node_previously_visited = TRUE;
}
}
......
......@@ -433,8 +433,11 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
* PARAMETERS: Type - acpi_object_type to search for
* start_object - Handle in namespace where search begins
* max_depth - Depth to which search is to reach
* user_function - Called when an object of "Type" is found
* Context - Passed to user function
* pre_order_visit - Called during tree pre-order visit
* when an object of "Type" is found
* post_order_visit - Called during tree post-order visit
* when an object of "Type" is found
* Context - Passed to user function(s) above
* return_value - Location where return value of
* user_function is put if terminated early
*
......@@ -443,16 +446,16 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
*
* DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
* starting (and ending) at the object specified by start_handle.
* The user_function is called whenever an object that matches
* the type parameter is found. If the user function returns
* The callback function is called whenever an object that matches
* the type parameter is found. If the callback function returns
* a non-zero value, the search is terminated immediately and this
* value is returned to the caller.
*
* The point of this procedure is to provide a generic namespace
* walk routine that can be called from multiple places to
* provide multiple services; the User Function can be tailored
* to each task, whether it is a print function, a compare
* function, etc.
* provide multiple services; the callback function(s) can be
* tailored to each task, whether it is a print function,
* a compare function, etc.
*
******************************************************************************/
......@@ -460,7 +463,8 @@ acpi_status
acpi_walk_namespace(acpi_object_type type,
acpi_handle start_object,
u32 max_depth,
acpi_walk_callback user_function,
acpi_walk_callback pre_order_visit,
acpi_walk_callback post_order_visit,
void *context, void **return_value)
{
acpi_status status;
......@@ -469,7 +473,8 @@ acpi_walk_namespace(acpi_object_type type,
/* Parameter validation */
if ((type > ACPI_TYPE_LOCAL_MAX) || (!max_depth) || (!user_function)) {
if ((type > ACPI_TYPE_LOCAL_MAX) ||
(!max_depth) || (!pre_order_visit && !post_order_visit)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
......@@ -501,8 +506,9 @@ acpi_walk_namespace(acpi_object_type type,
}
status = acpi_ns_walk_namespace(type, start_object, max_depth,
ACPI_NS_WALK_UNLOCK, user_function,
context, return_value);
ACPI_NS_WALK_UNLOCK, pre_order_visit,
post_order_visit, context,
return_value);
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
......@@ -681,8 +687,8 @@ acpi_get_devices(const char *HID,
status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
acpi_ns_get_device_callback, &info,
return_value);
acpi_ns_get_device_callback, NULL,
&info, return_value);
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status);
......
......@@ -258,7 +258,7 @@ static int __init acpi_container_init(void)
acpi_walk_namespace(ACPI_TYPE_DEVICE,
ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
container_walk_namespace_cb, &action, NULL);
container_walk_namespace_cb, NULL, &action, NULL);
return (0);
}
......@@ -271,7 +271,7 @@ static void __exit acpi_container_exit(void)
acpi_walk_namespace(ACPI_TYPE_DEVICE,
ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
container_walk_namespace_cb, &action, NULL);
container_walk_namespace_cb, NULL, &action, NULL);
acpi_bus_unregister_driver(&acpi_container_driver);
......
......@@ -1030,8 +1030,8 @@ static int dock_add(acpi_handle handle)
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock_devices, dock_station,
NULL);
ACPI_UINT32_MAX, find_dock_devices, NULL,
dock_station, NULL);
/* add the dock station as a device dependent on itself */
dd = alloc_dock_dependent_device(handle);
......@@ -1127,11 +1127,11 @@ static int __init dock_init(void)
/* look for a dock station */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock, NULL, NULL);
ACPI_UINT32_MAX, find_dock, NULL, NULL, NULL);
/* look for bay */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_bay, NULL, NULL);
ACPI_UINT32_MAX, find_bay, NULL, NULL, NULL);
if (!dock_station_count) {
printk(KERN_INFO PREFIX "No dock devices found.\n");
return 0;
......
......@@ -820,7 +820,7 @@ static int acpi_ec_add(struct acpi_device *device)
/* Find and register all query methods */
acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
acpi_ec_register_query_methods, ec, NULL);
acpi_ec_register_query_methods, NULL, ec, NULL);
if (!first_ec)
first_ec = ec;
......
......@@ -113,7 +113,7 @@ acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address)
if (!parent)
return NULL;
acpi_walk_namespace(ACPI_TYPE_DEVICE, parent,
1, do_acpi_find_child, &find, NULL);
1, do_acpi_find_child, NULL, &find, NULL);
return find.handle;
}
......
......@@ -219,12 +219,12 @@ walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
user_function, &child_context, NULL);
user_function, NULL, &child_context, NULL);
if (ACPI_FAILURE(status))
goto out;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
walk_p2p_bridge, &child_context, NULL);
walk_p2p_bridge, NULL, &child_context, NULL);
out:
pci_dev_put(dev);
return AE_OK;
......@@ -277,12 +277,12 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
user_function, &context, NULL);
user_function, NULL, &context, NULL);
if (ACPI_FAILURE(status))
return status;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
walk_p2p_bridge, &context, NULL);
walk_p2p_bridge, NULL, &context, NULL);
if (ACPI_FAILURE(status))
err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
......
......@@ -1102,7 +1102,7 @@ void acpi_processor_install_hotplug_notify(void)
acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
processor_walk_namespace_cb, NULL, &action, NULL);
#endif
register_hotcpu_notifier(&acpi_cpu_notifier);
}
......@@ -1115,7 +1115,7 @@ void acpi_processor_uninstall_hotplug_notify(void)
acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
processor_walk_namespace_cb, NULL, &action, NULL);
#endif
unregister_hotcpu_notifier(&acpi_cpu_notifier);
}
......
......@@ -1332,7 +1332,7 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
status = acpi_bus_check_add(handle, 0, ops, &device);
if (ACPI_SUCCESS(status))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, ops, &device);
acpi_bus_check_add, NULL, ops, &device);
if (child)