Commit 51a85faf authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Len Brown

ACPI: use acpi_walk_namespace() to enumerate devices

acpi_bus_scan() currently walks the namespace manually.  This patch changes
it to use acpi_walk_namespace() instead.

Besides removing some complicated code, this means we take advantage of the
namespace locking done by acpi_walk_namespace().  The locking isn't so
important at boot-time, but I hope to eventually use this same path to
handle hot-addition of devices, when it will be important.

Note that acpi_walk_namespace() does not actually visit the starting node
first, so we need to do that by hand first.
Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 859ac9a4
...@@ -1393,123 +1393,92 @@ static int acpi_add_single_object(struct acpi_device **child, ...@@ -1393,123 +1393,92 @@ static int acpi_add_single_object(struct acpi_device **child,
return result; return result;
} }
static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops) static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
void *context, void **return_value)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_device *parent = NULL; struct acpi_device *device = NULL;
struct acpi_device *child = NULL;
acpi_handle phandle = NULL;
acpi_handle chandle = NULL;
acpi_object_type type = 0; acpi_object_type type = 0;
u32 level = 1; struct acpi_bus_ops *ops = context;
int ret;
/* status = acpi_get_type(handle, &type);
* We must have an acpi_device for the starting node already, and if (ACPI_FAILURE(status))
* we scan its children. return AE_OK;
*/
phandle = handle;
ret = acpi_bus_get_device(phandle, &parent);
if (ret)
return ret;
/* /*
* Parse through the ACPI namespace, identify all 'devices', and * We're only interested in objects that we consider 'devices'.
* create a new 'struct acpi_device' for each.
*/ */
while ((level > 0) && parent) { switch (type) {
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
case ACPI_TYPE_DEVICE:
type = ACPI_BUS_TYPE_DEVICE;
break;
case ACPI_TYPE_PROCESSOR:
type = ACPI_BUS_TYPE_PROCESSOR;
break;
case ACPI_TYPE_THERMAL:
type = ACPI_BUS_TYPE_THERMAL;
break;
case ACPI_TYPE_POWER:
type = ACPI_BUS_TYPE_POWER;
break;
default:
return AE_OK;
}
status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, if (ops->acpi_op_add)
chandle, &chandle); status = acpi_add_single_object(&device, handle, type, ops);
else
status = acpi_bus_get_device(handle, &device);
/* if (ACPI_FAILURE(status))
* If this scope is exhausted then move our way back up. return AE_CTRL_DEPTH;
*/
if (ACPI_FAILURE(status)) {
level--;
chandle = phandle;
acpi_get_parent(phandle, &phandle);
if (parent->parent)
parent = parent->parent;
continue;
}
status = acpi_get_type(chandle, &type); if (ops->acpi_op_start && !(ops->acpi_op_add)) {
status = acpi_start_single_object(device);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
continue; return AE_CTRL_DEPTH;
}
/*
* If this is a scope object then parse it (depth-first).
*/
if (type == ACPI_TYPE_LOCAL_SCOPE) {
level++;
phandle = chandle;
chandle = NULL;
continue;
}
/* /*
* We're only interested in objects that we consider 'devices'. * If the device is present, enabled, and functioning then
*/ * parse its scope (depth-first). Note that we need to
switch (type) { * represent absent devices to facilitate PnP notifications
case ACPI_TYPE_DEVICE: * -- but only the subtree head (not all of its children,
type = ACPI_BUS_TYPE_DEVICE; * which will be enumerated when the parent is inserted).
break; *
case ACPI_TYPE_PROCESSOR: * TBD: Need notifications and other detection mechanisms
type = ACPI_BUS_TYPE_PROCESSOR; * in place before we can fully implement this.
break; *
case ACPI_TYPE_THERMAL: * When the device is not present but functional, it is also
type = ACPI_BUS_TYPE_THERMAL; * necessary to scan the children of this device.
break; */
case ACPI_TYPE_POWER: if (!device->status.present && !device->status.functional)
type = ACPI_BUS_TYPE_POWER; return AE_CTRL_DEPTH;
break;
default:
continue;
}
if (ops->acpi_op_add) if (!*return_value)
status = acpi_add_single_object(&child, chandle, type, *return_value = device;
ops); return AE_OK;
else }
status = acpi_bus_get_device(chandle, &child);
if (ACPI_FAILURE(status)) static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
continue; struct acpi_device **child)
{
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
void *device = NULL;
if (ops->acpi_op_start && !(ops->acpi_op_add)) { acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
status = acpi_start_single_object(child); printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n",
if (ACPI_FAILURE(status)) (char *) buffer.pointer);
continue;
}
/* status = acpi_bus_check_add(handle, 0, ops, &device);
* If the device is present, enabled, and functioning then if (ACPI_SUCCESS(status))
* parse its scope (depth-first). Note that we need to acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
* represent absent devices to facilitate PnP notifications acpi_bus_check_add, ops, &device);
* -- but only the subtree head (not all of its children,
* which will be enumerated when the parent is inserted).
*
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*/
/*
* When the device is not present but functional, it is also
* necessary to scan the children of this device.
*/
if (child->status.present || (!child->status.present &&
child->status.functional)) {
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
NULL, NULL);
if (ACPI_SUCCESS(status)) {
level++;
phandle = chandle;
chandle = NULL;
parent = child;
}
}
}
if (child)
*child = device;
return 0; return 0;
} }
...@@ -1517,33 +1486,25 @@ int ...@@ -1517,33 +1486,25 @@ int
acpi_bus_add(struct acpi_device **child, acpi_bus_add(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type) struct acpi_device *parent, acpi_handle handle, int type)
{ {
int result;
struct acpi_bus_ops ops; struct acpi_bus_ops ops;
memset(&ops, 0, sizeof(ops)); memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1; ops.acpi_op_add = 1;
result = acpi_add_single_object(child, handle, type, &ops); acpi_bus_scan(handle, &ops, child);
if (!result) return 0;
result = acpi_bus_scan((*child)->handle, &ops);
return result;
} }
EXPORT_SYMBOL(acpi_bus_add); EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_start(struct acpi_device *device) int acpi_bus_start(struct acpi_device *device)
{ {
int result;
struct acpi_bus_ops ops; struct acpi_bus_ops ops;
memset(&ops, 0, sizeof(ops)); memset(&ops, 0, sizeof(ops));
ops.acpi_op_start = 1; ops.acpi_op_start = 1;
result = acpi_start_single_object(device); acpi_bus_scan(device->handle, &ops, NULL);
if (!result) return 0;
result = acpi_bus_scan(device->handle, &ops);
return result;
} }
EXPORT_SYMBOL(acpi_bus_start); EXPORT_SYMBOL(acpi_bus_start);
...@@ -1645,18 +1606,10 @@ int __init acpi_scan_init(void) ...@@ -1645,18 +1606,10 @@ int __init acpi_scan_init(void)
printk(KERN_ERR PREFIX "Could not register bus type\n"); printk(KERN_ERR PREFIX "Could not register bus type\n");
} }
/*
* Create the root device in the bus's device tree
*/
result = acpi_add_single_object(&acpi_root, ACPI_ROOT_OBJECT,
ACPI_BUS_TYPE_DEVICE, &ops);
if (result)
goto Done;
/* /*
* Enumerate devices in the ACPI namespace. * Enumerate devices in the ACPI namespace.
*/ */
result = acpi_bus_scan(acpi_root->handle, &ops); result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
if (!result) if (!result)
result = acpi_bus_scan_fixed(); result = acpi_bus_scan_fixed();
...@@ -1664,6 +1617,5 @@ int __init acpi_scan_init(void) ...@@ -1664,6 +1617,5 @@ int __init acpi_scan_init(void)
if (result) if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
Done:
return result; return result;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment