diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-01-10 07:13:49 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-01-25 18:34:21 -0500 |
commit | 33f767d767e9a684e9cd60704d4c049a2014c8d5 (patch) | |
tree | 22fbc06ee9eb22974955625ffc296b04e35a9090 /drivers/acpi | |
parent | 949db153b6466c6f7cad5a427ecea94985927311 (diff) |
ACPI: Rework acpi_get_child() to be more efficient
Observe that acpi_get_child() doesn't need to use the helper
struct acpi_find_child structure and change it to work without it.
Also, using acpi_get_object_info() to get the output of _ADR for the
given device is overkill, because that function does much more than
just evaluating _ADR (let alone the additional memory allocation
done by it).
Moreover, acpi_get_child() doesn't need to loop any more once it has
found a matching handle, so make it stop in that case. To prevent
the results from changing, make it use do_acpi_find_child() as
a post-order callback.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/glue.c | 35 |
1 files changed, 13 insertions, 22 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 35da18113216..e9e486f79b35 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -95,40 +95,31 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) | |||
95 | return ret; | 95 | return ret; |
96 | } | 96 | } |
97 | 97 | ||
98 | /* Get device's handler per its address under its parent */ | 98 | static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used, |
99 | struct acpi_find_child { | 99 | void *addr_p, void **ret_p) |
100 | acpi_handle handle; | ||
101 | u64 address; | ||
102 | }; | ||
103 | |||
104 | static acpi_status | ||
105 | do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
106 | { | 100 | { |
101 | unsigned long long addr; | ||
107 | acpi_status status; | 102 | acpi_status status; |
108 | struct acpi_device_info *info; | 103 | |
109 | struct acpi_find_child *find = context; | 104 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); |
110 | 105 | if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) { | |
111 | status = acpi_get_object_info(handle, &info); | 106 | *ret_p = handle; |
112 | if (ACPI_SUCCESS(status)) { | 107 | return AE_CTRL_TERMINATE; |
113 | if ((info->address == find->address) | ||
114 | && (info->valid & ACPI_VALID_ADR)) | ||
115 | find->handle = handle; | ||
116 | kfree(info); | ||
117 | } | 108 | } |
118 | return AE_OK; | 109 | return AE_OK; |
119 | } | 110 | } |
120 | 111 | ||
121 | acpi_handle acpi_get_child(acpi_handle parent, u64 address) | 112 | acpi_handle acpi_get_child(acpi_handle parent, u64 address) |
122 | { | 113 | { |
123 | struct acpi_find_child find = { NULL, address }; | 114 | void *ret = NULL; |
124 | 115 | ||
125 | if (!parent) | 116 | if (!parent) |
126 | return NULL; | 117 | return NULL; |
127 | acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, | ||
128 | 1, do_acpi_find_child, NULL, &find, NULL); | ||
129 | return find.handle; | ||
130 | } | ||
131 | 118 | ||
119 | acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, NULL, | ||
120 | do_acpi_find_child, &address, &ret); | ||
121 | return (acpi_handle)ret; | ||
122 | } | ||
132 | EXPORT_SYMBOL(acpi_get_child); | 123 | EXPORT_SYMBOL(acpi_get_child); |
133 | 124 | ||
134 | static int acpi_bind_one(struct device *dev, acpi_handle handle) | 125 | static int acpi_bind_one(struct device *dev, acpi_handle handle) |