ACPI / property: Add possiblity to retrieve parent firmware node
authorMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 28 Mar 2017 07:52:16 +0000 (10:52 +0300)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 28 Mar 2017 22:00:27 +0000 (00:00 +0200)
Sometimes it is useful to be able to navigate firmware node hierarchy
upwards toward parent nodes. ACPI device nodes are pretty much already
supported because ACPICA provides acpi_get_parent(). ACPI data nodes,
however, are all below the same parent ACPI device. Their hierarchy is
created by "linking" each other using references in the value field.

Add parent pointer to the parent data node while we create them so it is
easy to navigate the hierarchy backwards. We use this parent pointer in a
new function acpi_node_get_parent() that is able to extract parent of both
ACPI firmware node types.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/property.c
include/acpi/acpi_bus.h
include/linux/acpi.h

index 3afddcd834efdb407f8b5dec1bebf42ce704c0c5..587c9d000f0e6705ff590ffd2e3ae86bdc98be8f 100644 (file)
@@ -37,14 +37,16 @@ static const u8 ads_uuid[16] = {
 
 static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
                                           const union acpi_object *desc,
-                                          struct acpi_device_data *data);
+                                          struct acpi_device_data *data,
+                                          struct fwnode_handle *parent);
 static bool acpi_extract_properties(const union acpi_object *desc,
                                    struct acpi_device_data *data);
 
 static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
                                        acpi_handle handle,
                                        const union acpi_object *link,
-                                       struct list_head *list)
+                                       struct list_head *list,
+                                       struct fwnode_handle *parent)
 {
        struct acpi_data_node *dn;
        bool result;
@@ -55,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
 
        dn->name = link->package.elements[0].string.pointer;
        dn->fwnode.type = FWNODE_ACPI_DATA;
+       dn->parent = parent;
        INIT_LIST_HEAD(&dn->data.subnodes);
 
        result = acpi_extract_properties(desc, &dn->data);
@@ -71,9 +74,11 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
                 */
                status = acpi_get_parent(handle, &scope);
                if (ACPI_SUCCESS(status)
-                   && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
+                   && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data,
+                                                     &dn->fwnode))
                        result = true;
-       } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
+       } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data,
+                                                 &dn->fwnode)) {
                result = true;
        }
 
@@ -91,7 +96,8 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
 
 static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
                                        const union acpi_object *link,
-                                       struct list_head *list)
+                                       struct list_head *list,
+                                       struct fwnode_handle *parent)
 {
        struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
        acpi_status status;
@@ -101,7 +107,8 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
        if (ACPI_FAILURE(status))
                return false;
 
-       if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
+       if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
+                                       parent))
                return true;
 
        ACPI_FREE(buf.pointer);
@@ -110,7 +117,8 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
 
 static bool acpi_nondev_subnode_ok(acpi_handle scope,
                                   const union acpi_object *link,
-                                  struct list_head *list)
+                                  struct list_head *list,
+                                  struct fwnode_handle *parent)
 {
        acpi_handle handle;
        acpi_status status;
@@ -123,12 +131,13 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
        if (ACPI_FAILURE(status))
                return false;
 
-       return acpi_nondev_subnode_data_ok(handle, link, list);
+       return acpi_nondev_subnode_data_ok(handle, link, list, parent);
 }
 
 static int acpi_add_nondev_subnodes(acpi_handle scope,
                                    const union acpi_object *links,
-                                   struct list_head *list)
+                                   struct list_head *list,
+                                   struct fwnode_handle *parent)
 {
        bool ret = false;
        int i;
@@ -150,15 +159,18 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
                /* 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);
+                       result = acpi_nondev_subnode_ok(scope, link, list,
+                                                        parent);
                        break;
                case ACPI_TYPE_LOCAL_REFERENCE:
                        handle = link->package.elements[1].reference.handle;
-                       result = acpi_nondev_subnode_data_ok(handle, link, list);
+                       result = acpi_nondev_subnode_data_ok(handle, link, list,
+                                                            parent);
                        break;
                case ACPI_TYPE_PACKAGE:
                        desc = &link->package.elements[1];
-                       result = acpi_nondev_subnode_extract(desc, NULL, link, list);
+                       result = acpi_nondev_subnode_extract(desc, NULL, link,
+                                                            list, parent);
                        break;
                default:
                        result = false;
@@ -172,7 +184,8 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
 
 static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
                                           const union acpi_object *desc,
-                                          struct acpi_device_data *data)
+                                          struct acpi_device_data *data,
+                                          struct fwnode_handle *parent)
 {
        int i;
 
@@ -194,7 +207,8 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
                if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid)))
                        continue;
 
-               return acpi_add_nondev_subnodes(scope, links, &data->subnodes);
+               return acpi_add_nondev_subnodes(scope, links, &data->subnodes,
+                                               parent);
        }
 
        return false;
@@ -345,7 +359,8 @@ void acpi_init_properties(struct acpi_device *adev)
                if (acpi_of)
                        acpi_init_of_compatible(adev);
        }
-       if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data))
+       if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer,
+                                       &adev->data, acpi_fwnode_handle(adev)))
                adev->data.pointer = buf.pointer;
 
        if (!adev->data.pointer) {
@@ -920,3 +935,30 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
        }
        return NULL;
 }
+
+/**
+ * acpi_node_get_parent - Return parent fwnode of this fwnode
+ * @fwnode: Firmware node whose parent to get
+ *
+ * Returns parent node of an ACPI device or data firmware node or %NULL if
+ * not available.
+ */
+struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode)
+{
+       if (is_acpi_data_node(fwnode)) {
+               /* All data nodes have parent pointer so just return that */
+               return to_acpi_data_node(fwnode)->parent;
+       } else if (is_acpi_device_node(fwnode)) {
+               acpi_handle handle, parent_handle;
+
+               handle = to_acpi_device_node(fwnode)->handle;
+               if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
+                       struct acpi_device *adev;
+
+                       if (!acpi_bus_get_device(parent_handle, &adev))
+                               return acpi_fwnode_handle(adev);
+               }
+       }
+
+       return NULL;
+}
index ef0ae8aaa56771a3a1c4e00a4712f55cbdda9114..49cca52b214bb5a5ab554acf5251495457876bc2 100644 (file)
@@ -386,6 +386,7 @@ struct acpi_data_node {
        const char *name;
        acpi_handle handle;
        struct fwnode_handle fwnode;
+       struct fwnode_handle *parent;
        struct acpi_device_data data;
        struct list_head sibling;
        struct kobject kobj;
index 9b05886f9773cde8439a0c3e21b39ad29460c440..e74e8bdbb6afd1c8be34242b5784ff9bdd05d31d 100644 (file)
@@ -999,6 +999,7 @@ int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
 
 struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
                                            struct fwnode_handle *subnode);
+struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode);
 
 struct acpi_probe_entry;
 typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *,
@@ -1121,6 +1122,12 @@ static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
        return NULL;
 }
 
+static inline struct fwnode_handle *
+acpi_node_get_parent(struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
 #define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
        static const void * __acpi_table_##name[]                       \
                __attribute__((unused))                                 \