Commit 8a06d1ea authored by Saravana Kannan's avatar Saravana Kannan Committed by Greg Kroah-Hartman

of: property: Update implementation of add_links() to create fwnode links

The semantics of add_links() has changed from creating device link
between devices to creating fwnode links between fwnodes. So, update the
implementation of add_links() to match the new semantics.
Acked-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarSaravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20201121020232.908850-15-saravanak@google.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 25ac86c6
...@@ -1038,33 +1038,9 @@ static bool of_is_ancestor_of(struct device_node *test_ancestor, ...@@ -1038,33 +1038,9 @@ static bool of_is_ancestor_of(struct device_node *test_ancestor,
} }
/** /**
* of_get_next_parent_dev - Add device link to supplier from supplier phandle * of_link_to_phandle - Add fwnode link to supplier from supplier phandle
* @np: device tree node * @con_np: consumer device tree node
* * @sup_np: supplier device tree node
* Given a device tree node (@np), this function finds its closest ancestor
* device tree node that has a corresponding struct device.
*
* The caller of this function is expected to call put_device() on the returned
* device when they are done.
*/
static struct device *of_get_next_parent_dev(struct device_node *np)
{
struct device *dev = NULL;
of_node_get(np);
do {
np = of_get_next_parent(np);
if (np)
dev = get_dev_from_fwnode(&np->fwnode);
} while (np && !dev);
of_node_put(np);
return dev;
}
/**
* of_link_to_phandle - Add device link to supplier from supplier phandle
* @dev: consumer device
* @sup_np: phandle to supplier device tree node
* *
* Given a phandle to a supplier device tree node (@sup_np), this function * Given a phandle to a supplier device tree node (@sup_np), this function
* finds the device that owns the supplier device tree node and creates a * finds the device that owns the supplier device tree node and creates a
...@@ -1074,16 +1050,14 @@ static struct device *of_get_next_parent_dev(struct device_node *np) ...@@ -1074,16 +1050,14 @@ static struct device *of_get_next_parent_dev(struct device_node *np)
* cases, it returns an error. * cases, it returns an error.
* *
* Returns: * Returns:
* - 0 if link successfully created to supplier * - 0 if fwnode link successfully created to supplier
* - -EAGAIN if linking to the supplier should be reattempted
* - -EINVAL if the supplier link is invalid and should not be created * - -EINVAL if the supplier link is invalid and should not be created
* - -ENODEV if there is no device that corresponds to the supplier phandle * - -ENODEV if struct device will never be create for supplier
*/ */
static int of_link_to_phandle(struct device *dev, struct device_node *sup_np, static int of_link_to_phandle(struct device_node *con_np,
u32 dl_flags) struct device_node *sup_np)
{ {
struct device *sup_dev, *sup_par_dev; struct device *sup_dev;
int ret = 0;
struct device_node *tmp_np = sup_np; struct device_node *tmp_np = sup_np;
of_node_get(sup_np); of_node_get(sup_np);
...@@ -1106,7 +1080,8 @@ static int of_link_to_phandle(struct device *dev, struct device_node *sup_np, ...@@ -1106,7 +1080,8 @@ static int of_link_to_phandle(struct device *dev, struct device_node *sup_np,
} }
if (!sup_np) { if (!sup_np) {
dev_dbg(dev, "Not linking to %pOFP - No device\n", tmp_np); pr_debug("Not linking %pOFP to %pOFP - No device\n",
con_np, tmp_np);
return -ENODEV; return -ENODEV;
} }
...@@ -1115,53 +1090,30 @@ static int of_link_to_phandle(struct device *dev, struct device_node *sup_np, ...@@ -1115,53 +1090,30 @@ static int of_link_to_phandle(struct device *dev, struct device_node *sup_np,
* descendant nodes. By definition, a child node can't be a functional * descendant nodes. By definition, a child node can't be a functional
* dependency for the parent node. * dependency for the parent node.
*/ */
if (of_is_ancestor_of(dev->of_node, sup_np)) { if (of_is_ancestor_of(con_np, sup_np)) {
dev_dbg(dev, "Not linking to %pOFP - is descendant\n", sup_np); pr_debug("Not linking %pOFP to %pOFP - is descendant\n",
con_np, sup_np);
of_node_put(sup_np); of_node_put(sup_np);
return -EINVAL; return -EINVAL;
} }
/*
* Don't create links to "early devices" that won't have struct devices
* created for them.
*/
sup_dev = get_dev_from_fwnode(&sup_np->fwnode); sup_dev = get_dev_from_fwnode(&sup_np->fwnode);
if (!sup_dev && of_node_check_flag(sup_np, OF_POPULATED)) { if (!sup_dev && of_node_check_flag(sup_np, OF_POPULATED)) {
/* Early device without struct device. */ pr_debug("Not linking %pOFP to %pOFP - No struct device\n",
dev_dbg(dev, "Not linking to %pOFP - No struct device\n", con_np, sup_np);
sup_np);
of_node_put(sup_np); of_node_put(sup_np);
return -ENODEV; return -ENODEV;
} else if (!sup_dev) {
/*
* DL_FLAG_SYNC_STATE_ONLY doesn't block probing and supports
* cycles. So cycle detection isn't necessary and shouldn't be
* done.
*/
if (dl_flags & DL_FLAG_SYNC_STATE_ONLY) {
of_node_put(sup_np);
return -EAGAIN;
}
sup_par_dev = of_get_next_parent_dev(sup_np);
if (sup_par_dev && device_is_dependent(dev, sup_par_dev)) {
/* Cyclic dependency detected, don't try to link */
dev_dbg(dev, "Not linking to %pOFP - cycle detected\n",
sup_np);
ret = -EINVAL;
} else {
/*
* Can't check for cycles or no cycles. So let's try
* again later.
*/
ret = -EAGAIN;
}
of_node_put(sup_np);
put_device(sup_par_dev);
return ret;
} }
of_node_put(sup_np);
if (!device_link_add(dev, sup_dev, dl_flags))
ret = -EINVAL;
put_device(sup_dev); put_device(sup_dev);
return ret;
fwnode_link_add(of_fwnode_handle(con_np), of_fwnode_handle(sup_np));
of_node_put(sup_np);
return 0;
} }
/** /**
...@@ -1361,37 +1313,29 @@ static const struct supplier_bindings of_supplier_bindings[] = { ...@@ -1361,37 +1313,29 @@ static const struct supplier_bindings of_supplier_bindings[] = {
* that list phandles to suppliers. If @prop_name isn't one, this function * that list phandles to suppliers. If @prop_name isn't one, this function
* doesn't do anything. * doesn't do anything.
* *
* If @prop_name is one, this function attempts to create device links from the * If @prop_name is one, this function attempts to create fwnode links from the
* consumer device @dev to all the devices of the suppliers listed in * consumer device tree node @con_np to all the suppliers device tree nodes
* @prop_name. * listed in @prop_name.
* *
* Any failed attempt to create a device link will NOT result in an immediate * Any failed attempt to create a fwnode link will NOT result in an immediate
* return. of_link_property() must create links to all the available supplier * return. of_link_property() must create links to all the available supplier
* devices even when attempts to create a link to one or more suppliers fail. * device tree nodes even when attempts to create a link to one or more
* suppliers fail.
*/ */
static int of_link_property(struct device *dev, struct device_node *con_np, static int of_link_property(struct device_node *con_np, const char *prop_name)
const char *prop_name)
{ {
struct device_node *phandle; struct device_node *phandle;
const struct supplier_bindings *s = of_supplier_bindings; const struct supplier_bindings *s = of_supplier_bindings;
unsigned int i = 0; unsigned int i = 0;
bool matched = false; bool matched = false;
int ret = 0; int ret = 0;
u32 dl_flags;
if (dev->of_node == con_np)
dl_flags = fw_devlink_get_flags();
else
dl_flags = DL_FLAG_SYNC_STATE_ONLY;
/* Do not stop at first failed link, link all available suppliers. */ /* Do not stop at first failed link, link all available suppliers. */
while (!matched && s->parse_prop) { while (!matched && s->parse_prop) {
while ((phandle = s->parse_prop(con_np, prop_name, i))) { while ((phandle = s->parse_prop(con_np, prop_name, i))) {
matched = true; matched = true;
i++; i++;
if (of_link_to_phandle(dev, phandle, dl_flags) of_link_to_phandle(con_np, phandle);
== -EAGAIN)
ret = -EAGAIN;
of_node_put(phandle); of_node_put(phandle);
} }
s++; s++;
...@@ -1399,31 +1343,19 @@ static int of_link_property(struct device *dev, struct device_node *con_np, ...@@ -1399,31 +1343,19 @@ static int of_link_property(struct device *dev, struct device_node *con_np,
return ret; return ret;
} }
static int of_link_to_suppliers(struct device *dev, static int of_fwnode_add_links(struct fwnode_handle *fwnode,
struct device_node *con_np) struct device *dev)
{ {
struct device_node *child;
struct property *p; struct property *p;
int ret = 0; struct device_node *con_np = to_of_node(fwnode);
for_each_property_of_node(con_np, p) if (!con_np)
if (of_link_property(dev, con_np, p->name)) return -EINVAL;
ret = -ENODEV;
for_each_available_child_of_node(con_np, child)
if (of_link_to_suppliers(dev, child) && !ret)
ret = -EAGAIN;
return ret;
}
static int of_fwnode_add_links(const struct fwnode_handle *fwnode, for_each_property_of_node(con_np, p)
struct device *dev) of_link_property(con_np, p->name);
{
if (unlikely(!is_of_node(fwnode)))
return 0;
return of_link_to_suppliers(dev, to_of_node(fwnode)); return 0;
} }
const struct fwnode_operations of_fwnode_ops = { const struct fwnode_operations of_fwnode_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment