Skip to content

Commit b60e4ea

Browse files
westerirafaeljw
authored andcommitted
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 <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 20a875e commit b60e4ea

File tree

2 files changed

+87
-52
lines changed

2 files changed

+87
-52
lines changed

drivers/acpi/property.c

Lines changed: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -468,10 +468,11 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
468468
}
469469

470470
/**
471-
* acpi_data_get_property_reference - returns handle to the referenced object
472-
* @data: ACPI device data object containing the property
471+
* __acpi_node_get_property_reference - returns handle to the referenced object
472+
* @fwnode: Firmware node to get the property from
473473
* @propname: Name of the property
474474
* @index: Index of the reference to return
475+
* @num_args: Maximum number of arguments after each reference
475476
* @args: Location to store the returned reference with optional arguments
476477
*
477478
* 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,
482483
* If there's more than one reference in the property value package, @index is
483484
* used to select the one to return.
484485
*
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+
*
485504
* Return: %0 on success, negative error code on failure.
486505
*/
487-
static int acpi_data_get_property_reference(struct acpi_device_data *data,
488-
const char *propname, size_t index,
489-
struct acpi_reference_args *args)
506+
int __acpi_node_get_property_reference(struct fwnode_handle *fwnode,
507+
const char *propname, size_t index, size_t num_args,
508+
struct acpi_reference_args *args)
490509
{
491510
const union acpi_object *element, *end;
492511
const union acpi_object *obj;
512+
struct acpi_device_data *data;
493513
struct acpi_device *device;
494514
int ret, idx = 0;
495515

516+
data = acpi_device_data_of_node(fwnode);
517+
if (!data)
518+
return -EINVAL;
519+
496520
ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
497521
if (ret)
498522
return ret;
@@ -532,59 +556,54 @@ static int acpi_data_get_property_reference(struct acpi_device_data *data,
532556
while (element < end) {
533557
u32 nargs, i;
534558

535-
if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
536-
return -EPROTO;
537-
538-
ret = acpi_bus_get_device(element->reference.handle, &device);
539-
if (ret)
540-
return -ENODEV;
541-
542-
element++;
543-
nargs = 0;
544-
545-
/* assume following integer elements are all args */
546-
for (i = 0; element + i < end; i++) {
547-
int type = element[i].type;
559+
if (element->type == ACPI_TYPE_LOCAL_REFERENCE) {
560+
ret = acpi_bus_get_device(element->reference.handle,
561+
&device);
562+
if (ret)
563+
return -ENODEV;
564+
565+
nargs = 0;
566+
element++;
567+
568+
/* assume following integer elements are all args */
569+
for (i = 0; element + i < end && i < num_args; i++) {
570+
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+
}
548579

549-
if (type == ACPI_TYPE_INTEGER)
550-
nargs++;
551-
else if (type == ACPI_TYPE_LOCAL_REFERENCE)
552-
break;
553-
else
580+
if (nargs > MAX_ACPI_REFERENCE_ARGS)
554581
return -EPROTO;
555-
}
556582

557-
if (idx++ == index) {
558-
args->adev = device;
559-
args->nargs = nargs;
560-
for (i = 0; i < nargs; i++)
561-
args->args[i] = element[i].integer.value;
583+
if (idx == index) {
584+
args->adev = device;
585+
args->nargs = nargs;
586+
for (i = 0; i < nargs; i++)
587+
args->args[i] = element[i].integer.value;
562588

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;
564599
}
565600

566-
element += nargs;
601+
idx++;
567602
}
568603

569-
return -EPROTO;
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-
*/
579-
int 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;
604+
return -ENODATA;
586605
}
587-
EXPORT_SYMBOL_GPL(acpi_node_get_property_reference);
606+
EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference);
588607

589608
static int acpi_data_prop_read_single(struct acpi_device_data *data,
590609
const char *propname,

include/linux/acpi.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -927,9 +927,17 @@ struct acpi_reference_args {
927927
#ifdef CONFIG_ACPI
928928
int acpi_dev_get_property(struct acpi_device *adev, const char *name,
929929
acpi_object_type type, const union acpi_object **obj);
930-
int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
931-
const char *name, size_t index,
932-
struct acpi_reference_args *args);
930+
int __acpi_node_get_property_reference(struct fwnode_handle *fwnode,
931+
const char *name, size_t index, size_t num_args,
932+
struct acpi_reference_args *args);
933+
934+
static 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+
}
933941

934942
int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
935943
void **valptr);
@@ -1005,6 +1013,14 @@ static inline int acpi_dev_get_property(struct acpi_device *adev,
10051013
return -ENXIO;
10061014
}
10071015

1016+
static 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+
10081024
static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
10091025
const char *name, size_t index,
10101026
struct acpi_reference_args *args)

0 commit comments

Comments
 (0)