diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-11-28 17:57:58 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-12-06 19:05:48 -0500 |
commit | d9fef0c4d2e08c3888add77f1dc54fb12afb3928 (patch) | |
tree | d5492f76a4cb79f7c18415585095b60cc7d84fe4 /drivers/acpi/glue.c | |
parent | 9ccad66f0171578445175ecd3bf66b35a96aaf6e (diff) |
ACPI / bind: Simplify child device lookups
Now that we create a struct acpi_device object for every ACPI
namespace node representing a device, it is not necessary to
use acpi_walk_namespace() for child device lookup in
acpi_find_child() any more. Instead, we can simply walk the
list of children of the given struct acpi_device object and
return the matching one (or the one which is the best match if
there are more of them). The checks done during the matching
loop can be simplified too so that the secondary namespace walks
in find_child_checks() are not necessary any more.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Aaron Lu <aaron.lu@intel.com>
Diffstat (limited to 'drivers/acpi/glue.c')
-rw-r--r-- | drivers/acpi/glue.c | 137 |
1 files changed, 55 insertions, 82 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a22a295edb69..ea77512ad70c 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -82,107 +82,80 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) | |||
82 | #define FIND_CHILD_MIN_SCORE 1 | 82 | #define FIND_CHILD_MIN_SCORE 1 |
83 | #define FIND_CHILD_MAX_SCORE 2 | 83 | #define FIND_CHILD_MAX_SCORE 2 |
84 | 84 | ||
85 | static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, | 85 | static int find_child_checks(struct acpi_device *adev, bool check_children) |
86 | void *not_used, void **ret_p) | ||
87 | { | ||
88 | struct acpi_device *adev = NULL; | ||
89 | |||
90 | acpi_bus_get_device(handle, &adev); | ||
91 | if (adev) { | ||
92 | *ret_p = handle; | ||
93 | return AE_CTRL_TERMINATE; | ||
94 | } | ||
95 | return AE_OK; | ||
96 | } | ||
97 | |||
98 | static int do_find_child_checks(acpi_handle handle, bool is_bridge) | ||
99 | { | 86 | { |
100 | bool sta_present = true; | 87 | bool sta_present = true; |
101 | unsigned long long sta; | 88 | unsigned long long sta; |
102 | acpi_status status; | 89 | acpi_status status; |
103 | 90 | ||
104 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | 91 | status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); |
105 | if (status == AE_NOT_FOUND) | 92 | if (status == AE_NOT_FOUND) |
106 | sta_present = false; | 93 | sta_present = false; |
107 | else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) | 94 | else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) |
108 | return -ENODEV; | 95 | return -ENODEV; |
109 | 96 | ||
110 | if (is_bridge) { | 97 | if (check_children && list_empty(&adev->children)) |
111 | void *test = NULL; | 98 | return -ENODEV; |
112 | 99 | ||
113 | /* Check if this object has at least one child device. */ | ||
114 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, | ||
115 | acpi_dev_present, NULL, NULL, &test); | ||
116 | if (!test) | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; | 100 | return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; |
120 | } | 101 | } |
121 | 102 | ||
122 | struct find_child_context { | 103 | struct acpi_device *acpi_find_child_device(struct acpi_device *parent, |
123 | u64 addr; | 104 | u64 address, bool check_children) |
124 | bool is_bridge; | ||
125 | acpi_handle ret; | ||
126 | int ret_score; | ||
127 | }; | ||
128 | |||
129 | static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, | ||
130 | void *data, void **not_used) | ||
131 | { | 105 | { |
132 | struct find_child_context *context = data; | 106 | struct acpi_device *adev, *ret = NULL; |
133 | unsigned long long addr; | 107 | int ret_score = 0; |
134 | acpi_status status; | 108 | |
135 | int score; | 109 | list_for_each_entry(adev, &parent->children, node) { |
136 | 110 | unsigned long long addr; | |
137 | status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); | 111 | acpi_status status; |
138 | if (ACPI_FAILURE(status) || addr != context->addr) | 112 | int score; |
139 | return AE_OK; | 113 | |
140 | 114 | status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, | |
141 | if (!context->ret) { | 115 | NULL, &addr); |
142 | /* This is the first matching object. Save its handle. */ | 116 | if (ACPI_FAILURE(status) || addr != address) |
143 | context->ret = handle; | 117 | continue; |
144 | return AE_OK; | 118 | |
145 | } | 119 | if (!ret) { |
146 | /* | 120 | /* This is the first matching object. Save it. */ |
147 | * There is more than one matching object with the same _ADR value. | 121 | ret = adev; |
148 | * That really is unexpected, so we are kind of beyond the scope of the | 122 | continue; |
149 | * spec here. We have to choose which one to return, though. | 123 | } |
150 | * | 124 | /* |
151 | * First, check if the previously found object is good enough and return | 125 | * There is more than one matching device object with the same |
152 | * its handle if so. Second, check the same for the object that we've | 126 | * _ADR value. That really is unexpected, so we are kind of |
153 | * just found. | 127 | * beyond the scope of the spec here. We have to choose which |
154 | */ | 128 | * one to return, though. |
155 | if (!context->ret_score) { | 129 | * |
156 | score = do_find_child_checks(context->ret, context->is_bridge); | 130 | * First, check if the previously found object is good enough |
157 | if (score == FIND_CHILD_MAX_SCORE) | 131 | * and return it if so. Second, do the same for the object that |
158 | return AE_CTRL_TERMINATE; | 132 | * we've just found. |
159 | else | 133 | */ |
160 | context->ret_score = score; | 134 | if (!ret_score) { |
161 | } | 135 | ret_score = find_child_checks(ret, check_children); |
162 | score = do_find_child_checks(handle, context->is_bridge); | 136 | if (ret_score == FIND_CHILD_MAX_SCORE) |
163 | if (score == FIND_CHILD_MAX_SCORE) { | 137 | return ret; |
164 | context->ret = handle; | 138 | } |
165 | return AE_CTRL_TERMINATE; | 139 | score = find_child_checks(adev, check_children); |
166 | } else if (score > context->ret_score) { | 140 | if (score == FIND_CHILD_MAX_SCORE) { |
167 | context->ret = handle; | 141 | return adev; |
168 | context->ret_score = score; | 142 | } else if (score > ret_score) { |
143 | ret = adev; | ||
144 | ret_score = score; | ||
145 | } | ||
169 | } | 146 | } |
170 | return AE_OK; | 147 | return ret; |
171 | } | 148 | } |
172 | 149 | ||
173 | acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) | 150 | acpi_handle acpi_find_child(acpi_handle handle, u64 addr, bool is_bridge) |
174 | { | 151 | { |
175 | if (parent) { | 152 | struct acpi_device *adev; |
176 | struct find_child_context context = { | 153 | |
177 | .addr = addr, | 154 | if (!handle || acpi_bus_get_device(handle, &adev)) |
178 | .is_bridge = is_bridge, | 155 | return NULL; |
179 | }; | 156 | |
180 | 157 | adev = acpi_find_child_device(adev, addr, is_bridge); | |
181 | acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child, | 158 | return adev ? adev->handle : NULL; |
182 | NULL, &context, NULL); | ||
183 | return context.ret; | ||
184 | } | ||
185 | return NULL; | ||
186 | } | 159 | } |
187 | EXPORT_SYMBOL_GPL(acpi_find_child); | 160 | EXPORT_SYMBOL_GPL(acpi_find_child); |
188 | 161 | ||