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: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
859ac9a4be
commit
51a85faf2d
1 changed files with 83 additions and 131 deletions
|
@ -1393,65 +1393,23 @@ end:
|
||||||
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
|
|
||||||
* we scan its children.
|
|
||||||
*/
|
|
||||||
phandle = handle;
|
|
||||||
ret = acpi_bus_get_device(phandle, &parent);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse through the ACPI namespace, identify all 'devices', and
|
|
||||||
* create a new 'struct acpi_device' for each.
|
|
||||||
*/
|
|
||||||
while ((level > 0) && parent) {
|
|
||||||
|
|
||||||
status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
|
|
||||||
chandle, &chandle);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If this scope is exhausted then move our way back up.
|
|
||||||
*/
|
|
||||||
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 (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
continue;
|
return AE_OK;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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'.
|
* We're only interested in objects that we consider 'devices'.
|
||||||
*/
|
*/
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
|
||||||
case ACPI_TYPE_DEVICE:
|
case ACPI_TYPE_DEVICE:
|
||||||
type = ACPI_BUS_TYPE_DEVICE;
|
type = ACPI_BUS_TYPE_DEVICE;
|
||||||
break;
|
break;
|
||||||
|
@ -1465,22 +1423,21 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops)
|
||||||
type = ACPI_BUS_TYPE_POWER;
|
type = ACPI_BUS_TYPE_POWER;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ops->acpi_op_add)
|
if (ops->acpi_op_add)
|
||||||
status = acpi_add_single_object(&child, chandle, type,
|
status = acpi_add_single_object(&device, handle, type, ops);
|
||||||
ops);
|
|
||||||
else
|
else
|
||||||
status = acpi_bus_get_device(chandle, &child);
|
status = acpi_bus_get_device(handle, &device);
|
||||||
|
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
continue;
|
return AE_CTRL_DEPTH;
|
||||||
|
|
||||||
if (ops->acpi_op_start && !(ops->acpi_op_add)) {
|
if (ops->acpi_op_start && !(ops->acpi_op_add)) {
|
||||||
status = acpi_start_single_object(child);
|
status = acpi_start_single_object(device);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
continue;
|
return AE_CTRL_DEPTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1492,24 +1449,36 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops)
|
||||||
*
|
*
|
||||||
* TBD: Need notifications and other detection mechanisms
|
* TBD: Need notifications and other detection mechanisms
|
||||||
* in place before we can fully implement this.
|
* in place before we can fully implement this.
|
||||||
*/
|
*
|
||||||
/*
|
|
||||||
* When the device is not present but functional, it is also
|
* When the device is not present but functional, it is also
|
||||||
* necessary to scan the children of this device.
|
* necessary to scan the children of this device.
|
||||||
*/
|
*/
|
||||||
if (child->status.present || (!child->status.present &&
|
if (!device->status.present && !device->status.functional)
|
||||||
child->status.functional)) {
|
return AE_CTRL_DEPTH;
|
||||||
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
|
|
||||||
NULL, NULL);
|
if (!*return_value)
|
||||||
if (ACPI_SUCCESS(status)) {
|
*return_value = device;
|
||||||
level++;
|
return AE_OK;
|
||||||
phandle = chandle;
|
|
||||||
chandle = NULL;
|
|
||||||
parent = child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
|
||||||
|
struct acpi_device **child)
|
||||||
|
{
|
||||||
|
acpi_status status;
|
||||||
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
void *device = NULL;
|
||||||
|
|
||||||
|
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||||
|
printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n",
|
||||||
|
(char *) buffer.pointer);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
*child = device;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue