1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ACPI device specific properties support. |
4 | * |
5 | * Copyright (C) 2014, Intel Corporation |
6 | * All rights reserved. |
7 | * |
8 | * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> |
9 | * Darren Hart <dvhart@linux.intel.com> |
10 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
11 | */ |
12 | |
13 | #include <linux/acpi.h> |
14 | #include <linux/device.h> |
15 | #include <linux/export.h> |
16 | |
17 | #include "internal.h" |
18 | |
19 | static int acpi_data_get_property_array(const struct acpi_device_data *data, |
20 | const char *name, |
21 | acpi_object_type type, |
22 | const union acpi_object **obj); |
23 | |
24 | /* |
25 | * The GUIDs here are made equivalent to each other in order to avoid extra |
26 | * complexity in the properties handling code, with the caveat that the |
27 | * kernel will accept certain combinations of GUID and properties that are |
28 | * not defined without a warning. For instance if any of the properties |
29 | * from different GUID appear in a property list of another, it will be |
30 | * accepted by the kernel. Firmware validation tools should catch these. |
31 | */ |
32 | static const guid_t prp_guids[] = { |
33 | /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ |
34 | GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, |
35 | 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01), |
36 | /* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */ |
37 | GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3, |
38 | 0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4), |
39 | /* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */ |
40 | GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3, |
41 | 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89), |
42 | /* Thunderbolt GUID for IMR_VALID: c44d002f-69f9-4e7d-a904-a7baabdf43f7 */ |
43 | GUID_INIT(0xc44d002f, 0x69f9, 0x4e7d, |
44 | 0xa9, 0x04, 0xa7, 0xba, 0xab, 0xdf, 0x43, 0xf7), |
45 | /* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */ |
46 | GUID_INIT(0x6c501103, 0xc189, 0x4296, |
47 | 0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d), |
48 | /* Storage device needs D3 GUID: 5025030f-842f-4ab4-a561-99a5189762d0 */ |
49 | GUID_INIT(0x5025030f, 0x842f, 0x4ab4, |
50 | 0xa5, 0x61, 0x99, 0xa5, 0x18, 0x97, 0x62, 0xd0), |
51 | }; |
52 | |
53 | /* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */ |
54 | static const guid_t ads_guid = |
55 | GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6, |
56 | 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b); |
57 | |
58 | /* ACPI _DSD data buffer GUID: edb12dd0-363d-4085-a3d2-49522ca160c4 */ |
59 | static const guid_t buffer_prop_guid = |
60 | GUID_INIT(0xedb12dd0, 0x363d, 0x4085, |
61 | 0xa3, 0xd2, 0x49, 0x52, 0x2c, 0xa1, 0x60, 0xc4); |
62 | |
63 | static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, |
64 | union acpi_object *desc, |
65 | struct acpi_device_data *data, |
66 | struct fwnode_handle *parent); |
67 | static bool acpi_extract_properties(acpi_handle handle, |
68 | union acpi_object *desc, |
69 | struct acpi_device_data *data); |
70 | |
71 | static bool (union acpi_object *desc, |
72 | acpi_handle handle, |
73 | const union acpi_object *link, |
74 | struct list_head *list, |
75 | struct fwnode_handle *parent) |
76 | { |
77 | struct acpi_data_node *dn; |
78 | bool result; |
79 | |
80 | dn = kzalloc(size: sizeof(*dn), GFP_KERNEL); |
81 | if (!dn) |
82 | return false; |
83 | |
84 | dn->name = link->package.elements[0].string.pointer; |
85 | fwnode_init(fwnode: &dn->fwnode, ops: &acpi_data_fwnode_ops); |
86 | dn->parent = parent; |
87 | INIT_LIST_HEAD(list: &dn->data.properties); |
88 | INIT_LIST_HEAD(list: &dn->data.subnodes); |
89 | |
90 | result = acpi_extract_properties(handle, desc, data: &dn->data); |
91 | |
92 | if (handle) { |
93 | acpi_handle scope; |
94 | acpi_status status; |
95 | |
96 | /* |
97 | * The scope for the subnode object lookup is the one of the |
98 | * namespace node (device) containing the object that has |
99 | * returned the package. That is, it's the scope of that |
100 | * object's parent. |
101 | */ |
102 | status = acpi_get_parent(object: handle, out_handle: &scope); |
103 | if (ACPI_SUCCESS(status) |
104 | && acpi_enumerate_nondev_subnodes(scope, desc, data: &dn->data, |
105 | parent: &dn->fwnode)) |
106 | result = true; |
107 | } else if (acpi_enumerate_nondev_subnodes(NULL, desc, data: &dn->data, |
108 | parent: &dn->fwnode)) { |
109 | result = true; |
110 | } |
111 | |
112 | if (result) { |
113 | dn->handle = handle; |
114 | dn->data.pointer = desc; |
115 | list_add_tail(new: &dn->sibling, head: list); |
116 | return true; |
117 | } |
118 | |
119 | kfree(objp: dn); |
120 | acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n" ); |
121 | return false; |
122 | } |
123 | |
124 | static bool acpi_nondev_subnode_data_ok(acpi_handle handle, |
125 | const union acpi_object *link, |
126 | struct list_head *list, |
127 | struct fwnode_handle *parent) |
128 | { |
129 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; |
130 | acpi_status status; |
131 | |
132 | status = acpi_evaluate_object_typed(object: handle, NULL, NULL, return_buffer: &buf, |
133 | ACPI_TYPE_PACKAGE); |
134 | if (ACPI_FAILURE(status)) |
135 | return false; |
136 | |
137 | if (acpi_nondev_subnode_extract(desc: buf.pointer, handle, link, list, |
138 | parent)) |
139 | return true; |
140 | |
141 | ACPI_FREE(buf.pointer); |
142 | return false; |
143 | } |
144 | |
145 | static bool acpi_nondev_subnode_ok(acpi_handle scope, |
146 | const union acpi_object *link, |
147 | struct list_head *list, |
148 | struct fwnode_handle *parent) |
149 | { |
150 | acpi_handle handle; |
151 | acpi_status status; |
152 | |
153 | if (!scope) |
154 | return false; |
155 | |
156 | status = acpi_get_handle(parent: scope, pathname: link->package.elements[1].string.pointer, |
157 | ret_handle: &handle); |
158 | if (ACPI_FAILURE(status)) |
159 | return false; |
160 | |
161 | return acpi_nondev_subnode_data_ok(handle, link, list, parent); |
162 | } |
163 | |
164 | static bool acpi_add_nondev_subnodes(acpi_handle scope, |
165 | union acpi_object *links, |
166 | struct list_head *list, |
167 | struct fwnode_handle *parent) |
168 | { |
169 | bool ret = false; |
170 | int i; |
171 | |
172 | for (i = 0; i < links->package.count; i++) { |
173 | union acpi_object *link, *desc; |
174 | acpi_handle handle; |
175 | bool result; |
176 | |
177 | link = &links->package.elements[i]; |
178 | /* Only two elements allowed. */ |
179 | if (link->package.count != 2) |
180 | continue; |
181 | |
182 | /* The first one must be a string. */ |
183 | if (link->package.elements[0].type != ACPI_TYPE_STRING) |
184 | continue; |
185 | |
186 | /* The second one may be a string, a reference or a package. */ |
187 | switch (link->package.elements[1].type) { |
188 | case ACPI_TYPE_STRING: |
189 | result = acpi_nondev_subnode_ok(scope, link, list, |
190 | parent); |
191 | break; |
192 | case ACPI_TYPE_LOCAL_REFERENCE: |
193 | handle = link->package.elements[1].reference.handle; |
194 | result = acpi_nondev_subnode_data_ok(handle, link, list, |
195 | parent); |
196 | break; |
197 | case ACPI_TYPE_PACKAGE: |
198 | desc = &link->package.elements[1]; |
199 | result = acpi_nondev_subnode_extract(desc, NULL, link, |
200 | list, parent); |
201 | break; |
202 | default: |
203 | result = false; |
204 | break; |
205 | } |
206 | ret = ret || result; |
207 | } |
208 | |
209 | return ret; |
210 | } |
211 | |
212 | static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, |
213 | union acpi_object *desc, |
214 | struct acpi_device_data *data, |
215 | struct fwnode_handle *parent) |
216 | { |
217 | int i; |
218 | |
219 | /* Look for the ACPI data subnodes GUID. */ |
220 | for (i = 0; i < desc->package.count; i += 2) { |
221 | const union acpi_object *guid; |
222 | union acpi_object *links; |
223 | |
224 | guid = &desc->package.elements[i]; |
225 | links = &desc->package.elements[i + 1]; |
226 | |
227 | /* |
228 | * The first element must be a GUID and the second one must be |
229 | * a package. |
230 | */ |
231 | if (guid->type != ACPI_TYPE_BUFFER || |
232 | guid->buffer.length != 16 || |
233 | links->type != ACPI_TYPE_PACKAGE) |
234 | break; |
235 | |
236 | if (!guid_equal(u1: (guid_t *)guid->buffer.pointer, u2: &ads_guid)) |
237 | continue; |
238 | |
239 | return acpi_add_nondev_subnodes(scope, links, list: &data->subnodes, |
240 | parent); |
241 | } |
242 | |
243 | return false; |
244 | } |
245 | |
246 | static bool acpi_property_value_ok(const union acpi_object *value) |
247 | { |
248 | int j; |
249 | |
250 | /* |
251 | * The value must be an integer, a string, a reference, or a package |
252 | * whose every element must be an integer, a string, or a reference. |
253 | */ |
254 | switch (value->type) { |
255 | case ACPI_TYPE_INTEGER: |
256 | case ACPI_TYPE_STRING: |
257 | case ACPI_TYPE_LOCAL_REFERENCE: |
258 | return true; |
259 | |
260 | case ACPI_TYPE_PACKAGE: |
261 | for (j = 0; j < value->package.count; j++) |
262 | switch (value->package.elements[j].type) { |
263 | case ACPI_TYPE_INTEGER: |
264 | case ACPI_TYPE_STRING: |
265 | case ACPI_TYPE_LOCAL_REFERENCE: |
266 | continue; |
267 | |
268 | default: |
269 | return false; |
270 | } |
271 | |
272 | return true; |
273 | } |
274 | return false; |
275 | } |
276 | |
277 | static bool acpi_properties_format_valid(const union acpi_object *properties) |
278 | { |
279 | int i; |
280 | |
281 | for (i = 0; i < properties->package.count; i++) { |
282 | const union acpi_object *property; |
283 | |
284 | property = &properties->package.elements[i]; |
285 | /* |
286 | * Only two elements allowed, the first one must be a string and |
287 | * the second one has to satisfy certain conditions. |
288 | */ |
289 | if (property->package.count != 2 |
290 | || property->package.elements[0].type != ACPI_TYPE_STRING |
291 | || !acpi_property_value_ok(value: &property->package.elements[1])) |
292 | return false; |
293 | } |
294 | return true; |
295 | } |
296 | |
297 | static void acpi_init_of_compatible(struct acpi_device *adev) |
298 | { |
299 | const union acpi_object *of_compatible; |
300 | int ret; |
301 | |
302 | ret = acpi_data_get_property_array(data: &adev->data, name: "compatible" , |
303 | ACPI_TYPE_STRING, obj: &of_compatible); |
304 | if (ret) { |
305 | ret = acpi_dev_get_property(adev, name: "compatible" , |
306 | ACPI_TYPE_STRING, obj: &of_compatible); |
307 | if (ret) { |
308 | struct acpi_device *parent; |
309 | |
310 | parent = acpi_dev_parent(adev); |
311 | if (parent && parent->flags.of_compatible_ok) |
312 | goto out; |
313 | |
314 | return; |
315 | } |
316 | } |
317 | adev->data.of_compatible = of_compatible; |
318 | |
319 | out: |
320 | adev->flags.of_compatible_ok = 1; |
321 | } |
322 | |
323 | static bool acpi_is_property_guid(const guid_t *guid) |
324 | { |
325 | int i; |
326 | |
327 | for (i = 0; i < ARRAY_SIZE(prp_guids); i++) { |
328 | if (guid_equal(u1: guid, u2: &prp_guids[i])) |
329 | return true; |
330 | } |
331 | |
332 | return false; |
333 | } |
334 | |
335 | struct acpi_device_properties * |
336 | acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid, |
337 | union acpi_object *properties) |
338 | { |
339 | struct acpi_device_properties *props; |
340 | |
341 | props = kzalloc(size: sizeof(*props), GFP_KERNEL); |
342 | if (props) { |
343 | INIT_LIST_HEAD(list: &props->list); |
344 | props->guid = guid; |
345 | props->properties = properties; |
346 | list_add_tail(new: &props->list, head: &data->properties); |
347 | } |
348 | |
349 | return props; |
350 | } |
351 | |
352 | static void acpi_nondev_subnode_tag(acpi_handle handle, void *context) |
353 | { |
354 | } |
355 | |
356 | static void acpi_untie_nondev_subnodes(struct acpi_device_data *data) |
357 | { |
358 | struct acpi_data_node *dn; |
359 | |
360 | list_for_each_entry(dn, &data->subnodes, sibling) { |
361 | acpi_detach_data(object: dn->handle, handler: acpi_nondev_subnode_tag); |
362 | |
363 | acpi_untie_nondev_subnodes(data: &dn->data); |
364 | } |
365 | } |
366 | |
367 | static bool acpi_tie_nondev_subnodes(struct acpi_device_data *data) |
368 | { |
369 | struct acpi_data_node *dn; |
370 | |
371 | list_for_each_entry(dn, &data->subnodes, sibling) { |
372 | acpi_status status; |
373 | bool ret; |
374 | |
375 | status = acpi_attach_data(object: dn->handle, handler: acpi_nondev_subnode_tag, data: dn); |
376 | if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) { |
377 | acpi_handle_err(dn->handle, "Can't tag data node\n" ); |
378 | return false; |
379 | } |
380 | |
381 | ret = acpi_tie_nondev_subnodes(data: &dn->data); |
382 | if (!ret) |
383 | return ret; |
384 | } |
385 | |
386 | return true; |
387 | } |
388 | |
389 | static void acpi_data_add_buffer_props(acpi_handle handle, |
390 | struct acpi_device_data *data, |
391 | union acpi_object *properties) |
392 | { |
393 | struct acpi_device_properties *props; |
394 | union acpi_object *package; |
395 | size_t alloc_size; |
396 | unsigned int i; |
397 | u32 *count; |
398 | |
399 | if (check_mul_overflow((size_t)properties->package.count, |
400 | sizeof(*package) + sizeof(void *), |
401 | &alloc_size) || |
402 | check_add_overflow(sizeof(*props) + sizeof(*package), alloc_size, |
403 | &alloc_size)) { |
404 | acpi_handle_warn(handle, |
405 | "can't allocate memory for %u buffer props" , |
406 | properties->package.count); |
407 | return; |
408 | } |
409 | |
410 | props = kvzalloc(size: alloc_size, GFP_KERNEL); |
411 | if (!props) |
412 | return; |
413 | |
414 | props->guid = &buffer_prop_guid; |
415 | props->bufs = (void *)(props + 1); |
416 | props->properties = (void *)(props->bufs + properties->package.count); |
417 | |
418 | /* Outer package */ |
419 | package = props->properties; |
420 | package->type = ACPI_TYPE_PACKAGE; |
421 | package->package.elements = package + 1; |
422 | count = &package->package.count; |
423 | *count = 0; |
424 | |
425 | /* Inner packages */ |
426 | package++; |
427 | |
428 | for (i = 0; i < properties->package.count; i++) { |
429 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; |
430 | union acpi_object *property = &properties->package.elements[i]; |
431 | union acpi_object *prop, *obj, *buf_obj; |
432 | acpi_status status; |
433 | |
434 | if (property->type != ACPI_TYPE_PACKAGE || |
435 | property->package.count != 2) { |
436 | acpi_handle_warn(handle, |
437 | "buffer property %u has %u entries\n" , |
438 | i, property->package.count); |
439 | continue; |
440 | } |
441 | |
442 | prop = &property->package.elements[0]; |
443 | obj = &property->package.elements[1]; |
444 | |
445 | if (prop->type != ACPI_TYPE_STRING || |
446 | obj->type != ACPI_TYPE_STRING) { |
447 | acpi_handle_warn(handle, |
448 | "wrong object types %u and %u\n" , |
449 | prop->type, obj->type); |
450 | continue; |
451 | } |
452 | |
453 | status = acpi_evaluate_object_typed(object: handle, pathname: obj->string.pointer, |
454 | NULL, return_buffer: &buf, |
455 | ACPI_TYPE_BUFFER); |
456 | if (ACPI_FAILURE(status)) { |
457 | acpi_handle_warn(handle, |
458 | "can't evaluate \"%*pE\" as buffer\n" , |
459 | obj->string.length, |
460 | obj->string.pointer); |
461 | continue; |
462 | } |
463 | |
464 | package->type = ACPI_TYPE_PACKAGE; |
465 | package->package.elements = prop; |
466 | package->package.count = 2; |
467 | |
468 | buf_obj = buf.pointer; |
469 | |
470 | /* Replace the string object with a buffer object */ |
471 | obj->type = ACPI_TYPE_BUFFER; |
472 | obj->buffer.length = buf_obj->buffer.length; |
473 | obj->buffer.pointer = buf_obj->buffer.pointer; |
474 | |
475 | props->bufs[i] = buf.pointer; |
476 | package++; |
477 | (*count)++; |
478 | } |
479 | |
480 | if (*count) |
481 | list_add(new: &props->list, head: &data->properties); |
482 | else |
483 | kvfree(addr: props); |
484 | } |
485 | |
486 | static bool (acpi_handle scope, union acpi_object *desc, |
487 | struct acpi_device_data *data) |
488 | { |
489 | int i; |
490 | |
491 | if (desc->package.count % 2) |
492 | return false; |
493 | |
494 | /* Look for the device properties GUID. */ |
495 | for (i = 0; i < desc->package.count; i += 2) { |
496 | const union acpi_object *guid; |
497 | union acpi_object *properties; |
498 | |
499 | guid = &desc->package.elements[i]; |
500 | properties = &desc->package.elements[i + 1]; |
501 | |
502 | /* |
503 | * The first element must be a GUID and the second one must be |
504 | * a package. |
505 | */ |
506 | if (guid->type != ACPI_TYPE_BUFFER || |
507 | guid->buffer.length != 16 || |
508 | properties->type != ACPI_TYPE_PACKAGE) |
509 | break; |
510 | |
511 | if (guid_equal(u1: (guid_t *)guid->buffer.pointer, |
512 | u2: &buffer_prop_guid)) { |
513 | acpi_data_add_buffer_props(handle: scope, data, properties); |
514 | continue; |
515 | } |
516 | |
517 | if (!acpi_is_property_guid(guid: (guid_t *)guid->buffer.pointer)) |
518 | continue; |
519 | |
520 | /* |
521 | * We found the matching GUID. Now validate the format of the |
522 | * package immediately following it. |
523 | */ |
524 | if (!acpi_properties_format_valid(properties)) |
525 | continue; |
526 | |
527 | acpi_data_add_props(data, guid: (const guid_t *)guid->buffer.pointer, |
528 | properties); |
529 | } |
530 | |
531 | return !list_empty(head: &data->properties); |
532 | } |
533 | |
534 | void acpi_init_properties(struct acpi_device *adev) |
535 | { |
536 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; |
537 | struct acpi_hardware_id *hwid; |
538 | acpi_status status; |
539 | bool acpi_of = false; |
540 | |
541 | INIT_LIST_HEAD(list: &adev->data.properties); |
542 | INIT_LIST_HEAD(list: &adev->data.subnodes); |
543 | |
544 | if (!adev->handle) |
545 | return; |
546 | |
547 | /* |
548 | * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in |
549 | * Device Tree compatible properties for this device. |
550 | */ |
551 | list_for_each_entry(hwid, &adev->pnp.ids, list) { |
552 | if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) { |
553 | acpi_of = true; |
554 | break; |
555 | } |
556 | } |
557 | |
558 | status = acpi_evaluate_object_typed(object: adev->handle, pathname: "_DSD" , NULL, return_buffer: &buf, |
559 | ACPI_TYPE_PACKAGE); |
560 | if (ACPI_FAILURE(status)) |
561 | goto out; |
562 | |
563 | if (acpi_extract_properties(scope: adev->handle, desc: buf.pointer, data: &adev->data)) { |
564 | adev->data.pointer = buf.pointer; |
565 | if (acpi_of) |
566 | acpi_init_of_compatible(adev); |
567 | } |
568 | if (acpi_enumerate_nondev_subnodes(scope: adev->handle, desc: buf.pointer, |
569 | data: &adev->data, parent: acpi_fwnode_handle(adev))) |
570 | adev->data.pointer = buf.pointer; |
571 | |
572 | if (!adev->data.pointer) { |
573 | acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n" ); |
574 | ACPI_FREE(buf.pointer); |
575 | } else { |
576 | if (!acpi_tie_nondev_subnodes(data: &adev->data)) |
577 | acpi_untie_nondev_subnodes(data: &adev->data); |
578 | } |
579 | |
580 | out: |
581 | if (acpi_of && !adev->flags.of_compatible_ok) |
582 | acpi_handle_info(adev->handle, |
583 | ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n" ); |
584 | |
585 | if (!adev->data.pointer) |
586 | acpi_extract_apple_properties(adev); |
587 | } |
588 | |
589 | static void acpi_free_device_properties(struct list_head *list) |
590 | { |
591 | struct acpi_device_properties *props, *tmp; |
592 | |
593 | list_for_each_entry_safe(props, tmp, list, list) { |
594 | u32 i; |
595 | |
596 | list_del(entry: &props->list); |
597 | /* Buffer data properties were separately allocated */ |
598 | if (props->bufs) |
599 | for (i = 0; i < props->properties->package.count; i++) |
600 | ACPI_FREE(props->bufs[i]); |
601 | kvfree(addr: props); |
602 | } |
603 | } |
604 | |
605 | static void acpi_destroy_nondev_subnodes(struct list_head *list) |
606 | { |
607 | struct acpi_data_node *dn, *next; |
608 | |
609 | if (list_empty(head: list)) |
610 | return; |
611 | |
612 | list_for_each_entry_safe_reverse(dn, next, list, sibling) { |
613 | acpi_destroy_nondev_subnodes(list: &dn->data.subnodes); |
614 | wait_for_completion(&dn->kobj_done); |
615 | list_del(entry: &dn->sibling); |
616 | ACPI_FREE((void *)dn->data.pointer); |
617 | acpi_free_device_properties(list: &dn->data.properties); |
618 | kfree(objp: dn); |
619 | } |
620 | } |
621 | |
622 | void acpi_free_properties(struct acpi_device *adev) |
623 | { |
624 | acpi_untie_nondev_subnodes(data: &adev->data); |
625 | acpi_destroy_nondev_subnodes(list: &adev->data.subnodes); |
626 | ACPI_FREE((void *)adev->data.pointer); |
627 | adev->data.of_compatible = NULL; |
628 | adev->data.pointer = NULL; |
629 | acpi_free_device_properties(list: &adev->data.properties); |
630 | } |
631 | |
632 | /** |
633 | * acpi_data_get_property - return an ACPI property with given name |
634 | * @data: ACPI device deta object to get the property from |
635 | * @name: Name of the property |
636 | * @type: Expected property type |
637 | * @obj: Location to store the property value (if not %NULL) |
638 | * |
639 | * Look up a property with @name and store a pointer to the resulting ACPI |
640 | * object at the location pointed to by @obj if found. |
641 | * |
642 | * Callers must not attempt to free the returned objects. These objects will be |
643 | * freed by the ACPI core automatically during the removal of @data. |
644 | * |
645 | * Return: %0 if property with @name has been found (success), |
646 | * %-EINVAL if the arguments are invalid, |
647 | * %-EINVAL if the property doesn't exist, |
648 | * %-EPROTO if the property value type doesn't match @type. |
649 | */ |
650 | static int acpi_data_get_property(const struct acpi_device_data *data, |
651 | const char *name, acpi_object_type type, |
652 | const union acpi_object **obj) |
653 | { |
654 | const struct acpi_device_properties *props; |
655 | |
656 | if (!data || !name) |
657 | return -EINVAL; |
658 | |
659 | if (!data->pointer || list_empty(head: &data->properties)) |
660 | return -EINVAL; |
661 | |
662 | list_for_each_entry(props, &data->properties, list) { |
663 | const union acpi_object *properties; |
664 | unsigned int i; |
665 | |
666 | properties = props->properties; |
667 | for (i = 0; i < properties->package.count; i++) { |
668 | const union acpi_object *propname, *propvalue; |
669 | const union acpi_object *property; |
670 | |
671 | property = &properties->package.elements[i]; |
672 | |
673 | propname = &property->package.elements[0]; |
674 | propvalue = &property->package.elements[1]; |
675 | |
676 | if (!strcmp(name, propname->string.pointer)) { |
677 | if (type != ACPI_TYPE_ANY && |
678 | propvalue->type != type) |
679 | return -EPROTO; |
680 | if (obj) |
681 | *obj = propvalue; |
682 | |
683 | return 0; |
684 | } |
685 | } |
686 | } |
687 | return -EINVAL; |
688 | } |
689 | |
690 | /** |
691 | * acpi_dev_get_property - return an ACPI property with given name. |
692 | * @adev: ACPI device to get the property from. |
693 | * @name: Name of the property. |
694 | * @type: Expected property type. |
695 | * @obj: Location to store the property value (if not %NULL). |
696 | */ |
697 | int acpi_dev_get_property(const struct acpi_device *adev, const char *name, |
698 | acpi_object_type type, const union acpi_object **obj) |
699 | { |
700 | return adev ? acpi_data_get_property(data: &adev->data, name, type, obj) : -EINVAL; |
701 | } |
702 | EXPORT_SYMBOL_GPL(acpi_dev_get_property); |
703 | |
704 | static const struct acpi_device_data * |
705 | acpi_device_data_of_node(const struct fwnode_handle *fwnode) |
706 | { |
707 | if (is_acpi_device_node(fwnode)) { |
708 | const struct acpi_device *adev = to_acpi_device_node(fwnode); |
709 | return &adev->data; |
710 | } |
711 | if (is_acpi_data_node(fwnode)) { |
712 | const struct acpi_data_node *dn = to_acpi_data_node(fwnode); |
713 | return &dn->data; |
714 | } |
715 | return NULL; |
716 | } |
717 | |
718 | /** |
719 | * acpi_node_prop_get - return an ACPI property with given name. |
720 | * @fwnode: Firmware node to get the property from. |
721 | * @propname: Name of the property. |
722 | * @valptr: Location to store a pointer to the property value (if not %NULL). |
723 | */ |
724 | int acpi_node_prop_get(const struct fwnode_handle *fwnode, |
725 | const char *propname, void **valptr) |
726 | { |
727 | return acpi_data_get_property(data: acpi_device_data_of_node(fwnode), |
728 | name: propname, ACPI_TYPE_ANY, |
729 | obj: (const union acpi_object **)valptr); |
730 | } |
731 | |
732 | /** |
733 | * acpi_data_get_property_array - return an ACPI array property with given name |
734 | * @data: ACPI data object to get the property from |
735 | * @name: Name of the property |
736 | * @type: Expected type of array elements |
737 | * @obj: Location to store a pointer to the property value (if not NULL) |
738 | * |
739 | * Look up an array property with @name and store a pointer to the resulting |
740 | * ACPI object at the location pointed to by @obj if found. |
741 | * |
742 | * Callers must not attempt to free the returned objects. Those objects will be |
743 | * freed by the ACPI core automatically during the removal of @data. |
744 | * |
745 | * Return: %0 if array property (package) with @name has been found (success), |
746 | * %-EINVAL if the arguments are invalid, |
747 | * %-EINVAL if the property doesn't exist, |
748 | * %-EPROTO if the property is not a package or the type of its elements |
749 | * doesn't match @type. |
750 | */ |
751 | static int acpi_data_get_property_array(const struct acpi_device_data *data, |
752 | const char *name, |
753 | acpi_object_type type, |
754 | const union acpi_object **obj) |
755 | { |
756 | const union acpi_object *prop; |
757 | int ret, i; |
758 | |
759 | ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, obj: &prop); |
760 | if (ret) |
761 | return ret; |
762 | |
763 | if (type != ACPI_TYPE_ANY) { |
764 | /* Check that all elements are of correct type. */ |
765 | for (i = 0; i < prop->package.count; i++) |
766 | if (prop->package.elements[i].type != type) |
767 | return -EPROTO; |
768 | } |
769 | if (obj) |
770 | *obj = prop; |
771 | |
772 | return 0; |
773 | } |
774 | |
775 | static struct fwnode_handle * |
776 | acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, |
777 | const char *childname) |
778 | { |
779 | struct fwnode_handle *child; |
780 | |
781 | fwnode_for_each_child_node(fwnode, child) { |
782 | if (is_acpi_data_node(fwnode: child)) { |
783 | if (acpi_data_node_match(fwnode: child, name: childname)) |
784 | return child; |
785 | continue; |
786 | } |
787 | |
788 | if (!strncmp(acpi_device_bid(to_acpi_device_node(child)), |
789 | childname, ACPI_NAMESEG_SIZE)) |
790 | return child; |
791 | } |
792 | |
793 | return NULL; |
794 | } |
795 | |
796 | static int acpi_get_ref_args(struct fwnode_reference_args *args, |
797 | struct fwnode_handle *ref_fwnode, |
798 | const union acpi_object **element, |
799 | const union acpi_object *end, size_t num_args) |
800 | { |
801 | u32 nargs = 0, i; |
802 | |
803 | /* |
804 | * Find the referred data extension node under the |
805 | * referred device node. |
806 | */ |
807 | for (; *element < end && (*element)->type == ACPI_TYPE_STRING; |
808 | (*element)++) { |
809 | const char *child_name = (*element)->string.pointer; |
810 | |
811 | ref_fwnode = acpi_fwnode_get_named_child_node(fwnode: ref_fwnode, childname: child_name); |
812 | if (!ref_fwnode) |
813 | return -EINVAL; |
814 | } |
815 | |
816 | /* |
817 | * Assume the following integer elements are all args. Stop counting on |
818 | * the first reference or end of the package arguments. In case of |
819 | * neither reference, nor integer, return an error, we can't parse it. |
820 | */ |
821 | for (i = 0; (*element) + i < end && i < num_args; i++) { |
822 | acpi_object_type type = (*element)[i].type; |
823 | |
824 | if (type == ACPI_TYPE_LOCAL_REFERENCE) |
825 | break; |
826 | |
827 | if (type == ACPI_TYPE_INTEGER) |
828 | nargs++; |
829 | else |
830 | return -EINVAL; |
831 | } |
832 | |
833 | if (nargs > NR_FWNODE_REFERENCE_ARGS) |
834 | return -EINVAL; |
835 | |
836 | if (args) { |
837 | args->fwnode = ref_fwnode; |
838 | args->nargs = nargs; |
839 | for (i = 0; i < nargs; i++) |
840 | args->args[i] = (*element)[i].integer.value; |
841 | } |
842 | |
843 | (*element) += nargs; |
844 | |
845 | return 0; |
846 | } |
847 | |
848 | /** |
849 | * __acpi_node_get_property_reference - returns handle to the referenced object |
850 | * @fwnode: Firmware node to get the property from |
851 | * @propname: Name of the property |
852 | * @index: Index of the reference to return |
853 | * @num_args: Maximum number of arguments after each reference |
854 | * @args: Location to store the returned reference with optional arguments |
855 | * |
856 | * Find property with @name, verifify that it is a package containing at least |
857 | * one object reference and if so, store the ACPI device object pointer to the |
858 | * target object in @args->adev. If the reference includes arguments, store |
859 | * them in the @args->args[] array. |
860 | * |
861 | * If there's more than one reference in the property value package, @index is |
862 | * used to select the one to return. |
863 | * |
864 | * It is possible to leave holes in the property value set like in the |
865 | * example below: |
866 | * |
867 | * Package () { |
868 | * "cs-gpios", |
869 | * Package () { |
870 | * ^GPIO, 19, 0, 0, |
871 | * ^GPIO, 20, 0, 0, |
872 | * 0, |
873 | * ^GPIO, 21, 0, 0, |
874 | * } |
875 | * } |
876 | * |
877 | * Calling this function with index %2 or index %3 return %-ENOENT. If the |
878 | * property does not contain any more values %-ENOENT is returned. The NULL |
879 | * entry must be single integer and preferably contain value %0. |
880 | * |
881 | * Return: %0 on success, negative error code on failure. |
882 | */ |
883 | int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, |
884 | const char *propname, size_t index, size_t num_args, |
885 | struct fwnode_reference_args *args) |
886 | { |
887 | const union acpi_object *element, *end; |
888 | const union acpi_object *obj; |
889 | const struct acpi_device_data *data; |
890 | struct acpi_device *device; |
891 | int ret, idx = 0; |
892 | |
893 | data = acpi_device_data_of_node(fwnode); |
894 | if (!data) |
895 | return -ENOENT; |
896 | |
897 | ret = acpi_data_get_property(data, name: propname, ACPI_TYPE_ANY, obj: &obj); |
898 | if (ret) |
899 | return ret == -EINVAL ? -ENOENT : -EINVAL; |
900 | |
901 | switch (obj->type) { |
902 | case ACPI_TYPE_LOCAL_REFERENCE: |
903 | /* Plain single reference without arguments. */ |
904 | if (index) |
905 | return -ENOENT; |
906 | |
907 | device = acpi_fetch_acpi_dev(handle: obj->reference.handle); |
908 | if (!device) |
909 | return -EINVAL; |
910 | |
911 | args->fwnode = acpi_fwnode_handle(adev: device); |
912 | args->nargs = 0; |
913 | return 0; |
914 | case ACPI_TYPE_PACKAGE: |
915 | /* |
916 | * If it is not a single reference, then it is a package of |
917 | * references followed by number of ints as follows: |
918 | * |
919 | * Package () { REF, INT, REF, INT, INT } |
920 | * |
921 | * The index argument is then used to determine which reference |
922 | * the caller wants (along with the arguments). |
923 | */ |
924 | break; |
925 | default: |
926 | return -EINVAL; |
927 | } |
928 | |
929 | if (index >= obj->package.count) |
930 | return -ENOENT; |
931 | |
932 | element = obj->package.elements; |
933 | end = element + obj->package.count; |
934 | |
935 | while (element < end) { |
936 | switch (element->type) { |
937 | case ACPI_TYPE_LOCAL_REFERENCE: |
938 | device = acpi_fetch_acpi_dev(handle: element->reference.handle); |
939 | if (!device) |
940 | return -EINVAL; |
941 | |
942 | element++; |
943 | |
944 | ret = acpi_get_ref_args(args: idx == index ? args : NULL, |
945 | ref_fwnode: acpi_fwnode_handle(adev: device), |
946 | element: &element, end, num_args); |
947 | if (ret < 0) |
948 | return ret; |
949 | |
950 | if (idx == index) |
951 | return 0; |
952 | |
953 | break; |
954 | case ACPI_TYPE_INTEGER: |
955 | if (idx == index) |
956 | return -ENOENT; |
957 | element++; |
958 | break; |
959 | default: |
960 | return -EINVAL; |
961 | } |
962 | |
963 | idx++; |
964 | } |
965 | |
966 | return -ENOENT; |
967 | } |
968 | EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference); |
969 | |
970 | static int acpi_data_prop_read_single(const struct acpi_device_data *data, |
971 | const char *propname, |
972 | enum dev_prop_type proptype, void *val) |
973 | { |
974 | const union acpi_object *obj; |
975 | int ret = 0; |
976 | |
977 | if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) |
978 | ret = acpi_data_get_property(data, name: propname, ACPI_TYPE_INTEGER, obj: &obj); |
979 | else if (proptype == DEV_PROP_STRING) |
980 | ret = acpi_data_get_property(data, name: propname, ACPI_TYPE_STRING, obj: &obj); |
981 | if (ret) |
982 | return ret; |
983 | |
984 | switch (proptype) { |
985 | case DEV_PROP_U8: |
986 | if (obj->integer.value > U8_MAX) |
987 | return -EOVERFLOW; |
988 | if (val) |
989 | *(u8 *)val = obj->integer.value; |
990 | break; |
991 | case DEV_PROP_U16: |
992 | if (obj->integer.value > U16_MAX) |
993 | return -EOVERFLOW; |
994 | if (val) |
995 | *(u16 *)val = obj->integer.value; |
996 | break; |
997 | case DEV_PROP_U32: |
998 | if (obj->integer.value > U32_MAX) |
999 | return -EOVERFLOW; |
1000 | if (val) |
1001 | *(u32 *)val = obj->integer.value; |
1002 | break; |
1003 | case DEV_PROP_U64: |
1004 | if (val) |
1005 | *(u64 *)val = obj->integer.value; |
1006 | break; |
1007 | case DEV_PROP_STRING: |
1008 | if (val) |
1009 | *(char **)val = obj->string.pointer; |
1010 | return 1; |
1011 | default: |
1012 | return -EINVAL; |
1013 | } |
1014 | |
1015 | /* When no storage provided return number of available values */ |
1016 | return val ? 0 : 1; |
1017 | } |
1018 | |
1019 | #define acpi_copy_property_array_uint(items, val, nval) \ |
1020 | ({ \ |
1021 | typeof(items) __items = items; \ |
1022 | typeof(val) __val = val; \ |
1023 | typeof(nval) __nval = nval; \ |
1024 | size_t i; \ |
1025 | int ret = 0; \ |
1026 | \ |
1027 | for (i = 0; i < __nval; i++) { \ |
1028 | if (__items->type == ACPI_TYPE_BUFFER) { \ |
1029 | __val[i] = __items->buffer.pointer[i]; \ |
1030 | continue; \ |
1031 | } \ |
1032 | if (__items[i].type != ACPI_TYPE_INTEGER) { \ |
1033 | ret = -EPROTO; \ |
1034 | break; \ |
1035 | } \ |
1036 | if (__items[i].integer.value > _Generic(__val, \ |
1037 | u8 *: U8_MAX, \ |
1038 | u16 *: U16_MAX, \ |
1039 | u32 *: U32_MAX, \ |
1040 | u64 *: U64_MAX)) { \ |
1041 | ret = -EOVERFLOW; \ |
1042 | break; \ |
1043 | } \ |
1044 | \ |
1045 | __val[i] = __items[i].integer.value; \ |
1046 | } \ |
1047 | ret; \ |
1048 | }) |
1049 | |
1050 | static int acpi_copy_property_array_string(const union acpi_object *items, |
1051 | char **val, size_t nval) |
1052 | { |
1053 | int i; |
1054 | |
1055 | for (i = 0; i < nval; i++) { |
1056 | if (items[i].type != ACPI_TYPE_STRING) |
1057 | return -EPROTO; |
1058 | |
1059 | val[i] = items[i].string.pointer; |
1060 | } |
1061 | return nval; |
1062 | } |
1063 | |
1064 | static int acpi_data_prop_read(const struct acpi_device_data *data, |
1065 | const char *propname, |
1066 | enum dev_prop_type proptype, |
1067 | void *val, size_t nval) |
1068 | { |
1069 | const union acpi_object *obj; |
1070 | const union acpi_object *items; |
1071 | int ret; |
1072 | |
1073 | if (nval == 1 || !val) { |
1074 | ret = acpi_data_prop_read_single(data, propname, proptype, val); |
1075 | /* |
1076 | * The overflow error means that the property is there and it is |
1077 | * single-value, but its type does not match, so return. |
1078 | */ |
1079 | if (ret >= 0 || ret == -EOVERFLOW) |
1080 | return ret; |
1081 | |
1082 | /* |
1083 | * Reading this property as a single-value one failed, but its |
1084 | * value may still be represented as one-element array, so |
1085 | * continue. |
1086 | */ |
1087 | } |
1088 | |
1089 | ret = acpi_data_get_property_array(data, name: propname, ACPI_TYPE_ANY, obj: &obj); |
1090 | if (ret && proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) |
1091 | ret = acpi_data_get_property(data, name: propname, ACPI_TYPE_BUFFER, |
1092 | obj: &obj); |
1093 | if (ret) |
1094 | return ret; |
1095 | |
1096 | if (!val) { |
1097 | if (obj->type == ACPI_TYPE_BUFFER) |
1098 | return obj->buffer.length; |
1099 | |
1100 | return obj->package.count; |
1101 | } |
1102 | |
1103 | switch (proptype) { |
1104 | case DEV_PROP_STRING: |
1105 | break; |
1106 | default: |
1107 | if (obj->type == ACPI_TYPE_BUFFER) { |
1108 | if (nval > obj->buffer.length) |
1109 | return -EOVERFLOW; |
1110 | } else { |
1111 | if (nval > obj->package.count) |
1112 | return -EOVERFLOW; |
1113 | } |
1114 | break; |
1115 | } |
1116 | if (nval == 0) |
1117 | return -EINVAL; |
1118 | |
1119 | if (obj->type == ACPI_TYPE_BUFFER) { |
1120 | if (proptype != DEV_PROP_U8) |
1121 | return -EPROTO; |
1122 | items = obj; |
1123 | } else { |
1124 | items = obj->package.elements; |
1125 | } |
1126 | |
1127 | switch (proptype) { |
1128 | case DEV_PROP_U8: |
1129 | ret = acpi_copy_property_array_uint(items, (u8 *)val, nval); |
1130 | break; |
1131 | case DEV_PROP_U16: |
1132 | ret = acpi_copy_property_array_uint(items, (u16 *)val, nval); |
1133 | break; |
1134 | case DEV_PROP_U32: |
1135 | ret = acpi_copy_property_array_uint(items, (u32 *)val, nval); |
1136 | break; |
1137 | case DEV_PROP_U64: |
1138 | ret = acpi_copy_property_array_uint(items, (u64 *)val, nval); |
1139 | break; |
1140 | case DEV_PROP_STRING: |
1141 | ret = acpi_copy_property_array_string( |
1142 | items, val: (char **)val, |
1143 | min_t(u32, nval, obj->package.count)); |
1144 | break; |
1145 | default: |
1146 | ret = -EINVAL; |
1147 | break; |
1148 | } |
1149 | return ret; |
1150 | } |
1151 | |
1152 | /** |
1153 | * acpi_node_prop_read - retrieve the value of an ACPI property with given name. |
1154 | * @fwnode: Firmware node to get the property from. |
1155 | * @propname: Name of the property. |
1156 | * @proptype: Expected property type. |
1157 | * @val: Location to store the property value (if not %NULL). |
1158 | * @nval: Size of the array pointed to by @val. |
1159 | * |
1160 | * If @val is %NULL, return the number of array elements comprising the value |
1161 | * of the property. Otherwise, read at most @nval values to the array at the |
1162 | * location pointed to by @val. |
1163 | */ |
1164 | static int acpi_node_prop_read(const struct fwnode_handle *fwnode, |
1165 | const char *propname, enum dev_prop_type proptype, |
1166 | void *val, size_t nval) |
1167 | { |
1168 | return acpi_data_prop_read(data: acpi_device_data_of_node(fwnode), |
1169 | propname, proptype, val, nval); |
1170 | } |
1171 | |
1172 | static int stop_on_next(struct acpi_device *adev, void *data) |
1173 | { |
1174 | struct acpi_device **ret_p = data; |
1175 | |
1176 | if (!*ret_p) { |
1177 | *ret_p = adev; |
1178 | return 1; |
1179 | } |
1180 | |
1181 | /* Skip until the "previous" object is found. */ |
1182 | if (*ret_p == adev) |
1183 | *ret_p = NULL; |
1184 | |
1185 | return 0; |
1186 | } |
1187 | |
1188 | /** |
1189 | * acpi_get_next_subnode - Return the next child node handle for a fwnode |
1190 | * @fwnode: Firmware node to find the next child node for. |
1191 | * @child: Handle to one of the device's child nodes or a null handle. |
1192 | */ |
1193 | struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode, |
1194 | struct fwnode_handle *child) |
1195 | { |
1196 | struct acpi_device *adev = to_acpi_device_node(fwnode); |
1197 | |
1198 | if ((!child || is_acpi_device_node(fwnode: child)) && adev) { |
1199 | struct acpi_device *child_adev = to_acpi_device_node(child); |
1200 | |
1201 | acpi_dev_for_each_child(adev, fn: stop_on_next, data: &child_adev); |
1202 | if (child_adev) |
1203 | return acpi_fwnode_handle(adev: child_adev); |
1204 | |
1205 | child = NULL; |
1206 | } |
1207 | |
1208 | if (!child || is_acpi_data_node(fwnode: child)) { |
1209 | const struct acpi_data_node *data = to_acpi_data_node(fwnode); |
1210 | const struct list_head *head; |
1211 | struct list_head *next; |
1212 | struct acpi_data_node *dn; |
1213 | |
1214 | /* |
1215 | * We can have a combination of device and data nodes, e.g. with |
1216 | * hierarchical _DSD properties. Make sure the adev pointer is |
1217 | * restored before going through data nodes, otherwise we will |
1218 | * be looking for data_nodes below the last device found instead |
1219 | * of the common fwnode shared by device_nodes and data_nodes. |
1220 | */ |
1221 | adev = to_acpi_device_node(fwnode); |
1222 | if (adev) |
1223 | head = &adev->data.subnodes; |
1224 | else if (data) |
1225 | head = &data->data.subnodes; |
1226 | else |
1227 | return NULL; |
1228 | |
1229 | if (list_empty(head)) |
1230 | return NULL; |
1231 | |
1232 | if (child) { |
1233 | dn = to_acpi_data_node(child); |
1234 | next = dn->sibling.next; |
1235 | if (next == head) |
1236 | return NULL; |
1237 | |
1238 | dn = list_entry(next, struct acpi_data_node, sibling); |
1239 | } else { |
1240 | dn = list_first_entry(head, struct acpi_data_node, sibling); |
1241 | } |
1242 | return &dn->fwnode; |
1243 | } |
1244 | return NULL; |
1245 | } |
1246 | |
1247 | /** |
1248 | * acpi_node_get_parent - Return parent fwnode of this fwnode |
1249 | * @fwnode: Firmware node whose parent to get |
1250 | * |
1251 | * Returns parent node of an ACPI device or data firmware node or %NULL if |
1252 | * not available. |
1253 | */ |
1254 | static struct fwnode_handle * |
1255 | acpi_node_get_parent(const struct fwnode_handle *fwnode) |
1256 | { |
1257 | if (is_acpi_data_node(fwnode)) { |
1258 | /* All data nodes have parent pointer so just return that */ |
1259 | return to_acpi_data_node(fwnode)->parent; |
1260 | } |
1261 | if (is_acpi_device_node(fwnode)) { |
1262 | struct acpi_device *parent; |
1263 | |
1264 | parent = acpi_dev_parent(to_acpi_device_node(fwnode)); |
1265 | if (parent) |
1266 | return acpi_fwnode_handle(adev: parent); |
1267 | } |
1268 | |
1269 | return NULL; |
1270 | } |
1271 | |
1272 | /* |
1273 | * Return true if the node is an ACPI graph node. Called on either ports |
1274 | * or endpoints. |
1275 | */ |
1276 | static bool is_acpi_graph_node(struct fwnode_handle *fwnode, |
1277 | const char *str) |
1278 | { |
1279 | unsigned int len = strlen(str); |
1280 | const char *name; |
1281 | |
1282 | if (!len || !is_acpi_data_node(fwnode)) |
1283 | return false; |
1284 | |
1285 | name = to_acpi_data_node(fwnode)->name; |
1286 | |
1287 | return (fwnode_property_present(fwnode, propname: "reg" ) && |
1288 | !strncmp(name, str, len) && name[len] == '@') || |
1289 | fwnode_property_present(fwnode, propname: str); |
1290 | } |
1291 | |
1292 | /** |
1293 | * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node |
1294 | * @fwnode: Pointer to the parent firmware node |
1295 | * @prev: Previous endpoint node or %NULL to get the first |
1296 | * |
1297 | * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns |
1298 | * %NULL if there is no next endpoint or in case of error. In case of success |
1299 | * the next endpoint is returned. |
1300 | */ |
1301 | static struct fwnode_handle *acpi_graph_get_next_endpoint( |
1302 | const struct fwnode_handle *fwnode, struct fwnode_handle *prev) |
1303 | { |
1304 | struct fwnode_handle *port = NULL; |
1305 | struct fwnode_handle *endpoint; |
1306 | |
1307 | if (!prev) { |
1308 | do { |
1309 | port = fwnode_get_next_child_node(fwnode, child: port); |
1310 | /* |
1311 | * The names of the port nodes begin with "port@" |
1312 | * followed by the number of the port node and they also |
1313 | * have a "reg" property that also has the number of the |
1314 | * port node. For compatibility reasons a node is also |
1315 | * recognised as a port node from the "port" property. |
1316 | */ |
1317 | if (is_acpi_graph_node(fwnode: port, str: "port" )) |
1318 | break; |
1319 | } while (port); |
1320 | } else { |
1321 | port = fwnode_get_parent(fwnode: prev); |
1322 | } |
1323 | |
1324 | if (!port) |
1325 | return NULL; |
1326 | |
1327 | endpoint = fwnode_get_next_child_node(fwnode: port, child: prev); |
1328 | while (!endpoint) { |
1329 | port = fwnode_get_next_child_node(fwnode, child: port); |
1330 | if (!port) |
1331 | break; |
1332 | if (is_acpi_graph_node(fwnode: port, str: "port" )) |
1333 | endpoint = fwnode_get_next_child_node(fwnode: port, NULL); |
1334 | } |
1335 | |
1336 | /* |
1337 | * The names of the endpoint nodes begin with "endpoint@" followed by |
1338 | * the number of the endpoint node and they also have a "reg" property |
1339 | * that also has the number of the endpoint node. For compatibility |
1340 | * reasons a node is also recognised as an endpoint node from the |
1341 | * "endpoint" property. |
1342 | */ |
1343 | if (!is_acpi_graph_node(fwnode: endpoint, str: "endpoint" )) |
1344 | return NULL; |
1345 | |
1346 | return endpoint; |
1347 | } |
1348 | |
1349 | /** |
1350 | * acpi_graph_get_child_prop_value - Return a child with a given property value |
1351 | * @fwnode: device fwnode |
1352 | * @prop_name: The name of the property to look for |
1353 | * @val: the desired property value |
1354 | * |
1355 | * Return the port node corresponding to a given port number. Returns |
1356 | * the child node on success, NULL otherwise. |
1357 | */ |
1358 | static struct fwnode_handle *acpi_graph_get_child_prop_value( |
1359 | const struct fwnode_handle *fwnode, const char *prop_name, |
1360 | unsigned int val) |
1361 | { |
1362 | struct fwnode_handle *child; |
1363 | |
1364 | fwnode_for_each_child_node(fwnode, child) { |
1365 | u32 nr; |
1366 | |
1367 | if (fwnode_property_read_u32(fwnode: child, propname: prop_name, val: &nr)) |
1368 | continue; |
1369 | |
1370 | if (val == nr) |
1371 | return child; |
1372 | } |
1373 | |
1374 | return NULL; |
1375 | } |
1376 | |
1377 | |
1378 | /** |
1379 | * acpi_graph_get_remote_endpoint - Parses and returns remote end of an endpoint |
1380 | * @__fwnode: Endpoint firmware node pointing to a remote device |
1381 | * |
1382 | * Returns the remote endpoint corresponding to @__fwnode. NULL on error. |
1383 | */ |
1384 | static struct fwnode_handle * |
1385 | acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode) |
1386 | { |
1387 | struct fwnode_handle *fwnode; |
1388 | unsigned int port_nr, endpoint_nr; |
1389 | struct fwnode_reference_args args; |
1390 | int ret; |
1391 | |
1392 | memset(&args, 0, sizeof(args)); |
1393 | ret = acpi_node_get_property_reference(fwnode: __fwnode, name: "remote-endpoint" , index: 0, |
1394 | args: &args); |
1395 | if (ret) |
1396 | return NULL; |
1397 | |
1398 | /* Direct endpoint reference? */ |
1399 | if (!is_acpi_device_node(fwnode: args.fwnode)) |
1400 | return args.nargs ? NULL : args.fwnode; |
1401 | |
1402 | /* |
1403 | * Always require two arguments with the reference: port and |
1404 | * endpoint indices. |
1405 | */ |
1406 | if (args.nargs != 2) |
1407 | return NULL; |
1408 | |
1409 | fwnode = args.fwnode; |
1410 | port_nr = args.args[0]; |
1411 | endpoint_nr = args.args[1]; |
1412 | |
1413 | fwnode = acpi_graph_get_child_prop_value(fwnode, prop_name: "port" , val: port_nr); |
1414 | |
1415 | return acpi_graph_get_child_prop_value(fwnode, prop_name: "endpoint" , val: endpoint_nr); |
1416 | } |
1417 | |
1418 | static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode) |
1419 | { |
1420 | if (!is_acpi_device_node(fwnode)) |
1421 | return false; |
1422 | |
1423 | return acpi_device_is_present(to_acpi_device_node(fwnode)); |
1424 | } |
1425 | |
1426 | static const void * |
1427 | acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, |
1428 | const struct device *dev) |
1429 | { |
1430 | return acpi_device_get_match_data(dev); |
1431 | } |
1432 | |
1433 | static bool acpi_fwnode_device_dma_supported(const struct fwnode_handle *fwnode) |
1434 | { |
1435 | return acpi_dma_supported(to_acpi_device_node(fwnode)); |
1436 | } |
1437 | |
1438 | static enum dev_dma_attr |
1439 | acpi_fwnode_device_get_dma_attr(const struct fwnode_handle *fwnode) |
1440 | { |
1441 | return acpi_get_dma_attr(to_acpi_device_node(fwnode)); |
1442 | } |
1443 | |
1444 | static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode, |
1445 | const char *propname) |
1446 | { |
1447 | return !acpi_node_prop_get(fwnode, propname, NULL); |
1448 | } |
1449 | |
1450 | static int |
1451 | acpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode, |
1452 | const char *propname, |
1453 | unsigned int elem_size, void *val, |
1454 | size_t nval) |
1455 | { |
1456 | enum dev_prop_type type; |
1457 | |
1458 | switch (elem_size) { |
1459 | case sizeof(u8): |
1460 | type = DEV_PROP_U8; |
1461 | break; |
1462 | case sizeof(u16): |
1463 | type = DEV_PROP_U16; |
1464 | break; |
1465 | case sizeof(u32): |
1466 | type = DEV_PROP_U32; |
1467 | break; |
1468 | case sizeof(u64): |
1469 | type = DEV_PROP_U64; |
1470 | break; |
1471 | default: |
1472 | return -ENXIO; |
1473 | } |
1474 | |
1475 | return acpi_node_prop_read(fwnode, propname, proptype: type, val, nval); |
1476 | } |
1477 | |
1478 | static int |
1479 | acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, |
1480 | const char *propname, const char **val, |
1481 | size_t nval) |
1482 | { |
1483 | return acpi_node_prop_read(fwnode, propname, proptype: DEV_PROP_STRING, |
1484 | val, nval); |
1485 | } |
1486 | |
1487 | static int |
1488 | acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, |
1489 | const char *prop, const char *nargs_prop, |
1490 | unsigned int args_count, unsigned int index, |
1491 | struct fwnode_reference_args *args) |
1492 | { |
1493 | return __acpi_node_get_property_reference(fwnode, prop, index, |
1494 | args_count, args); |
1495 | } |
1496 | |
1497 | static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode) |
1498 | { |
1499 | const struct acpi_device *adev; |
1500 | struct fwnode_handle *parent; |
1501 | |
1502 | /* Is this the root node? */ |
1503 | parent = fwnode_get_parent(fwnode); |
1504 | if (!parent) |
1505 | return "\\" ; |
1506 | |
1507 | fwnode_handle_put(fwnode: parent); |
1508 | |
1509 | if (is_acpi_data_node(fwnode)) { |
1510 | const struct acpi_data_node *dn = to_acpi_data_node(fwnode); |
1511 | |
1512 | return dn->name; |
1513 | } |
1514 | |
1515 | adev = to_acpi_device_node(fwnode); |
1516 | if (WARN_ON(!adev)) |
1517 | return NULL; |
1518 | |
1519 | return acpi_device_bid(adev); |
1520 | } |
1521 | |
1522 | static const char * |
1523 | acpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode) |
1524 | { |
1525 | struct fwnode_handle *parent; |
1526 | |
1527 | /* Is this the root node? */ |
1528 | parent = fwnode_get_parent(fwnode); |
1529 | if (!parent) |
1530 | return "" ; |
1531 | |
1532 | /* Is this 2nd node from the root? */ |
1533 | parent = fwnode_get_next_parent(fwnode: parent); |
1534 | if (!parent) |
1535 | return "" ; |
1536 | |
1537 | fwnode_handle_put(fwnode: parent); |
1538 | |
1539 | /* ACPI device or data node. */ |
1540 | return "." ; |
1541 | } |
1542 | |
1543 | static struct fwnode_handle * |
1544 | acpi_fwnode_get_parent(struct fwnode_handle *fwnode) |
1545 | { |
1546 | return acpi_node_get_parent(fwnode); |
1547 | } |
1548 | |
1549 | static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, |
1550 | struct fwnode_endpoint *endpoint) |
1551 | { |
1552 | struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode); |
1553 | |
1554 | endpoint->local_fwnode = fwnode; |
1555 | |
1556 | if (fwnode_property_read_u32(fwnode: port_fwnode, propname: "reg" , val: &endpoint->port)) |
1557 | fwnode_property_read_u32(fwnode: port_fwnode, propname: "port" , val: &endpoint->port); |
1558 | if (fwnode_property_read_u32(fwnode, propname: "reg" , val: &endpoint->id)) |
1559 | fwnode_property_read_u32(fwnode, propname: "endpoint" , val: &endpoint->id); |
1560 | |
1561 | return 0; |
1562 | } |
1563 | |
1564 | static int acpi_fwnode_irq_get(const struct fwnode_handle *fwnode, |
1565 | unsigned int index) |
1566 | { |
1567 | struct resource res; |
1568 | int ret; |
1569 | |
1570 | ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, res: &res); |
1571 | if (ret) |
1572 | return ret; |
1573 | |
1574 | return res.start; |
1575 | } |
1576 | |
1577 | #define DECLARE_ACPI_FWNODE_OPS(ops) \ |
1578 | const struct fwnode_operations ops = { \ |
1579 | .device_is_available = acpi_fwnode_device_is_available, \ |
1580 | .device_get_match_data = acpi_fwnode_device_get_match_data, \ |
1581 | .device_dma_supported = \ |
1582 | acpi_fwnode_device_dma_supported, \ |
1583 | .device_get_dma_attr = acpi_fwnode_device_get_dma_attr, \ |
1584 | .property_present = acpi_fwnode_property_present, \ |
1585 | .property_read_int_array = \ |
1586 | acpi_fwnode_property_read_int_array, \ |
1587 | .property_read_string_array = \ |
1588 | acpi_fwnode_property_read_string_array, \ |
1589 | .get_parent = acpi_node_get_parent, \ |
1590 | .get_next_child_node = acpi_get_next_subnode, \ |
1591 | .get_named_child_node = acpi_fwnode_get_named_child_node, \ |
1592 | .get_name = acpi_fwnode_get_name, \ |
1593 | .get_name_prefix = acpi_fwnode_get_name_prefix, \ |
1594 | .get_reference_args = acpi_fwnode_get_reference_args, \ |
1595 | .graph_get_next_endpoint = \ |
1596 | acpi_graph_get_next_endpoint, \ |
1597 | .graph_get_remote_endpoint = \ |
1598 | acpi_graph_get_remote_endpoint, \ |
1599 | .graph_get_port_parent = acpi_fwnode_get_parent, \ |
1600 | .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \ |
1601 | .irq_get = acpi_fwnode_irq_get, \ |
1602 | }; \ |
1603 | EXPORT_SYMBOL_GPL(ops) |
1604 | |
1605 | DECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops); |
1606 | DECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops); |
1607 | const struct fwnode_operations acpi_static_fwnode_ops; |
1608 | |
1609 | bool is_acpi_device_node(const struct fwnode_handle *fwnode) |
1610 | { |
1611 | return !IS_ERR_OR_NULL(ptr: fwnode) && |
1612 | fwnode->ops == &acpi_device_fwnode_ops; |
1613 | } |
1614 | EXPORT_SYMBOL(is_acpi_device_node); |
1615 | |
1616 | bool is_acpi_data_node(const struct fwnode_handle *fwnode) |
1617 | { |
1618 | return !IS_ERR_OR_NULL(ptr: fwnode) && fwnode->ops == &acpi_data_fwnode_ops; |
1619 | } |
1620 | EXPORT_SYMBOL(is_acpi_data_node); |
1621 | |