summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-09-11 15:22:27 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-09-11 15:22:27 +0200
commit0a733e6effb4a429551d8b000aa02750cc7e04ba (patch)
tree72ca7e1a9080b424b985b7c5633f9e5404806a1d /drivers/acpi
parent1a7b0ecbbc1219895f48934ff5549a3594db3480 (diff)
parent11b88ee275ec8590a373396888c2460ee89364d6 (diff)
Merge branch 'acpi-bind'
* acpi-bind: ACPI / bind: Prefer device objects with _STA to those without it
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/glue.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 94672297e1b..10f0f40587b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -79,6 +79,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
return ret;
}
+#define FIND_CHILD_MIN_SCORE 1
+#define FIND_CHILD_MAX_SCORE 2
+
static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_p)
{
@@ -92,14 +95,17 @@ static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
-static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
+static int do_find_child_checks(acpi_handle handle, bool is_bridge)
{
+ bool sta_present = true;
unsigned long long sta;
acpi_status status;
- status = acpi_bus_get_status_handle(handle, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
- return false;
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (status == AE_NOT_FOUND)
+ sta_present = false;
+ else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
+ return -ENODEV;
if (is_bridge) {
void *test = NULL;
@@ -107,16 +113,17 @@ static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
/* Check if this object has at least one child device. */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
acpi_dev_present, NULL, NULL, &test);
- return !!test;
+ if (!test)
+ return -ENODEV;
}
- return true;
+ return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
}
struct find_child_context {
u64 addr;
bool is_bridge;
acpi_handle ret;
- bool ret_checked;
+ int ret_score;
};
static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
@@ -125,6 +132,7 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
struct find_child_context *context = data;
unsigned long long addr;
acpi_status status;
+ int score;
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
if (ACPI_FAILURE(status) || addr != context->addr)
@@ -144,15 +152,20 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
* its handle if so. Second, check the same for the object that we've
* just found.
*/
- if (!context->ret_checked) {
- if (acpi_extra_checks_passed(context->ret, context->is_bridge))
+ if (!context->ret_score) {
+ score = do_find_child_checks(context->ret, context->is_bridge);
+ if (score == FIND_CHILD_MAX_SCORE)
return AE_CTRL_TERMINATE;
else
- context->ret_checked = true;
+ context->ret_score = score;
}
- if (acpi_extra_checks_passed(handle, context->is_bridge)) {
+ score = do_find_child_checks(handle, context->is_bridge);
+ if (score == FIND_CHILD_MAX_SCORE) {
context->ret = handle;
return AE_CTRL_TERMINATE;
+ } else if (score > context->ret_score) {
+ context->ret = handle;
+ context->ret_score = score;
}
return AE_OK;
}