From dfa672fbc0d9e83ff0dc1a75f1f5d0e59a30706b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Mar 2017 10:52:16 +0300 Subject: ACPI / property: Add possiblity to retrieve parent firmware node 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 Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 72 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 3afddcd834ef..587c9d000f0e 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -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; +} -- cgit v1.2.3 From afaf26fd8458be29949ae5a52c65a464a1b0cbb6 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Mar 2017 10:52:17 +0300 Subject: device property: Add fwnode_get_parent() Now that ACPI has support for returning parent firmware node for both types of nodes we can expose this to others as well. This adds a new function fwnode_get_parent() that can be used for DT and ACPI nodes to retrieve the parent firmware node. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index c458c63e353f..a25233430d18 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -931,6 +931,31 @@ int device_add_properties(struct device *dev, } EXPORT_SYMBOL_GPL(device_add_properties); +/** + * fwnode_get_parent - Return parent firwmare node + * @fwnode: Firmware whose parent is retrieved + * + * Return parent firmware node of the given node if possible or %NULL if no + * parent was available. + */ +struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_get_parent(to_of_node(fwnode)); + if (node) + parent = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + parent = acpi_node_get_parent(fwnode); + } + + return parent; +} +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. -- cgit v1.2.3 From 34055190b19d7c634caf738c8ca195cad06550cd Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Mar 2017 10:52:18 +0300 Subject: ACPI / property: Add fwnode_get_next_child_node() 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 Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 27 +++++++++++++++++---------- drivers/base/property.c | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 587c9d000f0e..8730ce745b43 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -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; diff --git a/drivers/base/property.c b/drivers/base/property.c index a25233430d18..bc0f07ac48f6 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -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); /** -- cgit v1.2.3 From 21ea73f54c6d77f35381c79870160496c9e78b60 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Mar 2017 10:52:19 +0300 Subject: device property: Add fwnode_get_named_child_node() Since now we have means to enumerate all children of any fwnode even in ACPI we can implement fwnode_get_named_child_node(). This is similar than device_get_named_child_node() with the exception that it can be called to any fwnode handle. Make device_get_named_child_node() call directly this new function. This is useful in cases where we need to be able to find child nodes which are not direct descendants of the parent device. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index bc0f07ac48f6..538b248d5dcf 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1000,20 +1000,20 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev, EXPORT_SYMBOL_GPL(device_get_next_child_node); /** - * device_get_named_child_node - Return first matching named child node handle - * @dev: Device to find the named child node for. + * fwnode_get_named_child_node - Return first matching named child node handle + * @fwnode: Firmware node to find the named child node for. * @childname: String to match child node name against. */ -struct fwnode_handle *device_get_named_child_node(struct device *dev, +struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode, const char *childname) { struct fwnode_handle *child; /* - * Find first matching named child node of this device. + * Find first matching named child node of this fwnode. * For ACPI this will be a data only sub-node. */ - device_for_each_child_node(dev, child) { + fwnode_for_each_child_node(fwnode, child) { if (is_of_node(child)) { if (!of_node_cmp(to_of_node(child)->name, childname)) return child; @@ -1025,6 +1025,18 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev, return NULL; } +EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); + +/** + * device_get_named_child_node - Return first matching named child node handle + * @dev: Device to find the named child node for. + * @childname: String to match child node name against. + */ +struct fwnode_handle *device_get_named_child_node(struct device *dev, + const char *childname) +{ + return fwnode_get_named_child_node(dev_fwnode(dev), childname); +} EXPORT_SYMBOL_GPL(device_get_named_child_node); /** -- cgit v1.2.3 From 79389a83bc3888a900191e3990cda5c76f2ca1ec Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Mar 2017 10:52:20 +0300 Subject: ACPI / property: Add support for remote endpoints DT has had concept of remote endpoints for some time already. It makes possible to reference another firmware node through a property called remote-endpoint. This is already used by some subsystems like v4l2 for parsing hardware properties related to camera. This patch adds ACPI support for remote endpoints utilizing _DSD hierarchical data extensions. Signed-off-by: Mika Westerberg Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 8730ce745b43..9eb7c13c5bb7 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -969,3 +969,141 @@ struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode) return NULL; } + +/** + * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node + * @fwnode: Pointer to the parent firmware node + * @prev: Previous endpoint node or %NULL to get the first + * + * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns + * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case + * of success the next endpoint is returned. + */ +struct fwnode_handle *acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle *prev) +{ + struct fwnode_handle *port = NULL; + struct fwnode_handle *endpoint; + + if (!prev) { + do { + port = fwnode_get_next_child_node(fwnode, port); + /* Ports must have port property */ + if (fwnode_property_present(port, "port")) + break; + } while (port); + } else { + port = fwnode_get_parent(prev); + } + + if (!port) + return NULL; + + endpoint = fwnode_get_next_child_node(port, prev); + while (!endpoint) { + port = fwnode_get_next_child_node(fwnode, port); + if (!port) + break; + if (fwnode_property_present(port, "port")) + endpoint = fwnode_get_next_child_node(port, NULL); + } + + if (endpoint) { + /* Endpoints must have "endpoint" property */ + if (!fwnode_property_present(endpoint, "endpoint")) + return ERR_PTR(-EPROTO); + } + + return endpoint; +} + +/** + * acpi_graph_get_child_prop_value - Return a child with a given property value + * @fwnode: device fwnode + * @prop_name: The name of the property to look for + * @val: the desired property value + * + * Return the port node corresponding to a given port number. Returns + * the child node on success, NULL otherwise. + */ +static struct fwnode_handle *acpi_graph_get_child_prop_value( + struct fwnode_handle *fwnode, const char *prop_name, unsigned int val) +{ + struct fwnode_handle *child; + + fwnode_for_each_child_node(fwnode, child) { + u32 nr; + + if (!fwnode_property_read_u32(fwnode, prop_name, &nr)) + continue; + + if (val == nr) + return child; + } + + return NULL; +} + + +/** + * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint + * @fwnode: Endpoint firmware node pointing to a remote device + * @parent: Firmware node of remote port parent is filled here if not %NULL + * @port: Firmware node of remote port is filled here if not %NULL + * @endpoint: Firmware node of remote endpoint is filled here if not %NULL + * + * Function parses remote end of ACPI firmware remote endpoint and fills in + * fields requested by the caller. Returns %0 in case of success and + * negative errno otherwise. + */ +int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle **parent, + struct fwnode_handle **port, + struct fwnode_handle **endpoint) +{ + unsigned int port_nr, endpoint_nr; + struct acpi_reference_args args; + int ret; + + memset(&args, 0, sizeof(args)); + ret = acpi_node_get_property_reference(fwnode, "remote-endpoint", 0, + &args); + if (ret) + return ret; + + /* + * Always require two arguments with the reference: port and + * endpoint indices. + */ + if (args.nargs != 2) + return -EPROTO; + + fwnode = acpi_fwnode_handle(args.adev); + port_nr = args.args[0]; + endpoint_nr = args.args[1]; + + if (parent) + *parent = fwnode; + + if (!port && !endpoint) + return 0; + + fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr); + if (!fwnode) + return -EPROTO; + + if (port) + *port = fwnode; + + if (!endpoint) + return 0; + + fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint", + endpoint_nr); + if (!fwnode) + return -EPROTO; + + *endpoint = fwnode; + + return 0; +} -- cgit v1.2.3 From 07bb80d40b0e6a43aafb422296d33baed255569a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 28 Mar 2017 10:52:21 +0300 Subject: device property: Add support for remote endpoints This follows DT implementation of of_graph_* APIs but we call them fwnode_graph_* instead. For DT nodes the existing of_graph_* implementation will be used. For ACPI we use the new ACPI graph implementation instead. Signed-off-by: Mika Westerberg Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 538b248d5dcf..4e98a6fad33f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1176,3 +1177,125 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen) return device_get_mac_addr(dev, "address", addr, alen); } EXPORT_SYMBOL(device_get_mac_address); + +/** + * device_graph_get_next_endpoint - Get next endpoint firmware node + * @fwnode: Pointer to the parent firmware node + * @prev: Previous endpoint node or %NULL to get the first + * + * Returns an endpoint firmware node pointer or %NULL if no more endpoints + * are available. + */ +struct fwnode_handle * +fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle *prev) +{ + struct fwnode_handle *endpoint = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_graph_get_next_endpoint(to_of_node(fwnode), + to_of_node(prev)); + + if (node) + endpoint = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + endpoint = acpi_graph_get_next_endpoint(fwnode, prev); + if (IS_ERR(endpoint)) + endpoint = NULL; + } + + return endpoint; + +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); + +/** + * fwnode_graph_get_remote_port_parent - Return fwnode of a remote device + * @fwnode: Endpoint firmware node pointing to the remote endpoint + * + * Extracts firmware node of a remote device the @fwnode points to. + */ +struct fwnode_handle * +fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_graph_get_remote_port_parent(to_of_node(fwnode)); + if (node) + parent = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + int ret; + + ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL, + NULL); + if (ret) + return NULL; + } + + return parent; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent); + +/** + * fwnode_graph_get_remote_port - Return fwnode of a remote port + * @fwnode: Endpoint firmware node pointing to the remote endpoint + * + * Extracts firmware node of a remote port the @fwnode points to. + */ +struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *port = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_graph_get_remote_port(to_of_node(fwnode)); + if (node) + port = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + int ret; + + ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL); + if (ret) + return NULL; + } + + return port; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); + +/** + * fwnode_graph_get_remote_endpoint - Return fwnode of a remote endpoint + * @fwnode: Endpoint firmware node pointing to the remote endpoint + * + * Extracts firmware node of a remote endpoint the @fwnode points to. + */ +struct fwnode_handle * +fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *endpoint = NULL; + + if (is_of_node(fwnode)) { + struct device_node *node; + + node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint", + 0); + if (node) + endpoint = &node->fwnode; + } else if (is_acpi_node(fwnode)) { + int ret; + + ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, + &endpoint); + if (ret) + return NULL; + } + + return endpoint; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint); -- cgit v1.2.3 From e7887c284969a23a98fe1aff2f631c5ccdcd1757 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 10:52:22 +0300 Subject: device property: Add fwnode_handle_get() fwnode_handle_get() is used to obtain a reference to a fwnode_handle container. In this case this is OF specific struct device_node. This complements fwnode_handle_put() which is already implemented. Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 4e98a6fad33f..23514bf67933 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1040,6 +1040,17 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev, } EXPORT_SYMBOL_GPL(device_get_named_child_node); +/** + * fwnode_handle_get - Obtain a reference to a device node + * @fwnode: Pointer to the device node to obtain the reference to. + */ +void fwnode_handle_get(struct fwnode_handle *fwnode) +{ + if (is_of_node(fwnode)) + of_node_get(to_of_node(fwnode)); +} +EXPORT_SYMBOL_GPL(fwnode_handle_get); + /** * fwnode_handle_put - Drop reference to a device node * @fwnode: Pointer to the device node to drop the reference to. -- cgit v1.2.3 From e44bb0cbdc88686c21e2175a990b40bf6db5d005 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 10:52:24 +0300 Subject: device property: Make dev_fwnode() public The function to obtain a fwnode related to a struct device is useful for drivers that use the fwnode property API: it allows not being aware of the underlying firmware implementation. Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 23514bf67933..22849a89a8b5 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -183,11 +183,12 @@ static int pset_prop_read_string(struct property_set *pset, return 0; } -static inline struct fwnode_handle *dev_fwnode(struct device *dev) +struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? &dev->of_node->fwnode : dev->fwnode; } +EXPORT_SYMBOL_GPL(dev_fwnode); /** * device_property_present - check if a property of a device is present -- cgit v1.2.3 From 2bd5452d46df46d99b869b59a1532647e2981d75 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 10:52:25 +0300 Subject: device property: Add support for fwnode endpoints Similar to OF endpoints, endpoint type nodes can be also supported on ACPI. In order to make it possible for drivers to ignore the matter, add a type for fwnode_endpoint and a function to parse them. On ACPI, find the child node index instead of relying on the "endpoint" property. Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 22849a89a8b5..8a53b8f1db66 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1311,3 +1311,35 @@ fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) return endpoint; } EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint); + +/** + * fwnode_graph_parse_endpoint - parse common endpoint node properties + * @fwnode: pointer to endpoint fwnode_handle + * @endpoint: pointer to the fwnode endpoint data structure + * + * Parse @fwnode representing a graph endpoint node and store the + * information in @endpoint. The caller must hold a reference to + * @fwnode. + */ +int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, + struct fwnode_endpoint *endpoint) +{ + struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_fwnode = fwnode; + + if (is_acpi_node(port_fwnode)) { + fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); + fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); + } else { + fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port); + fwnode_property_read_u32(fwnode, "reg", &endpoint->id); + } + + fwnode_handle_put(port_fwnode); + + return 0; +} +EXPORT_SYMBOL(fwnode_graph_parse_endpoint); -- cgit v1.2.3 From 233872585de1cf26c3c3da5859ffb3aba45bd486 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 10:52:26 +0300 Subject: device property: Add fwnode_get_next_parent() In order to differentiate the functionality between dropping a reference to the node (or not) for the benefit of OF, introduce fwnode_get_next_parent(). Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 8a53b8f1db66..627ebc9b570d 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -933,6 +933,27 @@ int device_add_properties(struct device *dev, } EXPORT_SYMBOL_GPL(device_add_properties); +/** + * fwnode_get_next_parent - Iterate to the node's parent + * @fwnode: Firmware whose parent is retrieved + * + * This is like fwnode_get_parent() except that it drops the refcount + * on the passed node, making it suitable for iterating through a + * node's parents. + * + * Returns a node pointer with refcount incremented, use + * fwnode_handle_node() on it when done. + */ +struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = fwnode_get_parent(fwnode); + + fwnode_handle_put(fwnode); + + return parent; +} +EXPORT_SYMBOL_GPL(fwnode_get_next_parent); + /** * fwnode_get_parent - Return parent firwmare node * @fwnode: Firmware whose parent is retrieved -- cgit v1.2.3 From 026b821745a7dd4552d43539e70c83d7143b59c8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 15:22:17 +0300 Subject: device property: fwnode_property_read_string_array() may return -EILSEQ fwnode_property_read_string_array() may return -EILSEQ through of_property_read_string_array(). Document this. Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 627ebc9b570d..c69bde8086cc 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -591,7 +591,7 @@ static int __fwnode_property_read_string(struct fwnode_handle *fwnode, * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of strings, + * %-EPROTO or %-EILSEQ if the property is not an array of strings, * %-EOVERFLOW if the size of the property is not as expected, * %-ENXIO if no suitable firmware interface is present. */ -- cgit v1.2.3 From 0f194992c85f972ee99f176eb78a5860cef78573 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 15:22:18 +0300 Subject: device property: Fix reading pset strings using array access functions The length field value of non-array string properties is the length of the string itself. Non-array string properties thus require specific handling. Fix this. Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index c69bde8086cc..166cfdb5e851 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -147,14 +147,36 @@ static int pset_prop_read_string_array(struct property_set *pset, const char *propname, const char **strings, size_t nval) { + const struct property_entry *prop; const void *pointer; - size_t length = nval * sizeof(*strings); + size_t array_len, length; + + /* Find out the array length. */ + prop = pset_prop_get(pset, propname); + if (!prop) + return -EINVAL; + + if (!prop->is_array) + /* The array length for a non-array string property is 1. */ + array_len = 1; + else + /* Find the length of an array. */ + array_len = pset_prop_count_elems_of_size(pset, propname, + sizeof(const char *)); + + /* Return how many there are if strings is NULL. */ + if (!strings) + return array_len; + + array_len = min(nval, array_len); + length = array_len * sizeof(*strings); pointer = pset_prop_find(pset, propname, length); if (IS_ERR(pointer)) return PTR_ERR(pointer); memcpy(strings, pointer, length); + return 0; } @@ -555,12 +577,8 @@ static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode, return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, nval); else if (is_pset_node(fwnode)) - return val ? - pset_prop_read_string_array(to_pset_node(fwnode), - propname, val, nval) : - pset_prop_count_elems_of_size(to_pset_node(fwnode), - propname, - sizeof(const char *)); + return pset_prop_read_string_array(to_pset_node(fwnode), + propname, val, nval); return -ENXIO; } -- cgit v1.2.3 From b0b027cee090a1e3278960e1c8257213fda40f10 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 15:22:19 +0300 Subject: device property: fwnode_property_read_string_array() returns nr of strings Functionally fwnode_property_read_string_array() should match of_property_read_string_array() and work as a drop-in substitute for the latter. of_property_read_string_array() returns the number of strings read if the target string pointer array is non-NULL. Make fwnode_property_read_string_array() do the same. Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 22 +++++++++++++++++----- drivers/base/property.c | 12 ++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 9eb7c13c5bb7..9364398204e9 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -714,6 +714,8 @@ static int acpi_data_prop_read_single(struct acpi_device_data *data, return ret; *(char **)val = obj->string.pointer; + + return 1; } else { ret = -EINVAL; } @@ -723,7 +725,15 @@ static int acpi_data_prop_read_single(struct acpi_device_data *data, int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname, enum dev_prop_type proptype, void *val) { - return adev ? acpi_data_prop_read_single(&adev->data, propname, proptype, val) : -EINVAL; + int ret; + + if (!adev) + return -EINVAL; + + ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val); + if (ret < 0 || proptype != ACPI_TYPE_STRING) + return ret; + return 0; } static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val, @@ -799,7 +809,7 @@ static int acpi_copy_property_array_string(const union acpi_object *items, val[i] = items[i].string.pointer; } - return 0; + return nval; } static int acpi_data_prop_read(struct acpi_device_data *data, @@ -813,7 +823,7 @@ static int acpi_data_prop_read(struct acpi_device_data *data, if (val && nval == 1) { ret = acpi_data_prop_read_single(data, propname, proptype, val); - if (!ret) + if (ret >= 0) return ret; } @@ -824,7 +834,7 @@ static int acpi_data_prop_read(struct acpi_device_data *data, if (!val) return obj->package.count; - if (nval > obj->package.count) + if (proptype != DEV_PROP_STRING && nval > obj->package.count) return -EOVERFLOW; else if (nval <= 0) return -EINVAL; @@ -845,7 +855,9 @@ static int acpi_data_prop_read(struct acpi_device_data *data, ret = acpi_copy_property_array_u64(items, (u64 *)val, nval); break; case DEV_PROP_STRING: - ret = acpi_copy_property_array_string(items, (char **)val, nval); + ret = acpi_copy_property_array_string( + items, (char **)val, + min_t(u32, nval, obj->package.count)); break; default: ret = -EINVAL; diff --git a/drivers/base/property.c b/drivers/base/property.c index 166cfdb5e851..71520454c038 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -177,7 +177,7 @@ static int pset_prop_read_string_array(struct property_set *pset, memcpy(strings, pointer, length); - return 0; + return array_len; } static int pset_prop_read_string(struct property_set *pset, @@ -364,8 +364,8 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); * Function reads an array of string properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), + * Return: number of values read on success if @val is non-NULL, + * number of values available on success if @val is NULL, * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO or %-EILSEQ if the property is not an array of strings, @@ -605,8 +605,8 @@ static int __fwnode_property_read_string(struct fwnode_handle *fwnode, * Read an string list property @propname from the given firmware node and store * them to @val if found. * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), + * Return: number of values read on success if @val is non-NULL, + * number of values available on success if @val is NULL, * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO or %-EILSEQ if the property is not an array of strings, @@ -653,7 +653,7 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, !IS_ERR_OR_NULL(fwnode->secondary)) ret = __fwnode_property_read_string(fwnode->secondary, propname, val); - return ret; + return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); -- cgit v1.2.3 From e48174779440c79ff5dd75f0e6b169d4e184262d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 28 Mar 2017 15:26:22 +0300 Subject: device property: Read strings using string array reading functions Always read strings using of_property_read_string_array() instead of of_property_read_string(). This allows using a single operation struct callback for accessing strings. Same for pset_prop_read_string_array() and pset_prop_read_string(). Signed-off-by: Sakari Ailus Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 45 +-------------------------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index 71520454c038..149de311a10e 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -180,31 +180,6 @@ static int pset_prop_read_string_array(struct property_set *pset, return array_len; } -static int pset_prop_read_string(struct property_set *pset, - const char *propname, const char **strings) -{ - const struct property_entry *prop; - const char * const *pointer; - - prop = pset_prop_get(pset, propname); - if (!prop) - return -EINVAL; - if (!prop->is_string) - return -EILSEQ; - if (prop->is_array) { - pointer = prop->pointer.str; - if (!pointer) - return -ENODATA; - } else { - pointer = &prop->value.str; - if (*pointer && strnlen(*pointer, prop->length) >= prop->length) - return -EILSEQ; - } - - *strings = *pointer; - return 0; -} - struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? @@ -582,19 +557,6 @@ static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode, return -ENXIO; } -static int __fwnode_property_read_string(struct fwnode_handle *fwnode, - const char *propname, const char **val) -{ - if (is_of_node(fwnode)) - return of_property_read_string(to_of_node(fwnode), propname, val); - else if (is_acpi_node(fwnode)) - return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, - val, 1); - else if (is_pset_node(fwnode)) - return pset_prop_read_string(to_pset_node(fwnode), propname, val); - return -ENXIO; -} - /** * fwnode_property_read_string_array - return string array property of a node * @fwnode: Firmware node to get the property of @@ -646,13 +608,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); int fwnode_property_read_string(struct fwnode_handle *fwnode, const char *propname, const char **val) { - int ret; + int ret = fwnode_property_read_string_array(fwnode, propname, val, 1); - ret = __fwnode_property_read_string(fwnode, propname, val); - if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && - !IS_ERR_OR_NULL(fwnode->secondary)) - ret = __fwnode_property_read_string(fwnode->secondary, - propname, val); return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); -- cgit v1.2.3