Branch data Line data Source code
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 : : };
49 : :
50 : : /* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
51 : : static const guid_t ads_guid =
52 : : GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
53 : : 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
54 : :
55 : : static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
56 : : const union acpi_object *desc,
57 : : struct acpi_device_data *data,
58 : : struct fwnode_handle *parent);
59 : : static bool acpi_extract_properties(const union acpi_object *desc,
60 : : struct acpi_device_data *data);
61 : :
62 : : static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
63 : : acpi_handle handle,
64 : : const union acpi_object *link,
65 : : struct list_head *list,
66 : : struct fwnode_handle *parent)
67 : : {
68 : : struct acpi_data_node *dn;
69 : : bool result;
70 : :
71 : : dn = kzalloc(sizeof(*dn), GFP_KERNEL);
72 : : if (!dn)
73 : : return false;
74 : :
75 : : dn->name = link->package.elements[0].string.pointer;
76 : : dn->fwnode.ops = &acpi_data_fwnode_ops;
77 : : dn->parent = parent;
78 : : INIT_LIST_HEAD(&dn->data.properties);
79 : : INIT_LIST_HEAD(&dn->data.subnodes);
80 : :
81 : : result = acpi_extract_properties(desc, &dn->data);
82 : :
83 : : if (handle) {
84 : : acpi_handle scope;
85 : : acpi_status status;
86 : :
87 : : /*
88 : : * The scope for the subnode object lookup is the one of the
89 : : * namespace node (device) containing the object that has
90 : : * returned the package. That is, it's the scope of that
91 : : * object's parent.
92 : : */
93 : : status = acpi_get_parent(handle, &scope);
94 : : if (ACPI_SUCCESS(status)
95 : : && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data,
96 : : &dn->fwnode))
97 : : result = true;
98 : : } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data,
99 : : &dn->fwnode)) {
100 : : result = true;
101 : : }
102 : :
103 : : if (result) {
104 : : dn->handle = handle;
105 : : dn->data.pointer = desc;
106 : : list_add_tail(&dn->sibling, list);
107 : : return true;
108 : : }
109 : :
110 : : kfree(dn);
111 : : acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
112 : : return false;
113 : : }
114 : :
115 : 0 : static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
116 : : const union acpi_object *link,
117 : : struct list_head *list,
118 : : struct fwnode_handle *parent)
119 : : {
120 : 0 : struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
121 : 0 : acpi_status status;
122 : :
123 : 0 : status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
124 : : ACPI_TYPE_PACKAGE);
125 [ # # ]: 0 : if (ACPI_FAILURE(status))
126 : : return false;
127 : :
128 [ # # ]: 0 : if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
129 : : parent))
130 : : return true;
131 : :
132 : 0 : ACPI_FREE(buf.pointer);
133 : 0 : return false;
134 : : }
135 : :
136 : 0 : static bool acpi_nondev_subnode_ok(acpi_handle scope,
137 : : const union acpi_object *link,
138 : : struct list_head *list,
139 : : struct fwnode_handle *parent)
140 : : {
141 : 0 : acpi_handle handle;
142 : 0 : acpi_status status;
143 : :
144 [ # # ]: 0 : if (!scope)
145 : : return false;
146 : :
147 : 0 : status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
148 : : &handle);
149 [ # # ]: 0 : if (ACPI_FAILURE(status))
150 : : return false;
151 : :
152 : 0 : return acpi_nondev_subnode_data_ok(handle, link, list, parent);
153 : : }
154 : :
155 : : static int acpi_add_nondev_subnodes(acpi_handle scope,
156 : : const union acpi_object *links,
157 : : struct list_head *list,
158 : : struct fwnode_handle *parent)
159 : : {
160 : : bool ret = false;
161 : : int i;
162 : :
163 : : for (i = 0; i < links->package.count; i++) {
164 : : const union acpi_object *link, *desc;
165 : : acpi_handle handle;
166 : : bool result;
167 : :
168 : : link = &links->package.elements[i];
169 : : /* Only two elements allowed. */
170 : : if (link->package.count != 2)
171 : : continue;
172 : :
173 : : /* The first one must be a string. */
174 : : if (link->package.elements[0].type != ACPI_TYPE_STRING)
175 : : continue;
176 : :
177 : : /* The second one may be a string, a reference or a package. */
178 : : switch (link->package.elements[1].type) {
179 : : case ACPI_TYPE_STRING:
180 : : result = acpi_nondev_subnode_ok(scope, link, list,
181 : : parent);
182 : : break;
183 : : case ACPI_TYPE_LOCAL_REFERENCE:
184 : : handle = link->package.elements[1].reference.handle;
185 : : result = acpi_nondev_subnode_data_ok(handle, link, list,
186 : : parent);
187 : : break;
188 : : case ACPI_TYPE_PACKAGE:
189 : : desc = &link->package.elements[1];
190 : : result = acpi_nondev_subnode_extract(desc, NULL, link,
191 : : list, parent);
192 : : break;
193 : : default:
194 : : result = false;
195 : : break;
196 : : }
197 : : ret = ret || result;
198 : : }
199 : :
200 : : return ret;
201 : : }
202 : :
203 : : static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
204 : : const union acpi_object *desc,
205 : : struct acpi_device_data *data,
206 : : struct fwnode_handle *parent)
207 : : {
208 : : int i;
209 : :
210 : : /* Look for the ACPI data subnodes GUID. */
211 : : for (i = 0; i < desc->package.count; i += 2) {
212 : : const union acpi_object *guid, *links;
213 : :
214 : : guid = &desc->package.elements[i];
215 : : links = &desc->package.elements[i + 1];
216 : :
217 : : /*
218 : : * The first element must be a GUID and the second one must be
219 : : * a package.
220 : : */
221 : : if (guid->type != ACPI_TYPE_BUFFER ||
222 : : guid->buffer.length != 16 ||
223 : : links->type != ACPI_TYPE_PACKAGE)
224 : : break;
225 : :
226 : : if (!guid_equal((guid_t *)guid->buffer.pointer, &ads_guid))
227 : : continue;
228 : :
229 : : return acpi_add_nondev_subnodes(scope, links, &data->subnodes,
230 : : parent);
231 : : }
232 : :
233 : : return false;
234 : : }
235 : :
236 : 0 : static bool acpi_property_value_ok(const union acpi_object *value)
237 : : {
238 : 0 : int j;
239 : :
240 : : /*
241 : : * The value must be an integer, a string, a reference, or a package
242 : : * whose every element must be an integer, a string, or a reference.
243 : : */
244 [ # # # ]: 0 : switch (value->type) {
245 : : case ACPI_TYPE_INTEGER:
246 : : case ACPI_TYPE_STRING:
247 : : case ACPI_TYPE_LOCAL_REFERENCE:
248 : : return true;
249 : :
250 : : case ACPI_TYPE_PACKAGE:
251 [ # # ]: 0 : for (j = 0; j < value->package.count; j++)
252 [ # # ]: 0 : switch (value->package.elements[j].type) {
253 : 0 : case ACPI_TYPE_INTEGER:
254 : : case ACPI_TYPE_STRING:
255 : : case ACPI_TYPE_LOCAL_REFERENCE:
256 : 0 : continue;
257 : :
258 : : default:
259 : : return false;
260 : : }
261 : :
262 : : return true;
263 : : }
264 : 0 : return false;
265 : : }
266 : :
267 : : static bool acpi_properties_format_valid(const union acpi_object *properties)
268 : : {
269 : : int i;
270 : :
271 : : for (i = 0; i < properties->package.count; i++) {
272 : : const union acpi_object *property;
273 : :
274 : : property = &properties->package.elements[i];
275 : : /*
276 : : * Only two elements allowed, the first one must be a string and
277 : : * the second one has to satisfy certain conditions.
278 : : */
279 : : if (property->package.count != 2
280 : : || property->package.elements[0].type != ACPI_TYPE_STRING
281 : : || !acpi_property_value_ok(&property->package.elements[1]))
282 : : return false;
283 : : }
284 : : return true;
285 : : }
286 : :
287 : 0 : static void acpi_init_of_compatible(struct acpi_device *adev)
288 : : {
289 : 0 : const union acpi_object *of_compatible;
290 : 0 : int ret;
291 : :
292 : 0 : ret = acpi_data_get_property_array(&adev->data, "compatible",
293 : : ACPI_TYPE_STRING, &of_compatible);
294 [ # # ]: 0 : if (ret) {
295 : 0 : ret = acpi_dev_get_property(adev, "compatible",
296 : : ACPI_TYPE_STRING, &of_compatible);
297 [ # # ]: 0 : if (ret) {
298 [ # # ]: 0 : if (adev->parent
299 [ # # ]: 0 : && adev->parent->flags.of_compatible_ok)
300 : 0 : goto out;
301 : :
302 : 0 : return;
303 : : }
304 : : }
305 : 0 : adev->data.of_compatible = of_compatible;
306 : :
307 : 0 : out:
308 : 0 : adev->flags.of_compatible_ok = 1;
309 : : }
310 : :
311 : : static bool acpi_is_property_guid(const guid_t *guid)
312 : : {
313 : : int i;
314 : :
315 : : for (i = 0; i < ARRAY_SIZE(prp_guids); i++) {
316 : : if (guid_equal(guid, &prp_guids[i]))
317 : : return true;
318 : : }
319 : :
320 : : return false;
321 : : }
322 : :
323 : : struct acpi_device_properties *
324 : 0 : acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
325 : : const union acpi_object *properties)
326 : : {
327 : 0 : struct acpi_device_properties *props;
328 : :
329 : 0 : props = kzalloc(sizeof(*props), GFP_KERNEL);
330 [ # # ]: 0 : if (props) {
331 : 0 : INIT_LIST_HEAD(&props->list);
332 : 0 : props->guid = guid;
333 : 0 : props->properties = properties;
334 : 0 : list_add_tail(&props->list, &data->properties);
335 : : }
336 : :
337 : 0 : return props;
338 : : }
339 : :
340 : : static bool acpi_extract_properties(const union acpi_object *desc,
341 : : struct acpi_device_data *data)
342 : : {
343 : : int i;
344 : :
345 : : if (desc->package.count % 2)
346 : : return false;
347 : :
348 : : /* Look for the device properties GUID. */
349 : : for (i = 0; i < desc->package.count; i += 2) {
350 : : const union acpi_object *guid, *properties;
351 : :
352 : : guid = &desc->package.elements[i];
353 : : properties = &desc->package.elements[i + 1];
354 : :
355 : : /*
356 : : * The first element must be a GUID and the second one must be
357 : : * a package.
358 : : */
359 : : if (guid->type != ACPI_TYPE_BUFFER ||
360 : : guid->buffer.length != 16 ||
361 : : properties->type != ACPI_TYPE_PACKAGE)
362 : : break;
363 : :
364 : : if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer))
365 : : continue;
366 : :
367 : : /*
368 : : * We found the matching GUID. Now validate the format of the
369 : : * package immediately following it.
370 : : */
371 : : if (!acpi_properties_format_valid(properties))
372 : : continue;
373 : :
374 : : acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer,
375 : : properties);
376 : : }
377 : :
378 : : return !list_empty(&data->properties);
379 : : }
380 : :
381 : 4524 : void acpi_init_properties(struct acpi_device *adev)
382 : : {
383 : 4524 : struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
384 : 4524 : struct acpi_hardware_id *hwid;
385 : 4524 : acpi_status status;
386 : 4524 : bool acpi_of = false;
387 : :
388 [ + + ]: 4524 : INIT_LIST_HEAD(&adev->data.properties);
389 : 4524 : INIT_LIST_HEAD(&adev->data.subnodes);
390 : :
391 [ + + ]: 4524 : if (!adev->handle)
392 : 78 : return;
393 : :
394 : : /*
395 : : * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
396 : : * Device Tree compatible properties for this device.
397 : : */
398 [ + + ]: 6318 : list_for_each_entry(hwid, &adev->pnp.ids, list) {
399 [ + - ]: 1872 : if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
400 : : acpi_of = true;
401 : : break;
402 : : }
403 : : }
404 : :
405 : 4446 : status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
406 : : ACPI_TYPE_PACKAGE);
407 [ + - ]: 4446 : if (ACPI_FAILURE(status))
408 : 4446 : goto out;
409 : :
410 [ # # ]: 0 : if (acpi_extract_properties(buf.pointer, &adev->data)) {
411 : 0 : adev->data.pointer = buf.pointer;
412 [ # # ]: 0 : if (acpi_of)
413 : 0 : acpi_init_of_compatible(adev);
414 : : }
415 [ # # ]: 0 : if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer,
416 : : &adev->data, acpi_fwnode_handle(adev)))
417 : 0 : adev->data.pointer = buf.pointer;
418 : :
419 [ # # ]: 0 : if (!adev->data.pointer) {
420 : 0 : acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n");
421 : 0 : ACPI_FREE(buf.pointer);
422 : : }
423 : :
424 : 0 : out:
425 [ - + - - ]: 4446 : if (acpi_of && !adev->flags.of_compatible_ok)
426 : 0 : acpi_handle_info(adev->handle,
427 : : ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
428 : :
429 [ + - ]: 4446 : if (!adev->data.pointer)
430 : 4446 : acpi_extract_apple_properties(adev);
431 : : }
432 : :
433 : 0 : static void acpi_destroy_nondev_subnodes(struct list_head *list)
434 : : {
435 : 0 : struct acpi_data_node *dn, *next;
436 : :
437 [ # # ]: 0 : if (list_empty(list))
438 : : return;
439 : :
440 [ # # ]: 0 : list_for_each_entry_safe_reverse(dn, next, list, sibling) {
441 : 0 : acpi_destroy_nondev_subnodes(&dn->data.subnodes);
442 : 0 : wait_for_completion(&dn->kobj_done);
443 : 0 : list_del(&dn->sibling);
444 : 0 : ACPI_FREE((void *)dn->data.pointer);
445 : 0 : kfree(dn);
446 : : }
447 : : }
448 : :
449 : 0 : void acpi_free_properties(struct acpi_device *adev)
450 : : {
451 : 0 : struct acpi_device_properties *props, *tmp;
452 : :
453 : 0 : acpi_destroy_nondev_subnodes(&adev->data.subnodes);
454 : 0 : ACPI_FREE((void *)adev->data.pointer);
455 : 0 : adev->data.of_compatible = NULL;
456 : 0 : adev->data.pointer = NULL;
457 [ # # ]: 0 : list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
458 : 0 : list_del(&props->list);
459 : 0 : kfree(props);
460 : : }
461 : 0 : }
462 : :
463 : : /**
464 : : * acpi_data_get_property - return an ACPI property with given name
465 : : * @data: ACPI device deta object to get the property from
466 : : * @name: Name of the property
467 : : * @type: Expected property type
468 : : * @obj: Location to store the property value (if not %NULL)
469 : : *
470 : : * Look up a property with @name and store a pointer to the resulting ACPI
471 : : * object at the location pointed to by @obj if found.
472 : : *
473 : : * Callers must not attempt to free the returned objects. These objects will be
474 : : * freed by the ACPI core automatically during the removal of @data.
475 : : *
476 : : * Return: %0 if property with @name has been found (success),
477 : : * %-EINVAL if the arguments are invalid,
478 : : * %-EINVAL if the property doesn't exist,
479 : : * %-EPROTO if the property value type doesn't match @type.
480 : : */
481 : 78 : static int acpi_data_get_property(const struct acpi_device_data *data,
482 : : const char *name, acpi_object_type type,
483 : : const union acpi_object **obj)
484 : : {
485 : 78 : const struct acpi_device_properties *props;
486 : :
487 [ + - ]: 78 : if (!data || !name)
488 : : return -EINVAL;
489 : :
490 [ - + - - ]: 78 : if (!data->pointer || list_empty(&data->properties))
491 : : return -EINVAL;
492 : :
493 [ # # ]: 0 : list_for_each_entry(props, &data->properties, list) {
494 : 0 : const union acpi_object *properties;
495 : 0 : unsigned int i;
496 : :
497 : 0 : properties = props->properties;
498 [ # # ]: 0 : for (i = 0; i < properties->package.count; i++) {
499 : 0 : const union acpi_object *propname, *propvalue;
500 : 0 : const union acpi_object *property;
501 : :
502 : 0 : property = &properties->package.elements[i];
503 : :
504 : 0 : propname = &property->package.elements[0];
505 : 0 : propvalue = &property->package.elements[1];
506 : :
507 [ # # ]: 0 : if (!strcmp(name, propname->string.pointer)) {
508 [ # # ]: 0 : if (type != ACPI_TYPE_ANY &&
509 [ # # ]: 0 : propvalue->type != type)
510 : : return -EPROTO;
511 [ # # ]: 0 : if (obj)
512 : 0 : *obj = propvalue;
513 : :
514 : 0 : return 0;
515 : : }
516 : : }
517 : : }
518 : : return -EINVAL;
519 : : }
520 : :
521 : : /**
522 : : * acpi_dev_get_property - return an ACPI property with given name.
523 : : * @adev: ACPI device to get the property from.
524 : : * @name: Name of the property.
525 : : * @type: Expected property type.
526 : : * @obj: Location to store the property value (if not %NULL).
527 : : */
528 : 0 : int acpi_dev_get_property(const struct acpi_device *adev, const char *name,
529 : : acpi_object_type type, const union acpi_object **obj)
530 : : {
531 [ # # # # ]: 0 : return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL;
532 : : }
533 : : EXPORT_SYMBOL_GPL(acpi_dev_get_property);
534 : :
535 : : static const struct acpi_device_data *
536 : 78 : acpi_device_data_of_node(const struct fwnode_handle *fwnode)
537 : : {
538 : 156 : if (is_acpi_device_node(fwnode)) {
539 : 78 : const struct acpi_device *adev = to_acpi_device_node(fwnode);
540 : 78 : return &adev->data;
541 : 0 : } else if (is_acpi_data_node(fwnode)) {
542 : 0 : const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
543 : 0 : return &dn->data;
544 : : }
545 : : return NULL;
546 : : }
547 : :
548 : : /**
549 : : * acpi_node_prop_get - return an ACPI property with given name.
550 : : * @fwnode: Firmware node to get the property from.
551 : : * @propname: Name of the property.
552 : : * @valptr: Location to store a pointer to the property value (if not %NULL).
553 : : */
554 : 78 : int acpi_node_prop_get(const struct fwnode_handle *fwnode,
555 : : const char *propname, void **valptr)
556 : : {
557 : 0 : return acpi_data_get_property(acpi_device_data_of_node(fwnode),
558 : : propname, ACPI_TYPE_ANY,
559 : : (const union acpi_object **)valptr);
560 : : }
561 : :
562 : : /**
563 : : * acpi_data_get_property_array - return an ACPI array property with given name
564 : : * @adev: ACPI data object to get the property from
565 : : * @name: Name of the property
566 : : * @type: Expected type of array elements
567 : : * @obj: Location to store a pointer to the property value (if not NULL)
568 : : *
569 : : * Look up an array property with @name and store a pointer to the resulting
570 : : * ACPI object at the location pointed to by @obj if found.
571 : : *
572 : : * Callers must not attempt to free the returned objects. Those objects will be
573 : : * freed by the ACPI core automatically during the removal of @data.
574 : : *
575 : : * Return: %0 if array property (package) with @name has been found (success),
576 : : * %-EINVAL if the arguments are invalid,
577 : : * %-EINVAL if the property doesn't exist,
578 : : * %-EPROTO if the property is not a package or the type of its elements
579 : : * doesn't match @type.
580 : : */
581 : 0 : static int acpi_data_get_property_array(const struct acpi_device_data *data,
582 : : const char *name,
583 : : acpi_object_type type,
584 : : const union acpi_object **obj)
585 : : {
586 : 0 : const union acpi_object *prop;
587 : 0 : int ret, i;
588 : :
589 : 0 : ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop);
590 [ # # # # ]: 0 : if (ret)
591 : : return ret;
592 : :
593 [ # # ]: 0 : if (type != ACPI_TYPE_ANY) {
594 : : /* Check that all elements are of correct type. */
595 [ # # ]: 0 : for (i = 0; i < prop->package.count; i++)
596 [ # # ]: 0 : if (prop->package.elements[i].type != type)
597 : : return -EPROTO;
598 : : }
599 [ # # ]: 0 : if (obj)
600 : 0 : *obj = prop;
601 : :
602 : : return 0;
603 : : }
604 : :
605 : : static struct fwnode_handle *
606 : 0 : acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
607 : : const char *childname)
608 : : {
609 : 0 : char name[ACPI_PATH_SEGMENT_LENGTH];
610 : 0 : struct fwnode_handle *child;
611 : 0 : struct acpi_buffer path;
612 : 0 : acpi_status status;
613 : :
614 : 0 : path.length = sizeof(name);
615 : 0 : path.pointer = name;
616 : :
617 [ # # ]: 0 : fwnode_for_each_child_node(fwnode, child) {
618 : 0 : if (is_acpi_data_node(child)) {
619 [ # # ]: 0 : if (acpi_data_node_match(child, childname))
620 : 0 : return child;
621 : 0 : continue;
622 : : }
623 : :
624 [ # # ]: 0 : status = acpi_get_name(ACPI_HANDLE_FWNODE(child),
625 : : ACPI_SINGLE_NAME, &path);
626 [ # # ]: 0 : if (ACPI_FAILURE(status))
627 : : break;
628 : :
629 [ # # ]: 0 : if (!strncmp(name, childname, ACPI_NAMESEG_SIZE))
630 : 0 : return child;
631 : : }
632 : :
633 : : return NULL;
634 : : }
635 : :
636 : : /**
637 : : * __acpi_node_get_property_reference - returns handle to the referenced object
638 : : * @fwnode: Firmware node to get the property from
639 : : * @propname: Name of the property
640 : : * @index: Index of the reference to return
641 : : * @num_args: Maximum number of arguments after each reference
642 : : * @args: Location to store the returned reference with optional arguments
643 : : *
644 : : * Find property with @name, verifify that it is a package containing at least
645 : : * one object reference and if so, store the ACPI device object pointer to the
646 : : * target object in @args->adev. If the reference includes arguments, store
647 : : * them in the @args->args[] array.
648 : : *
649 : : * If there's more than one reference in the property value package, @index is
650 : : * used to select the one to return.
651 : : *
652 : : * It is possible to leave holes in the property value set like in the
653 : : * example below:
654 : : *
655 : : * Package () {
656 : : * "cs-gpios",
657 : : * Package () {
658 : : * ^GPIO, 19, 0, 0,
659 : : * ^GPIO, 20, 0, 0,
660 : : * 0,
661 : : * ^GPIO, 21, 0, 0,
662 : : * }
663 : : * }
664 : : *
665 : : * Calling this function with index %2 or index %3 return %-ENOENT. If the
666 : : * property does not contain any more values %-ENOENT is returned. The NULL
667 : : * entry must be single integer and preferably contain value %0.
668 : : *
669 : : * Return: %0 on success, negative error code on failure.
670 : : */
671 : 0 : int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
672 : : const char *propname, size_t index, size_t num_args,
673 : : struct fwnode_reference_args *args)
674 : : {
675 : 0 : const union acpi_object *element, *end;
676 : 0 : const union acpi_object *obj;
677 : 0 : const struct acpi_device_data *data;
678 : 0 : struct acpi_device *device;
679 : 0 : int ret, idx = 0;
680 : :
681 : 0 : data = acpi_device_data_of_node(fwnode);
682 [ # # ]: 0 : if (!data)
683 : : return -ENOENT;
684 : :
685 : 0 : ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
686 [ # # ]: 0 : if (ret)
687 [ # # ]: 0 : return ret == -EINVAL ? -ENOENT : -EINVAL;
688 : :
689 : : /*
690 : : * The simplest case is when the value is a single reference. Just
691 : : * return that reference then.
692 : : */
693 [ # # ]: 0 : if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
694 [ # # ]: 0 : if (index)
695 : : return -EINVAL;
696 : :
697 : 0 : ret = acpi_bus_get_device(obj->reference.handle, &device);
698 [ # # ]: 0 : if (ret)
699 [ # # ]: 0 : return ret == -ENODEV ? -EINVAL : ret;
700 : :
701 : 0 : args->fwnode = acpi_fwnode_handle(device);
702 : 0 : args->nargs = 0;
703 : 0 : return 0;
704 : : }
705 : :
706 : : /*
707 : : * If it is not a single reference, then it is a package of
708 : : * references followed by number of ints as follows:
709 : : *
710 : : * Package () { REF, INT, REF, INT, INT }
711 : : *
712 : : * The index argument is then used to determine which reference
713 : : * the caller wants (along with the arguments).
714 : : */
715 [ # # ]: 0 : if (obj->type != ACPI_TYPE_PACKAGE)
716 : : return -EINVAL;
717 [ # # ]: 0 : if (index >= obj->package.count)
718 : : return -ENOENT;
719 : :
720 : 0 : element = obj->package.elements;
721 : 0 : end = element + obj->package.count;
722 : :
723 [ # # ]: 0 : while (element < end) {
724 : 0 : u32 nargs, i;
725 : :
726 [ # # ]: 0 : if (element->type == ACPI_TYPE_LOCAL_REFERENCE) {
727 : 0 : struct fwnode_handle *ref_fwnode;
728 : :
729 : 0 : ret = acpi_bus_get_device(element->reference.handle,
730 : : &device);
731 [ # # ]: 0 : if (ret)
732 : : return -EINVAL;
733 : :
734 : 0 : nargs = 0;
735 : 0 : element++;
736 : :
737 : : /*
738 : : * Find the referred data extension node under the
739 : : * referred device node.
740 : : */
741 : 0 : for (ref_fwnode = acpi_fwnode_handle(device);
742 [ # # # # ]: 0 : element < end && element->type == ACPI_TYPE_STRING;
743 : 0 : element++) {
744 : 0 : ref_fwnode = acpi_fwnode_get_named_child_node(
745 : 0 : ref_fwnode, element->string.pointer);
746 [ # # ]: 0 : if (!ref_fwnode)
747 : : return -EINVAL;
748 : : }
749 : :
750 : : /* assume following integer elements are all args */
751 [ # # # # ]: 0 : for (i = 0; element + i < end && i < num_args; i++) {
752 : 0 : int type = element[i].type;
753 : :
754 [ # # ]: 0 : if (type == ACPI_TYPE_INTEGER)
755 : 0 : nargs++;
756 [ # # ]: 0 : else if (type == ACPI_TYPE_LOCAL_REFERENCE)
757 : : break;
758 : : else
759 : : return -EINVAL;
760 : : }
761 : :
762 [ # # ]: 0 : if (nargs > NR_FWNODE_REFERENCE_ARGS)
763 : : return -EINVAL;
764 : :
765 [ # # ]: 0 : if (idx == index) {
766 : 0 : args->fwnode = ref_fwnode;
767 : 0 : args->nargs = nargs;
768 [ # # ]: 0 : for (i = 0; i < nargs; i++)
769 : 0 : args->args[i] = element[i].integer.value;
770 : :
771 : : return 0;
772 : : }
773 : :
774 : : element += nargs;
775 [ # # ]: 0 : } else if (element->type == ACPI_TYPE_INTEGER) {
776 [ # # ]: 0 : if (idx == index)
777 : : return -ENOENT;
778 : 0 : element++;
779 : : } else {
780 : : return -EINVAL;
781 : : }
782 : :
783 : 0 : idx++;
784 : : }
785 : :
786 : : return -ENOENT;
787 : : }
788 : : EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference);
789 : :
790 : 0 : static int acpi_data_prop_read_single(const struct acpi_device_data *data,
791 : : const char *propname,
792 : : enum dev_prop_type proptype, void *val)
793 : : {
794 : 0 : const union acpi_object *obj;
795 : 0 : int ret;
796 : :
797 [ # # ]: 0 : if (!val)
798 : : return -EINVAL;
799 : :
800 [ # # ]: 0 : if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
801 : 0 : ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
802 [ # # ]: 0 : if (ret)
803 : : return ret;
804 : :
805 [ # # # # ]: 0 : switch (proptype) {
806 : 0 : case DEV_PROP_U8:
807 [ # # ]: 0 : if (obj->integer.value > U8_MAX)
808 : : return -EOVERFLOW;
809 : 0 : *(u8 *)val = obj->integer.value;
810 : 0 : break;
811 : 0 : case DEV_PROP_U16:
812 [ # # ]: 0 : if (obj->integer.value > U16_MAX)
813 : : return -EOVERFLOW;
814 : 0 : *(u16 *)val = obj->integer.value;
815 : 0 : break;
816 : 0 : case DEV_PROP_U32:
817 [ # # ]: 0 : if (obj->integer.value > U32_MAX)
818 : : return -EOVERFLOW;
819 : 0 : *(u32 *)val = obj->integer.value;
820 : 0 : break;
821 : 0 : default:
822 : 0 : *(u64 *)val = obj->integer.value;
823 : 0 : break;
824 : : }
825 [ # # ]: 0 : } else if (proptype == DEV_PROP_STRING) {
826 : 0 : ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
827 [ # # ]: 0 : if (ret)
828 : : return ret;
829 : :
830 : 0 : *(char **)val = obj->string.pointer;
831 : :
832 : 0 : return 1;
833 : : } else {
834 : : ret = -EINVAL;
835 : : }
836 : : return ret;
837 : : }
838 : :
839 : 0 : int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
840 : : enum dev_prop_type proptype, void *val)
841 : : {
842 : 0 : int ret;
843 : :
844 [ # # ]: 0 : if (!adev)
845 : : return -EINVAL;
846 : :
847 : 0 : ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val);
848 [ # # ]: 0 : if (ret < 0 || proptype != ACPI_TYPE_STRING)
849 : 0 : return ret;
850 : : return 0;
851 : : }
852 : :
853 : : static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
854 : : size_t nval)
855 : : {
856 : : int i;
857 : :
858 [ # # ]: 0 : for (i = 0; i < nval; i++) {
859 [ # # ]: 0 : if (items[i].type != ACPI_TYPE_INTEGER)
860 : : return -EPROTO;
861 [ # # ]: 0 : if (items[i].integer.value > U8_MAX)
862 : : return -EOVERFLOW;
863 : :
864 : 0 : val[i] = items[i].integer.value;
865 : : }
866 : : return 0;
867 : : }
868 : :
869 : : static int acpi_copy_property_array_u16(const union acpi_object *items,
870 : : u16 *val, size_t nval)
871 : : {
872 : : int i;
873 : :
874 [ # # ]: 0 : for (i = 0; i < nval; i++) {
875 [ # # ]: 0 : if (items[i].type != ACPI_TYPE_INTEGER)
876 : : return -EPROTO;
877 [ # # ]: 0 : if (items[i].integer.value > U16_MAX)
878 : : return -EOVERFLOW;
879 : :
880 : 0 : val[i] = items[i].integer.value;
881 : : }
882 : : return 0;
883 : : }
884 : :
885 : : static int acpi_copy_property_array_u32(const union acpi_object *items,
886 : : u32 *val, size_t nval)
887 : : {
888 : : int i;
889 : :
890 [ # # ]: 0 : for (i = 0; i < nval; i++) {
891 [ # # ]: 0 : if (items[i].type != ACPI_TYPE_INTEGER)
892 : : return -EPROTO;
893 [ # # ]: 0 : if (items[i].integer.value > U32_MAX)
894 : : return -EOVERFLOW;
895 : :
896 : 0 : val[i] = items[i].integer.value;
897 : : }
898 : : return 0;
899 : : }
900 : :
901 : : static int acpi_copy_property_array_u64(const union acpi_object *items,
902 : : u64 *val, size_t nval)
903 : : {
904 : : int i;
905 : :
906 [ # # ]: 0 : for (i = 0; i < nval; i++) {
907 [ # # ]: 0 : if (items[i].type != ACPI_TYPE_INTEGER)
908 : : return -EPROTO;
909 : :
910 : 0 : val[i] = items[i].integer.value;
911 : : }
912 : : return 0;
913 : : }
914 : :
915 : 0 : static int acpi_copy_property_array_string(const union acpi_object *items,
916 : : char **val, size_t nval)
917 : : {
918 : 0 : int i;
919 : :
920 [ # # ]: 0 : for (i = 0; i < nval; i++) {
921 [ # # ]: 0 : if (items[i].type != ACPI_TYPE_STRING)
922 : : return -EPROTO;
923 : :
924 : 0 : val[i] = items[i].string.pointer;
925 : : }
926 : 0 : return nval;
927 : : }
928 : :
929 : 0 : static int acpi_data_prop_read(const struct acpi_device_data *data,
930 : : const char *propname,
931 : : enum dev_prop_type proptype,
932 : : void *val, size_t nval)
933 : : {
934 : 0 : const union acpi_object *obj;
935 : 0 : const union acpi_object *items;
936 : 0 : int ret;
937 : :
938 [ # # ]: 0 : if (val && nval == 1) {
939 : 0 : ret = acpi_data_prop_read_single(data, propname, proptype, val);
940 [ # # ]: 0 : if (ret >= 0)
941 : : return ret;
942 : : }
943 : :
944 : 0 : ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
945 : 0 : if (ret)
946 : 0 : return ret;
947 : :
948 [ # # ]: 0 : if (!val)
949 : 0 : return obj->package.count;
950 : :
951 [ # # # # ]: 0 : if (proptype != DEV_PROP_STRING && nval > obj->package.count)
952 : : return -EOVERFLOW;
953 [ # # ]: 0 : else if (nval <= 0)
954 : : return -EINVAL;
955 : :
956 : 0 : items = obj->package.elements;
957 : :
958 [ # # # # : 0 : switch (proptype) {
# # ]
959 : : case DEV_PROP_U8:
960 : : ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
961 : : break;
962 : : case DEV_PROP_U16:
963 : : ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
964 : : break;
965 : : case DEV_PROP_U32:
966 : : ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
967 : : break;
968 : : case DEV_PROP_U64:
969 : : ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
970 : : break;
971 : 0 : case DEV_PROP_STRING:
972 : 0 : ret = acpi_copy_property_array_string(
973 : : items, (char **)val,
974 : 0 : min_t(u32, nval, obj->package.count));
975 : : break;
976 : : default:
977 : : ret = -EINVAL;
978 : : break;
979 : : }
980 : : return ret;
981 : : }
982 : :
983 : 0 : int acpi_dev_prop_read(const struct acpi_device *adev, const char *propname,
984 : : enum dev_prop_type proptype, void *val, size_t nval)
985 : : {
986 [ # # ]: 0 : return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;
987 : : }
988 : :
989 : : /**
990 : : * acpi_node_prop_read - retrieve the value of an ACPI property with given name.
991 : : * @fwnode: Firmware node to get the property from.
992 : : * @propname: Name of the property.
993 : : * @proptype: Expected property type.
994 : : * @val: Location to store the property value (if not %NULL).
995 : : * @nval: Size of the array pointed to by @val.
996 : : *
997 : : * If @val is %NULL, return the number of array elements comprising the value
998 : : * of the property. Otherwise, read at most @nval values to the array at the
999 : : * location pointed to by @val.
1000 : : */
1001 : 0 : int acpi_node_prop_read(const struct fwnode_handle *fwnode,
1002 : : const char *propname, enum dev_prop_type proptype,
1003 : : void *val, size_t nval)
1004 : : {
1005 : 0 : return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
1006 : : propname, proptype, val, nval);
1007 : : }
1008 : :
1009 : : /**
1010 : : * acpi_get_next_subnode - Return the next child node handle for a fwnode
1011 : : * @fwnode: Firmware node to find the next child node for.
1012 : : * @child: Handle to one of the device's child nodes or a null handle.
1013 : : */
1014 : 0 : struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
1015 : : struct fwnode_handle *child)
1016 : : {
1017 : 0 : const struct acpi_device *adev = to_acpi_device_node(fwnode);
1018 : 0 : const struct list_head *head;
1019 : 0 : struct list_head *next;
1020 : :
1021 [ # # ]: 0 : if (!child || is_acpi_device_node(child)) {
1022 : 0 : struct acpi_device *child_adev;
1023 : :
1024 [ # # ]: 0 : if (adev)
1025 : 0 : head = &adev->children;
1026 : : else
1027 : 0 : goto nondev;
1028 : :
1029 [ # # ]: 0 : if (list_empty(head))
1030 : 0 : goto nondev;
1031 : :
1032 [ # # ]: 0 : if (child) {
1033 : 0 : adev = to_acpi_device_node(child);
1034 : 0 : next = adev->node.next;
1035 [ # # ]: 0 : if (next == head) {
1036 : 0 : child = NULL;
1037 : 0 : goto nondev;
1038 : : }
1039 : 0 : child_adev = list_entry(next, struct acpi_device, node);
1040 : : } else {
1041 : 0 : child_adev = list_first_entry(head, struct acpi_device,
1042 : : node);
1043 : : }
1044 : 0 : return acpi_fwnode_handle(child_adev);
1045 : : }
1046 : :
1047 : 0 : nondev:
1048 [ # # ]: 0 : if (!child || is_acpi_data_node(child)) {
1049 : 0 : const struct acpi_data_node *data = to_acpi_data_node(fwnode);
1050 : 0 : struct acpi_data_node *dn;
1051 : :
1052 : : /*
1053 : : * We can have a combination of device and data nodes, e.g. with
1054 : : * hierarchical _DSD properties. Make sure the adev pointer is
1055 : : * restored before going through data nodes, otherwise we will
1056 : : * be looking for data_nodes below the last device found instead
1057 : : * of the common fwnode shared by device_nodes and data_nodes.
1058 : : */
1059 : 0 : adev = to_acpi_device_node(fwnode);
1060 [ # # ]: 0 : if (adev)
1061 : 0 : head = &adev->data.subnodes;
1062 [ # # ]: 0 : else if (data)
1063 : 0 : head = &data->data.subnodes;
1064 : : else
1065 : : return NULL;
1066 : :
1067 [ # # ]: 0 : if (list_empty(head))
1068 : : return NULL;
1069 : :
1070 [ # # ]: 0 : if (child) {
1071 : 0 : dn = to_acpi_data_node(child);
1072 : 0 : next = dn->sibling.next;
1073 [ # # ]: 0 : if (next == head)
1074 : : return NULL;
1075 : :
1076 : 0 : dn = list_entry(next, struct acpi_data_node, sibling);
1077 : : } else {
1078 : 0 : dn = list_first_entry(head, struct acpi_data_node, sibling);
1079 : : }
1080 : 0 : return &dn->fwnode;
1081 : : }
1082 : : return NULL;
1083 : : }
1084 : :
1085 : : /**
1086 : : * acpi_node_get_parent - Return parent fwnode of this fwnode
1087 : : * @fwnode: Firmware node whose parent to get
1088 : : *
1089 : : * Returns parent node of an ACPI device or data firmware node or %NULL if
1090 : : * not available.
1091 : : */
1092 : 0 : struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode)
1093 : : {
1094 : 0 : if (is_acpi_data_node(fwnode)) {
1095 : : /* All data nodes have parent pointer so just return that */
1096 : 0 : return to_acpi_data_node(fwnode)->parent;
1097 : 0 : } else if (is_acpi_device_node(fwnode)) {
1098 : 0 : acpi_handle handle, parent_handle;
1099 : :
1100 : 0 : handle = to_acpi_device_node(fwnode)->handle;
1101 [ # # ]: 0 : if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
1102 : 0 : struct acpi_device *adev;
1103 : :
1104 [ # # ]: 0 : if (!acpi_bus_get_device(parent_handle, &adev))
1105 : 0 : return acpi_fwnode_handle(adev);
1106 : : }
1107 : : }
1108 : :
1109 : : return NULL;
1110 : : }
1111 : :
1112 : : /*
1113 : : * Return true if the node is an ACPI graph node. Called on either ports
1114 : : * or endpoints.
1115 : : */
1116 : 0 : static bool is_acpi_graph_node(struct fwnode_handle *fwnode,
1117 : : const char *str)
1118 : : {
1119 : 0 : unsigned int len = strlen(str);
1120 : 0 : const char *name;
1121 : :
1122 [ # # ]: 0 : if (!len || !is_acpi_data_node(fwnode))
1123 : : return false;
1124 : :
1125 : 0 : name = to_acpi_data_node(fwnode)->name;
1126 : :
1127 : 0 : return (fwnode_property_present(fwnode, "reg") &&
1128 [ # # # # : 0 : !strncmp(name, str, len) && name[len] == '@') ||
# # # # ]
1129 : 0 : fwnode_property_present(fwnode, str);
1130 : : }
1131 : :
1132 : : /**
1133 : : * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node
1134 : : * @fwnode: Pointer to the parent firmware node
1135 : : * @prev: Previous endpoint node or %NULL to get the first
1136 : : *
1137 : : * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns
1138 : : * %NULL if there is no next endpoint or in case of error. In case of success
1139 : : * the next endpoint is returned.
1140 : : */
1141 : 0 : static struct fwnode_handle *acpi_graph_get_next_endpoint(
1142 : : const struct fwnode_handle *fwnode, struct fwnode_handle *prev)
1143 : : {
1144 : 0 : struct fwnode_handle *port = NULL;
1145 : 0 : struct fwnode_handle *endpoint;
1146 : :
1147 [ # # ]: 0 : if (!prev) {
1148 : 0 : do {
1149 : 0 : port = fwnode_get_next_child_node(fwnode, port);
1150 : : /*
1151 : : * The names of the port nodes begin with "port@"
1152 : : * followed by the number of the port node and they also
1153 : : * have a "reg" property that also has the number of the
1154 : : * port node. For compatibility reasons a node is also
1155 : : * recognised as a port node from the "port" property.
1156 : : */
1157 [ # # ]: 0 : if (is_acpi_graph_node(port, "port"))
1158 : : break;
1159 [ # # ]: 0 : } while (port);
1160 : : } else {
1161 : 0 : port = fwnode_get_parent(prev);
1162 : : }
1163 : :
1164 [ # # ]: 0 : if (!port)
1165 : : return NULL;
1166 : :
1167 : 0 : endpoint = fwnode_get_next_child_node(port, prev);
1168 [ # # ]: 0 : while (!endpoint) {
1169 : 0 : port = fwnode_get_next_child_node(fwnode, port);
1170 [ # # ]: 0 : if (!port)
1171 : : break;
1172 [ # # ]: 0 : if (is_acpi_graph_node(port, "port"))
1173 : 0 : endpoint = fwnode_get_next_child_node(port, NULL);
1174 : : }
1175 : :
1176 : : /*
1177 : : * The names of the endpoint nodes begin with "endpoint@" followed by
1178 : : * the number of the endpoint node and they also have a "reg" property
1179 : : * that also has the number of the endpoint node. For compatibility
1180 : : * reasons a node is also recognised as an endpoint node from the
1181 : : * "endpoint" property.
1182 : : */
1183 [ # # ]: 0 : if (!is_acpi_graph_node(endpoint, "endpoint"))
1184 : 0 : return NULL;
1185 : :
1186 : : return endpoint;
1187 : : }
1188 : :
1189 : : /**
1190 : : * acpi_graph_get_child_prop_value - Return a child with a given property value
1191 : : * @fwnode: device fwnode
1192 : : * @prop_name: The name of the property to look for
1193 : : * @val: the desired property value
1194 : : *
1195 : : * Return the port node corresponding to a given port number. Returns
1196 : : * the child node on success, NULL otherwise.
1197 : : */
1198 : 0 : static struct fwnode_handle *acpi_graph_get_child_prop_value(
1199 : : const struct fwnode_handle *fwnode, const char *prop_name,
1200 : : unsigned int val)
1201 : : {
1202 : 0 : struct fwnode_handle *child;
1203 : :
1204 [ # # ]: 0 : fwnode_for_each_child_node(fwnode, child) {
1205 : 0 : u32 nr;
1206 : :
1207 [ # # ]: 0 : if (fwnode_property_read_u32(child, prop_name, &nr))
1208 : 0 : continue;
1209 : :
1210 [ # # ]: 0 : if (val == nr)
1211 : 0 : return child;
1212 : : }
1213 : :
1214 : : return NULL;
1215 : : }
1216 : :
1217 : :
1218 : : /**
1219 : : * acpi_graph_get_remote_endpoint - Parses and returns remote end of an endpoint
1220 : : * @fwnode: Endpoint firmware node pointing to a remote device
1221 : : * @endpoint: Firmware node of remote endpoint is filled here if not %NULL
1222 : : *
1223 : : * Returns the remote endpoint corresponding to @__fwnode. NULL on error.
1224 : : */
1225 : : static struct fwnode_handle *
1226 : 0 : acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode)
1227 : : {
1228 : 0 : struct fwnode_handle *fwnode;
1229 : 0 : unsigned int port_nr, endpoint_nr;
1230 : 0 : struct fwnode_reference_args args;
1231 : 0 : int ret;
1232 : :
1233 : 0 : memset(&args, 0, sizeof(args));
1234 : 0 : ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0,
1235 : : &args);
1236 [ # # ]: 0 : if (ret)
1237 : : return NULL;
1238 : :
1239 : : /* Direct endpoint reference? */
1240 : 0 : if (!is_acpi_device_node(args.fwnode))
1241 [ # # ]: 0 : return args.nargs ? NULL : args.fwnode;
1242 : :
1243 : : /*
1244 : : * Always require two arguments with the reference: port and
1245 : : * endpoint indices.
1246 : : */
1247 [ # # ]: 0 : if (args.nargs != 2)
1248 : : return NULL;
1249 : :
1250 : 0 : fwnode = args.fwnode;
1251 : 0 : port_nr = args.args[0];
1252 : 0 : endpoint_nr = args.args[1];
1253 : :
1254 : 0 : fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
1255 : :
1256 : 0 : return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr);
1257 : : }
1258 : :
1259 : 0 : static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
1260 : : {
1261 : 0 : if (!is_acpi_device_node(fwnode))
1262 : : return false;
1263 : :
1264 : 0 : return acpi_device_is_present(to_acpi_device_node(fwnode));
1265 : : }
1266 : :
1267 : 78 : static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
1268 : : const char *propname)
1269 : : {
1270 : 78 : return !acpi_node_prop_get(fwnode, propname, NULL);
1271 : : }
1272 : :
1273 : : static int
1274 : 0 : acpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
1275 : : const char *propname,
1276 : : unsigned int elem_size, void *val,
1277 : : size_t nval)
1278 : : {
1279 : 0 : enum dev_prop_type type;
1280 : :
1281 [ # # # # : 0 : switch (elem_size) {
# ]
1282 : : case sizeof(u8):
1283 : : type = DEV_PROP_U8;
1284 : : break;
1285 : 0 : case sizeof(u16):
1286 : 0 : type = DEV_PROP_U16;
1287 : 0 : break;
1288 : 0 : case sizeof(u32):
1289 : 0 : type = DEV_PROP_U32;
1290 : 0 : break;
1291 : 0 : case sizeof(u64):
1292 : 0 : type = DEV_PROP_U64;
1293 : 0 : break;
1294 : : default:
1295 : : return -ENXIO;
1296 : : }
1297 : :
1298 : 0 : return acpi_node_prop_read(fwnode, propname, type, val, nval);
1299 : : }
1300 : :
1301 : : static int
1302 : 0 : acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
1303 : : const char *propname, const char **val,
1304 : : size_t nval)
1305 : : {
1306 : 0 : return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
1307 : : val, nval);
1308 : : }
1309 : :
1310 : : static int
1311 : 0 : acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
1312 : : const char *prop, const char *nargs_prop,
1313 : : unsigned int args_count, unsigned int index,
1314 : : struct fwnode_reference_args *args)
1315 : : {
1316 : 0 : return __acpi_node_get_property_reference(fwnode, prop, index,
1317 : : args_count, args);
1318 : : }
1319 : :
1320 : 0 : static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode)
1321 : : {
1322 : 0 : const struct acpi_device *adev;
1323 : 0 : struct fwnode_handle *parent;
1324 : :
1325 : : /* Is this the root node? */
1326 : 0 : parent = fwnode_get_parent(fwnode);
1327 [ # # ]: 0 : if (!parent)
1328 : : return "\\";
1329 : :
1330 : 0 : fwnode_handle_put(parent);
1331 : :
1332 : 0 : if (is_acpi_data_node(fwnode)) {
1333 : 0 : const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
1334 : :
1335 : 0 : return dn->name;
1336 : : }
1337 : :
1338 : 0 : adev = to_acpi_device_node(fwnode);
1339 [ # # # # ]: 0 : if (WARN_ON(!adev))
1340 : : return NULL;
1341 : :
1342 : 0 : return acpi_device_bid(adev);
1343 : : }
1344 : :
1345 : : static const char *
1346 : 0 : acpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
1347 : : {
1348 : 0 : struct fwnode_handle *parent;
1349 : :
1350 : : /* Is this the root node? */
1351 : 0 : parent = fwnode_get_parent(fwnode);
1352 [ # # ]: 0 : if (!parent)
1353 : : return "";
1354 : :
1355 : : /* Is this 2nd node from the root? */
1356 : 0 : parent = fwnode_get_next_parent(parent);
1357 [ # # ]: 0 : if (!parent)
1358 : : return "";
1359 : :
1360 : 0 : fwnode_handle_put(parent);
1361 : :
1362 : : /* ACPI device or data node. */
1363 : 0 : return ".";
1364 : : }
1365 : :
1366 : : static struct fwnode_handle *
1367 : 0 : acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
1368 : : {
1369 : 0 : return acpi_node_get_parent(fwnode);
1370 : : }
1371 : :
1372 : 0 : static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
1373 : : struct fwnode_endpoint *endpoint)
1374 : : {
1375 : 0 : struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
1376 : :
1377 : 0 : endpoint->local_fwnode = fwnode;
1378 : :
1379 [ # # ]: 0 : if (fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port))
1380 : 0 : fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
1381 [ # # ]: 0 : if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id))
1382 : 0 : fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
1383 : :
1384 : 0 : return 0;
1385 : : }
1386 : :
1387 : : static const void *
1388 : 0 : acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
1389 : : const struct device *dev)
1390 : : {
1391 : 0 : return acpi_device_get_match_data(dev);
1392 : : }
1393 : :
1394 : : #define DECLARE_ACPI_FWNODE_OPS(ops) \
1395 : : const struct fwnode_operations ops = { \
1396 : : .device_is_available = acpi_fwnode_device_is_available, \
1397 : : .device_get_match_data = acpi_fwnode_device_get_match_data, \
1398 : : .property_present = acpi_fwnode_property_present, \
1399 : : .property_read_int_array = \
1400 : : acpi_fwnode_property_read_int_array, \
1401 : : .property_read_string_array = \
1402 : : acpi_fwnode_property_read_string_array, \
1403 : : .get_parent = acpi_node_get_parent, \
1404 : : .get_next_child_node = acpi_get_next_subnode, \
1405 : : .get_named_child_node = acpi_fwnode_get_named_child_node, \
1406 : : .get_name = acpi_fwnode_get_name, \
1407 : : .get_name_prefix = acpi_fwnode_get_name_prefix, \
1408 : : .get_reference_args = acpi_fwnode_get_reference_args, \
1409 : : .graph_get_next_endpoint = \
1410 : : acpi_graph_get_next_endpoint, \
1411 : : .graph_get_remote_endpoint = \
1412 : : acpi_graph_get_remote_endpoint, \
1413 : : .graph_get_port_parent = acpi_fwnode_get_parent, \
1414 : : .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
1415 : : }; \
1416 : : EXPORT_SYMBOL_GPL(ops)
1417 : :
1418 : : DECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops);
1419 : : DECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops);
1420 : : const struct fwnode_operations acpi_static_fwnode_ops;
1421 : :
1422 : 69363 : bool is_acpi_device_node(const struct fwnode_handle *fwnode)
1423 : : {
1424 [ + + + + : 82902 : return !IS_ERR_OR_NULL(fwnode) &&
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- + - + -
+ - + - +
- + - ]
1425 [ - + - - : 13461 : fwnode->ops == &acpi_device_fwnode_ops;
- - - - -
- - - - -
- - - - -
- - - - -
- + - + ]
1426 : : }
1427 : : EXPORT_SYMBOL(is_acpi_device_node);
1428 : :
1429 : 0 : bool is_acpi_data_node(const struct fwnode_handle *fwnode)
1430 : : {
1431 [ # # # # : 0 : return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops;
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1432 : : }
1433 : : EXPORT_SYMBOL(is_acpi_data_node);
|