aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/glue.c137
-rw-r--r--include/acpi/acpi_bus.h3
2 files changed, 58 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
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index b241b733052e..6d82c5c14c0f 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -431,6 +431,9 @@ struct acpi_pci_root {
431}; 431};
432 432
433/* helper */ 433/* helper */
434
435struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
436 u64 address, bool check_children);
434acpi_handle acpi_find_child(acpi_handle, u64, bool); 437acpi_handle acpi_find_child(acpi_handle, u64, bool);
435static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr) 438static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr)
436{ 439{