aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/glue.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-28 17:57:58 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-12-06 19:05:48 -0500
commitd9fef0c4d2e08c3888add77f1dc54fb12afb3928 (patch)
treed5492f76a4cb79f7c18415585095b60cc7d84fe4 /drivers/acpi/glue.c
parent9ccad66f0171578445175ecd3bf66b35a96aaf6e (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.c137
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
85static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, 85static 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
98static 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
122struct find_child_context { 103struct 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
129static 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
173acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) 150acpi_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}
187EXPORT_SYMBOL_GPL(acpi_find_child); 160EXPORT_SYMBOL_GPL(acpi_find_child);
188 161