summaryrefslogtreecommitdiff
path: root/drivers/acpi/property.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-11-22 00:02:19 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-11-24 02:43:47 +0100
commit99db5ff7fe0b4e1657423d7bbe2aa8f655dd02d1 (patch)
tree16f7b7203b451a951fb9bd1d0a0e29edebf7122c /drivers/acpi/property.c
parent9c763584b7c8911106bb77af7e648bef09af9d80 (diff)
downloadlwn-99db5ff7fe0b4e1657423d7bbe2aa8f655dd02d1.tar.gz
lwn-99db5ff7fe0b4e1657423d7bbe2aa8f655dd02d1.zip
ACPI / property: Hierarchical properties support update
The definition document of the Hierarchical Properties Extension UUID for _DSD has been changed recently to allow local references to be used as sub-node link targets (previously, it only allowed strings to be used for that purpose). Update the code in drivers/acpi/property.c to reflect that change. Link: http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/property.c')
-rw-r--r--drivers/acpi/property.c125
1 files changed, 89 insertions, 36 deletions
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 03f5ec11ab31..3afddcd834ef 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
static bool acpi_extract_properties(const union acpi_object *desc,
struct acpi_device_data *data);
-static bool acpi_nondev_subnode_ok(acpi_handle scope,
- const union acpi_object *link,
- struct list_head *list)
+static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
+ acpi_handle handle,
+ const union acpi_object *link,
+ struct list_head *list)
{
- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
struct acpi_data_node *dn;
- acpi_handle handle;
- acpi_status status;
+ bool result;
dn = kzalloc(sizeof(*dn), GFP_KERNEL);
if (!dn)
@@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
dn->fwnode.type = FWNODE_ACPI_DATA;
INIT_LIST_HEAD(&dn->data.subnodes);
- status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
- &handle);
- if (ACPI_FAILURE(status))
- goto fail;
+ result = acpi_extract_properties(desc, &dn->data);
- status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
- ACPI_TYPE_PACKAGE);
- if (ACPI_FAILURE(status))
- goto fail;
+ if (handle) {
+ acpi_handle scope;
+ acpi_status status;
- if (acpi_extract_properties(buf.pointer, &dn->data))
- dn->handle = handle;
+ /*
+ * The scope for the subnode object lookup is the one of the
+ * namespace node (device) containing the object that has
+ * returned the package. That is, it's the scope of that
+ * object's parent.
+ */
+ status = acpi_get_parent(handle, &scope);
+ if (ACPI_SUCCESS(status)
+ && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
+ result = true;
+ } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
+ result = true;
+ }
- /*
- * The scope for the subnode object lookup is the one of the namespace
- * node (device) containing the object that has returned the package.
- * That is, it's the scope of that object's parent.
- */
- status = acpi_get_parent(handle, &scope);
- if (ACPI_SUCCESS(status)
- && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
+ if (result) {
dn->handle = handle;
-
- if (dn->handle) {
- dn->data.pointer = buf.pointer;
+ dn->data.pointer = desc;
list_add_tail(&dn->sibling, list);
return true;
}
+ kfree(dn);
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
+ return false;
+}
+
+static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
+ const union acpi_object *link,
+ struct list_head *list)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ acpi_status status;
+
+ status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
+ return true;
- fail:
ACPI_FREE(buf.pointer);
- kfree(dn);
return false;
}
+static bool acpi_nondev_subnode_ok(acpi_handle scope,
+ const union acpi_object *link,
+ struct list_head *list)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!scope)
+ return false;
+
+ status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
+ &handle);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ return acpi_nondev_subnode_data_ok(handle, link, list);
+}
+
static int acpi_add_nondev_subnodes(acpi_handle scope,
const union acpi_object *links,
struct list_head *list)
@@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
int i;
for (i = 0; i < links->package.count; i++) {
- const union acpi_object *link;
+ const union acpi_object *link, *desc;
+ acpi_handle handle;
+ bool result;
link = &links->package.elements[i];
- /* Only two elements allowed, both must be strings. */
- if (link->package.count == 2
- && link->package.elements[0].type == ACPI_TYPE_STRING
- && link->package.elements[1].type == ACPI_TYPE_STRING
- && acpi_nondev_subnode_ok(scope, link, list))
- ret = true;
+ /* Only two elements allowed. */
+ if (link->package.count != 2)
+ continue;
+
+ /* The first one must be a string. */
+ if (link->package.elements[0].type != ACPI_TYPE_STRING)
+ continue;
+
+ /* The second one may be a string, a reference or a package. */
+ switch (link->package.elements[1].type) {
+ case ACPI_TYPE_STRING:
+ result = acpi_nondev_subnode_ok(scope, link, list);
+ break;
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ handle = link->package.elements[1].reference.handle;
+ result = acpi_nondev_subnode_data_ok(handle, link, list);
+ break;
+ case ACPI_TYPE_PACKAGE:
+ desc = &link->package.elements[1];
+ result = acpi_nondev_subnode_extract(desc, NULL, link, list);
+ break;
+ default:
+ result = false;
+ break;
+ }
+ ret = ret || result;
}
return ret;