ACPI / property: Add fwnode_get_next_child_node()
authorMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 28 Mar 2017 07:52:18 +0000 (10:52 +0300)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 28 Mar 2017 22:00:27 +0000 (00:00 +0200)
The ACPI _DSD hierarchical data extension makes it possible to have
hierarchies deeper than one level in similar way than DT allows. These
"subsubnodes" have not been accessible because device property
implementation only provides device_get_next_child_node() that is limited
to direct descendants of a device.

We need this ability in order support things like remote endpoints
currently supported in DT with of_graph_* APIs.

Modify acpi_get_next_subnode() to accept fwnode handle instead and update
callers accordingly. Also add a new function fwnode_get_next_child_node()
that works directly with fwnodes and modify device_get_next_child_node() to
call it directly. While there add a macro fwnode_for_each_child_node()
analogous to the current device_for_each_child_node() but it works with
fwnodes instead of devices.

Link: http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.pdf
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
drivers/base/property.c
include/linux/acpi.h
include/linux/property.h

index 587c9d000f0e6705ff590ffd2e3ae86bdc98be8f..8730ce745b43d4ba1b88659b27cb42b95700106a 100644 (file)
@@ -880,21 +880,22 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode,  const char *propname,
 }
 
 /**
- * acpi_get_next_subnode - Return the next child node handle for a device.
- * @dev: Device to find the next child node for.
+ * acpi_get_next_subnode - Return the next child node handle for a fwnode
+ * @fwnode: Firmware node to find the next child node for.
  * @child: Handle to one of the device's child nodes or a null handle.
  */
-struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
                                            struct fwnode_handle *child)
 {
-       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct acpi_device *adev = to_acpi_device_node(fwnode);
        struct list_head *head, *next;
 
-       if (!adev)
-               return NULL;
-
        if (!child || child->type == FWNODE_ACPI) {
-               head = &adev->children;
+               if (adev)
+                       head = &adev->children;
+               else
+                       goto nondev;
+
                if (list_empty(head))
                        goto nondev;
 
@@ -903,7 +904,6 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
                        next = adev->node.next;
                        if (next == head) {
                                child = NULL;
-                               adev = ACPI_COMPANION(dev);
                                goto nondev;
                        }
                        adev = list_entry(next, struct acpi_device, node);
@@ -915,9 +915,16 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
 
  nondev:
        if (!child || child->type == FWNODE_ACPI_DATA) {
+               struct acpi_data_node *data = to_acpi_data_node(fwnode);
                struct acpi_data_node *dn;
 
-               head = &adev->data.subnodes;
+               if (adev)
+                       head = &adev->data.subnodes;
+               else if (data)
+                       head = &data->data.subnodes;
+               else
+                       return NULL;
+
                if (list_empty(head))
                        return NULL;
 
index a25233430d18f0d0c8f1b67b16094b78dda35482..bc0f07ac48f6622d8d85ac02beefba53d83b7f28 100644 (file)
@@ -957,24 +957,46 @@ struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode)
 EXPORT_SYMBOL_GPL(fwnode_get_parent);
 
 /**
- * device_get_next_child_node - Return the next child node handle for a device
- * @dev: Device to find the next child node for.
- * @child: Handle to one of the device's child nodes or a null handle.
+ * fwnode_get_next_child_node - Return the next child node handle for a node
+ * @fwnode: Firmware node to find the next child node for.
+ * @child: Handle to one of the node's child nodes or a %NULL handle.
  */
-struct fwnode_handle *device_get_next_child_node(struct device *dev,
+struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
                                                 struct fwnode_handle *child)
 {
-       if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+       if (is_of_node(fwnode)) {
                struct device_node *node;
 
-               node = of_get_next_available_child(dev->of_node, to_of_node(child));
+               node = of_get_next_available_child(to_of_node(fwnode),
+                                                  to_of_node(child));
                if (node)
                        return &node->fwnode;
-       } else if (IS_ENABLED(CONFIG_ACPI)) {
-               return acpi_get_next_subnode(dev, child);
+       } else if (is_acpi_node(fwnode)) {
+               return acpi_get_next_subnode(fwnode, child);
        }
+
        return NULL;
 }
+EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+                                                struct fwnode_handle *child)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct fwnode_handle *fwnode = NULL;
+
+       if (dev->of_node)
+               fwnode = &dev->of_node->fwnode;
+       else if (adev)
+               fwnode = acpi_fwnode_handle(adev);
+
+       return fwnode_get_next_child_node(fwnode, child);
+}
 EXPORT_SYMBOL_GPL(device_get_next_child_node);
 
 /**
index e74e8bdbb6afd1c8be34242b5784ff9bdd05d31d..4eb1f5941ede4e68a55d789e66d6536998d04053 100644 (file)
@@ -997,8 +997,8 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
 int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
                       enum dev_prop_type proptype, void *val, size_t nval);
 
-struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
-                                           struct fwnode_handle *subnode);
+struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode,
+                                           struct fwnode_handle *child);
 struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode);
 
 struct acpi_probe_entry;
@@ -1116,8 +1116,8 @@ static inline int acpi_dev_prop_read(struct acpi_device *adev,
        return -ENXIO;
 }
 
-static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
-                                               struct fwnode_handle *subnode)
+static inline struct fwnode_handle *
+acpi_get_next_subnode(struct fwnode_handle *fwnode, struct fwnode_handle *child)
 {
        return NULL;
 }
index ab0a8160cef626b9eb9f7de168795b1c8d4e021f..f4786a8655f168cad87b5ee2991ac146a78f3bdc 100644 (file)
@@ -71,6 +71,12 @@ int fwnode_property_match_string(struct fwnode_handle *fwnode,
                                 const char *propname, const char *string);
 
 struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode);
+struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
+                                                struct fwnode_handle *child);
+
+#define fwnode_for_each_child_node(fwnode, child)                      \
+       for (child = fwnode_get_next_child_node(fwnode, NULL); child;   \
+            child = fwnode_get_next_child_node(fwnode, child))
 
 struct fwnode_handle *device_get_next_child_node(struct device *dev,
                                                 struct fwnode_handle *child);