aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2016-09-29 09:39:41 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-10-11 16:44:00 -0400
commitb60e4ea4a400bde8a4811f94b84a9bb65f81b677 (patch)
treec280735891b88f947481dab0df0e4607ff253d48
parent20a875e2e86e73d13ec256781a7d55a7885868ec (diff)
ACPI / property: Allow holes in reference properties
DT allows holes or empty phandles for references. This is used for example in SPI subsystem where some chip selects are native and others are regular GPIOs. In ACPI _DSD we currently do not support this but instead the preceding reference consumes all following integer arguments. For example we would like to support something like the below ASL fragment for SPI: Package () { "cs-gpios", Package () { ^GPIO, 19, 0, 0, // GPIO CS0 0, // Native CS ^GPIO, 20, 0, 0, // GPIO CS1 } } The zero in the middle means "no entry" or NULL reference. To support this we change acpi_data_get_property_reference() to take firmware node and num_args as argument and rename it to __acpi_node_get_property_reference(). The function returns -ENOENT if the given index resolves to "no entry" reference and -ENODATA when there are no more entries in the property. We then add static inline wrapper acpi_node_get_property_reference() that passes MAX_ACPI_REFERENCE_ARGS as num_args to support the existing behaviour which some drivers have been relying on. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/property.c117
-rw-r--r--include/linux/acpi.h22
2 files changed, 87 insertions, 52 deletions
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index f2fd3fee588a..03f5ec11ab31 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -468,10 +468,11 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
468} 468}
469 469
470/** 470/**
471 * acpi_data_get_property_reference - returns handle to the referenced object 471 * __acpi_node_get_property_reference - returns handle to the referenced object
472 * @data: ACPI device data object containing the property 472 * @fwnode: Firmware node to get the property from
473 * @propname: Name of the property 473 * @propname: Name of the property
474 * @index: Index of the reference to return 474 * @index: Index of the reference to return
475 * @num_args: Maximum number of arguments after each reference
475 * @args: Location to store the returned reference with optional arguments 476 * @args: Location to store the returned reference with optional arguments
476 * 477 *
477 * Find property with @name, verifify that it is a package containing at least 478 * Find property with @name, verifify that it is a package containing at least
@@ -482,17 +483,40 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
482 * If there's more than one reference in the property value package, @index is 483 * If there's more than one reference in the property value package, @index is
483 * used to select the one to return. 484 * used to select the one to return.
484 * 485 *
486 * It is possible to leave holes in the property value set like in the
487 * example below:
488 *
489 * Package () {
490 * "cs-gpios",
491 * Package () {
492 * ^GPIO, 19, 0, 0,
493 * ^GPIO, 20, 0, 0,
494 * 0,
495 * ^GPIO, 21, 0, 0,
496 * }
497 * }
498 *
499 * Calling this function with index %2 return %-ENOENT and with index %3
500 * returns the last entry. If the property does not contain any more values
501 * %-ENODATA is returned. The NULL entry must be single integer and
502 * preferably contain value %0.
503 *
485 * Return: %0 on success, negative error code on failure. 504 * Return: %0 on success, negative error code on failure.
486 */ 505 */
487static int acpi_data_get_property_reference(struct acpi_device_data *data, 506int __acpi_node_get_property_reference(struct fwnode_handle *fwnode,
488 const char *propname, size_t index, 507 const char *propname, size_t index, size_t num_args,
489 struct acpi_reference_args *args) 508 struct acpi_reference_args *args)
490{ 509{
491 const union acpi_object *element, *end; 510 const union acpi_object *element, *end;
492 const union acpi_object *obj; 511 const union acpi_object *obj;
512 struct acpi_device_data *data;
493 struct acpi_device *device; 513 struct acpi_device *device;
494 int ret, idx = 0; 514 int ret, idx = 0;
495 515
516 data = acpi_device_data_of_node(fwnode);
517 if (!data)
518 return -EINVAL;
519
496 ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj); 520 ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
497 if (ret) 521 if (ret)
498 return ret; 522 return ret;
@@ -532,59 +556,54 @@ static int acpi_data_get_property_reference(struct acpi_device_data *data,
532 while (element < end) { 556 while (element < end) {
533 u32 nargs, i; 557 u32 nargs, i;
534 558
535 if (element->type != ACPI_TYPE_LOCAL_REFERENCE) 559 if (element->type == ACPI_TYPE_LOCAL_REFERENCE) {
536 return -EPROTO; 560 ret = acpi_bus_get_device(element->reference.handle,
537 561 &device);
538 ret = acpi_bus_get_device(element->reference.handle, &device); 562 if (ret)
539 if (ret) 563 return -ENODEV;
540 return -ENODEV; 564
541 565 nargs = 0;
542 element++; 566 element++;
543 nargs = 0; 567
544 568 /* assume following integer elements are all args */
545 /* assume following integer elements are all args */ 569 for (i = 0; element + i < end && i < num_args; i++) {
546 for (i = 0; element + i < end; i++) { 570 int type = element[i].type;
547 int type = element[i].type; 571
572 if (type == ACPI_TYPE_INTEGER)
573 nargs++;
574 else if (type == ACPI_TYPE_LOCAL_REFERENCE)
575 break;
576 else
577 return -EPROTO;
578 }
548 579
549 if (type == ACPI_TYPE_INTEGER) 580 if (nargs > MAX_ACPI_REFERENCE_ARGS)
550 nargs++;
551 else if (type == ACPI_TYPE_LOCAL_REFERENCE)
552 break;
553 else
554 return -EPROTO; 581 return -EPROTO;
555 }
556 582
557 if (idx++ == index) { 583 if (idx == index) {
558 args->adev = device; 584 args->adev = device;
559 args->nargs = nargs; 585 args->nargs = nargs;
560 for (i = 0; i < nargs; i++) 586 for (i = 0; i < nargs; i++)
561 args->args[i] = element[i].integer.value; 587 args->args[i] = element[i].integer.value;
562 588
563 return 0; 589 return 0;
590 }
591
592 element += nargs;
593 } else if (element->type == ACPI_TYPE_INTEGER) {
594 if (idx == index)
595 return -ENOENT;
596 element++;
597 } else {
598 return -EPROTO;
564 } 599 }
565 600
566 element += nargs; 601 idx++;
567 } 602 }
568 603
569 return -EPROTO; 604 return -ENODATA;
570}
571
572/**
573 * acpi_node_get_property_reference - get a handle to the referenced object.
574 * @fwnode: Firmware node to get the property from.
575 * @propname: Name of the property.
576 * @index: Index of the reference to return.
577 * @args: Location to store the returned reference with optional arguments.
578 */
579int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
580 const char *name, size_t index,
581 struct acpi_reference_args *args)
582{
583 struct acpi_device_data *data = acpi_device_data_of_node(fwnode);
584
585 return data ? acpi_data_get_property_reference(data, name, index, args) : -EINVAL;
586} 605}
587EXPORT_SYMBOL_GPL(acpi_node_get_property_reference); 606EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference);
588 607
589static int acpi_data_prop_read_single(struct acpi_device_data *data, 608static int acpi_data_prop_read_single(struct acpi_device_data *data,
590 const char *propname, 609 const char *propname,
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4d8452c2384b..632ec16a855e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -927,9 +927,17 @@ struct acpi_reference_args {
927#ifdef CONFIG_ACPI 927#ifdef CONFIG_ACPI
928int acpi_dev_get_property(struct acpi_device *adev, const char *name, 928int acpi_dev_get_property(struct acpi_device *adev, const char *name,
929 acpi_object_type type, const union acpi_object **obj); 929 acpi_object_type type, const union acpi_object **obj);
930int acpi_node_get_property_reference(struct fwnode_handle *fwnode, 930int __acpi_node_get_property_reference(struct fwnode_handle *fwnode,
931 const char *name, size_t index, 931 const char *name, size_t index, size_t num_args,
932 struct acpi_reference_args *args); 932 struct acpi_reference_args *args);
933
934static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
935 const char *name, size_t index,
936 struct acpi_reference_args *args)
937{
938 return __acpi_node_get_property_reference(fwnode, name, index,
939 MAX_ACPI_REFERENCE_ARGS, args);
940}
933 941
934int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname, 942int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
935 void **valptr); 943 void **valptr);
@@ -1005,6 +1013,14 @@ static inline int acpi_dev_get_property(struct acpi_device *adev,
1005 return -ENXIO; 1013 return -ENXIO;
1006} 1014}
1007 1015
1016static inline int
1017__acpi_node_get_property_reference(struct fwnode_handle *fwnode,
1018 const char *name, size_t index, size_t num_args,
1019 struct acpi_reference_args *args)
1020{
1021 return -ENXIO;
1022}
1023
1008static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode, 1024static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
1009 const char *name, size_t index, 1025 const char *name, size_t index,
1010 struct acpi_reference_args *args) 1026 struct acpi_reference_args *args)