Commit 0290c4ca authored by Frank Rowand's avatar Frank Rowand Committed by Rob Herring

of: overlay: rename identifiers to more reflect what they do

This patch is aimed primarily at drivers/of/overlay.c, but those
changes also have a small impact in a few other files.

overlay.c is difficult to read and maintain.  Improve readability:
  - Rename functions, types and variables to better reflect what
    they do and to be consistent with names in other places,
    such as the device tree overlay FDT (flattened device tree),
    and make the algorithms more clear
  - Use the same names consistently throughout the file
  - Update comments for name changes
  - Fix incorrect comments

This patch is intended to not introduce any functional change.
Signed-off-by: default avatarFrank Rowand <frank.rowand@sony.com>
Signed-off-by: default avatarRob Herring <robh@kernel.org>
parent bbed8794
...@@ -87,15 +87,15 @@ Overlay in-kernel API ...@@ -87,15 +87,15 @@ Overlay in-kernel API
The API is quite easy to use. The API is quite easy to use.
1. Call of_overlay_create() to create and apply an overlay. The return value 1. Call of_overlay_apply() to create and apply an overlay changeset. The return
is a cookie identifying this overlay. value is an error or a cookie identifying this overlay.
2. Call of_overlay_destroy() to remove and cleanup the overlay previously 2. Call of_overlay_remove() to remove and cleanup the overlay changeset
created via the call to of_overlay_create(). Removal of an overlay that previously created via the call to of_overlay_apply(). Removal of an overlay
is stacked by another will not be permitted. changeset that is stacked by another will not be permitted.
Finally, if you need to remove all overlays in one-go, just call Finally, if you need to remove all overlays in one-go, just call
of_overlay_destroy_all() which will remove every single one in the correct of_overlay_remove_all() which will remove every single one in the correct
order. order.
Overlay DTS Format Overlay DTS Format
......
...@@ -247,9 +247,10 @@ static void __init tilcdc_convert_slave_node(void) ...@@ -247,9 +247,10 @@ static void __init tilcdc_convert_slave_node(void)
tilcdc_node_disable(slave); tilcdc_node_disable(slave);
ret = of_overlay_create(overlay); ret = of_overlay_apply(overlay);
if (ret) if (ret)
pr_err("%s: Creating overlay failed: %d\n", __func__, ret); pr_err("%s: Applying overlay changeset failed: %d\n",
__func__, ret);
else else
pr_info("%s: ti,tilcdc,slave node successfully converted\n", pr_info("%s: ti,tilcdc,slave node successfully converted\n",
__func__); __func__);
......
...@@ -758,7 +758,7 @@ int of_changeset_revert(struct of_changeset *ocs) ...@@ -758,7 +758,7 @@ int of_changeset_revert(struct of_changeset *ocs)
EXPORT_SYMBOL_GPL(of_changeset_revert); EXPORT_SYMBOL_GPL(of_changeset_revert);
/** /**
* of_changeset_action - Perform a changeset action * of_changeset_action - Add an action to the tail of the changeset list
* *
* @ocs: changeset pointer * @ocs: changeset pointer
* @action: action to perform * @action: action to perform
......
...@@ -25,67 +25,63 @@ ...@@ -25,67 +25,63 @@
#include "of_private.h" #include "of_private.h"
/** /**
* struct of_overlay_info - Holds a single overlay info * struct fragment - info about fragment nodes in overlay expanded device tree
* @target: target of the overlay operation * @target: target of the overlay operation
* @overlay: pointer to the overlay contents node * @overlay: pointer to the __overlay__ node
*
* Holds a single overlay state, including all the overlay logs &
* records.
*/ */
struct of_overlay_info { struct fragment {
struct device_node *target; struct device_node *target;
struct device_node *overlay; struct device_node *overlay;
bool is_symbols_node; bool is_symbols_node;
}; };
/** /**
* struct of_overlay - Holds a complete overlay transaction * struct overlay_changeset
* @node: List on which we are located * @ovcs_list: list on which we are located
* @count: Count of ovinfo structures * @count: count of @fragments structures
* @ovinfo_tab: Overlay info table (count sized) * @fragments: info about fragment nodes in overlay expanded device tree
* @cset: Changeset to be used * @cset: changeset to apply fragments to live device tree
*
* Holds a complete overlay transaction
*/ */
struct of_overlay { struct overlay_changeset {
int id; int id;
struct list_head node; struct list_head ovcs_list;
int count; int count;
struct of_overlay_info *ovinfo_tab; struct fragment *fragments;
struct of_changeset cset; struct of_changeset cset;
}; };
static int of_overlay_apply_one(struct of_overlay *ov, static int build_changeset_next_level(struct overlay_changeset *ovcs,
struct device_node *target, const struct device_node *overlay, struct device_node *target_node,
const struct device_node *overlay_node,
bool is_symbols_node); bool is_symbols_node);
static BLOCKING_NOTIFIER_HEAD(of_overlay_chain); static BLOCKING_NOTIFIER_HEAD(overlay_notify_chain);
int of_overlay_notifier_register(struct notifier_block *nb) int of_overlay_notifier_register(struct notifier_block *nb)
{ {
return blocking_notifier_chain_register(&of_overlay_chain, nb); return blocking_notifier_chain_register(&overlay_notify_chain, nb);
} }
EXPORT_SYMBOL_GPL(of_overlay_notifier_register); EXPORT_SYMBOL_GPL(of_overlay_notifier_register);
int of_overlay_notifier_unregister(struct notifier_block *nb) int of_overlay_notifier_unregister(struct notifier_block *nb)
{ {
return blocking_notifier_chain_unregister(&of_overlay_chain, nb); return blocking_notifier_chain_unregister(&overlay_notify_chain, nb);
} }
EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister); EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister);
static int of_overlay_notify(struct of_overlay *ov, static int overlay_notify(struct overlay_changeset *ovcs,
enum of_overlay_notify_action action) enum of_overlay_notify_action action)
{ {
struct of_overlay_notify_data nd; struct of_overlay_notify_data nd;
int i, ret; int i, ret;
for (i = 0; i < ov->count; i++) { for (i = 0; i < ovcs->count; i++) {
struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i]; struct fragment *fragment = &ovcs->fragments[i];
nd.target = ovinfo->target; nd.target = fragment->target;
nd.overlay = ovinfo->overlay; nd.overlay = fragment->overlay;
ret = blocking_notifier_call_chain(&of_overlay_chain, ret = blocking_notifier_call_chain(&overlay_notify_chain,
action, &nd); action, &nd);
if (ret) if (ret)
return notifier_to_errno(ret); return notifier_to_errno(ret);
...@@ -94,10 +90,10 @@ static int of_overlay_notify(struct of_overlay *ov, ...@@ -94,10 +90,10 @@ static int of_overlay_notify(struct of_overlay *ov,
return 0; return 0;
} }
static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov, static struct property *dup_and_fixup_symbol_prop(
const struct property *prop) struct overlay_changeset *ovcs, const struct property *prop)
{ {
struct of_overlay_info *ovinfo; struct fragment *fragment;
struct property *new; struct property *new;
const char *overlay_name; const char *overlay_name;
char *label_path; char *label_path;
...@@ -116,18 +112,18 @@ static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov, ...@@ -116,18 +112,18 @@ static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov,
if (!new) if (!new)
return NULL; return NULL;
for (k = 0; k < ov->count; k++) { for (k = 0; k < ovcs->count; k++) {
ovinfo = &ov->ovinfo_tab[k]; fragment = &ovcs->fragments[k];
overlay_name = ovinfo->overlay->full_name; overlay_name = fragment->overlay->full_name;
overlay_name_len = strlen(overlay_name); overlay_name_len = strlen(overlay_name);
if (!strncasecmp(symbol_path, overlay_name, overlay_name_len)) if (!strncasecmp(symbol_path, overlay_name, overlay_name_len))
break; break;
} }
if (k >= ov->count) if (k >= ovcs->count)
goto err_free; goto err_free;
target_path = ovinfo->target->full_name; target_path = fragment->target->full_name;
target_path_len = strlen(target_path); target_path_len = strlen(target_path);
label_path = symbol_path + overlay_name_len; label_path = symbol_path + overlay_name_len;
...@@ -156,82 +152,119 @@ static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov, ...@@ -156,82 +152,119 @@ static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov,
} }
/* /**
* add_changeset_property() - add @overlay_prop to overlay changeset
* @ovcs: overlay changeset
* @target_node: where to place @overlay_prop in live tree
* @overlay_prop: property to add or update, from overlay tree
* is_symbols_node: 1 if @target_node is "/__symbols__"
*
* If @overlay_prop does not already exist in @target_node, add changeset entry
* to add @overlay_prop in @target_node, else add changeset entry to update
* value of @overlay_prop.
*
* Some special properties are not updated (no error returned). * Some special properties are not updated (no error returned).
*
* Update of property in symbols node is not allowed. * Update of property in symbols node is not allowed.
*
* Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid @overlay.
*/ */
static int of_overlay_apply_single_property(struct of_overlay *ov, static int add_changeset_property(struct overlay_changeset *ovcs,
struct device_node *target, struct property *prop, struct device_node *target_node,
struct property *overlay_prop,
bool is_symbols_node) bool is_symbols_node)
{ {
struct property *propn = NULL, *tprop; struct property *new_prop = NULL, *prop;
int ret = 0; int ret = 0;
tprop = of_find_property(target, prop->name, NULL); prop = of_find_property(target_node, overlay_prop->name, NULL);
if (!of_prop_cmp(prop->name, "name") || if (!of_prop_cmp(overlay_prop->name, "name") ||
!of_prop_cmp(prop->name, "phandle") || !of_prop_cmp(overlay_prop->name, "phandle") ||
!of_prop_cmp(prop->name, "linux,phandle")) !of_prop_cmp(overlay_prop->name, "linux,phandle"))
return 0; return 0;
if (is_symbols_node) { if (is_symbols_node) {
if (tprop) if (prop)
return -EINVAL; return -EINVAL;
propn = dup_and_fixup_symbol_prop(ov, prop); new_prop = dup_and_fixup_symbol_prop(ovcs, overlay_prop);
} else { } else {
propn = __of_prop_dup(prop, GFP_KERNEL); new_prop = __of_prop_dup(overlay_prop, GFP_KERNEL);
} }
if (!propn) if (!new_prop)
return -ENOMEM; return -ENOMEM;
if (!tprop) if (!prop)
ret = of_changeset_add_property(&ov->cset, target, propn); ret = of_changeset_add_property(&ovcs->cset, target_node,
new_prop);
else else
ret = of_changeset_update_property(&ov->cset, target, propn); ret = of_changeset_update_property(&ovcs->cset, target_node,
new_prop);
if (ret) { if (ret) {
kfree(propn->name); kfree(new_prop->name);
kfree(propn->value); kfree(new_prop->value);
kfree(propn); kfree(new_prop);
} }
return ret; return ret;
} }
static int of_overlay_apply_single_device_node(struct of_overlay *ov, /**
struct device_node *target, struct device_node *child) * add_changeset_node() - add @node (and children) to overlay changeset
* @ovcs: overlay changeset
* @target_node: where to place @node in live tree
* @node: node from within overlay device tree fragment
*
* If @node does not already exist in @target_node, add changeset entry
* to add @node in @target_node.
*
* If @node already exists in @target_node, and the existing node has
* a phandle, the overlay node is not allowed to have a phandle.
*
* If @node has child nodes, add the children recursively via
* build_changeset_next_level().
*
* NOTE: Multiple mods of created nodes not supported.
*
* Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid @overlay.
*/
static int add_changeset_node(struct overlay_changeset *ovcs,
struct device_node *target_node, struct device_node *node)
{ {
const char *cname; const char *node_kbasename;
struct device_node *tchild; struct device_node *tchild;
int ret = 0; int ret = 0;
cname = kbasename(child->full_name); node_kbasename = kbasename(node->full_name);
if (!cname) if (!node_kbasename)
return -ENOMEM; return -ENOMEM;
for_each_child_of_node(target, tchild) for_each_child_of_node(target_node, tchild)
if (!of_node_cmp(cname, kbasename(tchild->full_name))) if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
break; break;
if (tchild) { if (tchild) {
if (child->phandle) if (node->phandle)
return -EINVAL; return -EINVAL;
/* apply overlay recursively */ ret = build_changeset_next_level(ovcs, tchild, node, 0);
ret = of_overlay_apply_one(ov, tchild, child, 0);
of_node_put(tchild); of_node_put(tchild);
} else { } else {
tchild = __of_node_dup(child, "%pOF/%s", target, cname); tchild = __of_node_dup(node, "%pOF/%s",
target_node, node_kbasename);
if (!tchild) if (!tchild)
return -ENOMEM; return -ENOMEM;
tchild->parent = target; tchild->parent = target_node;
ret = of_changeset_attach_node(&ov->cset, tchild); ret = of_changeset_attach_node(&ovcs->cset, tchild);
if (ret) if (ret)
return ret; return ret;
ret = of_overlay_apply_one(ov, tchild, child, 0); ret = build_changeset_next_level(ovcs, tchild, node, 0);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -239,29 +272,37 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov, ...@@ -239,29 +272,37 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
return ret; return ret;
} }
/* /**
* Apply a single overlay node recursively. * build_changeset_next_level() - add level of overlay changeset
* @ovcs: overlay changeset
* @target_node: where to place @overlay_node in live tree
* @overlay_node: node from within an overlay device tree fragment
* @is_symbols_node: @overlay_node is node "/__symbols__"
* *
* Note that the in case of an error the target node is left * Add the properties (if any) and nodes (if any) from @overlay_node to the
* in a inconsistent state. Error recovery should be performed * @ovcs->cset changeset. If an added node has child nodes, they will
* by using the changeset. * be added recursively.
* *
* Do not allow symbols node to have any children. * Do not allow symbols node to have any children.
*
* Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* invalid @overlay_node.
*/ */
static int of_overlay_apply_one(struct of_overlay *ov, static int build_changeset_next_level(struct overlay_changeset *ovcs,
struct device_node *target, const struct device_node *overlay, struct device_node *target_node,
const struct device_node *overlay_node,
bool is_symbols_node) bool is_symbols_node)
{ {
struct device_node *child; struct device_node *child;
struct property *prop; struct property *prop;
int ret; int ret;
for_each_property_of_node(overlay, prop) { for_each_property_of_node(overlay_node, prop) {
ret = of_overlay_apply_single_property(ov, target, prop, ret = add_changeset_property(ovcs, target_node, prop,
is_symbols_node); is_symbols_node);
if (ret) { if (ret) {
pr_err("Failed to apply prop @%pOF/%s\n", pr_err("Failed to apply prop @%pOF/%s\n",
target, prop->name); target_node, prop->name);
return ret; return ret;
} }
} }
...@@ -269,11 +310,11 @@ static int of_overlay_apply_one(struct of_overlay *ov, ...@@ -269,11 +310,11 @@ static int of_overlay_apply_one(struct of_overlay *ov,
if (is_symbols_node) if (is_symbols_node)
return 0; return 0;
for_each_child_of_node(overlay, child) { for_each_child_of_node(overlay_node, child) {
ret = of_overlay_apply_single_device_node(ov, target, child); ret = add_changeset_node(ovcs, target_node, child);
if (ret) { if (ret) {
pr_err("Failed to apply single node @%pOF/%s\n", pr_err("Failed to apply node @%pOF/%s\n",
target, child->name); target_node, child->name);
of_node_put(child); of_node_put(child);
return ret; return ret;
} }
...@@ -283,26 +324,30 @@ static int of_overlay_apply_one(struct of_overlay *ov, ...@@ -283,26 +324,30 @@ static int of_overlay_apply_one(struct of_overlay *ov,
} }
/** /**
* of_overlay_apply() - Apply @count overlays pointed at by @ovinfo_tab * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments
* @ov: Overlay to apply * @ovcs: Overlay changeset
*
* Create changeset @ovcs->cset to contain the nodes and properties of the
* overlay device tree fragments in @ovcs->fragments[]. If an error occurs,
* any portions of the changeset that were successfully created will remain
* in @ovcs->cset.
* *
* Applies the overlays given, while handling all error conditions * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
* appropriately. Either the operation succeeds, or if it fails the * invalid overlay in @ovcs->fragments[].
* live tree is reverted to the state before the attempt.
* Returns 0, or an error if the overlay attempt failed.
*/ */
static int of_overlay_apply(struct of_overlay *ov) static int build_changeset(struct overlay_changeset *ovcs)
{ {
int i, err; int i, ret;
for (i = 0; i < ov->count; i++) { for (i = 0; i < ovcs->count; i++) {
struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i]; struct fragment *fragment = &ovcs->fragments[i];
err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay, ret = build_changeset_next_level(ovcs, fragment->target,
ovinfo->is_symbols_node); fragment->overlay,
if (err) { fragment->is_symbols_node);
pr_err("apply failed '%pOF'\n", ovinfo->target); if (ret) {
return err; pr_err("apply failed '%pOF'\n", fragment->target);
return ret;
} }
} }
...@@ -350,45 +395,46 @@ static struct device_node *find_target_node(struct device_node *info_node) ...@@ -350,45 +395,46 @@ static struct device_node *find_target_node(struct device_node *info_node)
* *
* Returns 0 on success, or a negative error value. * Returns 0 on success, or a negative error value.
*/ */
static int of_fill_overlay_info(struct of_overlay *ov, static int of_fill_overlay_info(struct overlay_changeset *ovcset,
struct device_node *info_node, struct of_overlay_info *ovinfo) struct device_node *info_node, struct fragment *fragment)
{ {
ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__"); fragment->overlay = of_get_child_by_name(info_node, "__overlay__");
if (!ovinfo->overlay) if (!fragment->overlay)
goto err_fail; goto err_fail;
ovinfo->target = find_target_node(info_node); fragment->target = find_target_node(info_node);
if (!ovinfo->target) if (!fragment->target)
goto err_fail; goto err_fail;
return 0; return 0;
err_fail: err_fail:
of_node_put(ovinfo->target); of_node_put(fragment->target);
of_node_put(ovinfo->overlay); of_node_put(fragment->overlay);
memset(ovinfo, 0, sizeof(*ovinfo)); memset(fragment, 0, sizeof(*fragment));
return -EINVAL; return -EINVAL;
} }
/** /**
* of_build_overlay_info() - Build an overlay info array * init_overlay_changeset() - initialize overlay changeset from overlay tree
* @ov Overlay to build * @ovcs Overlay changeset to build
* @tree: Device node containing all the overlays * @tree: Contains all the overlay fragments and overlay fixup nodes
* *
* Helper function that given a tree containing overlay information, * Initialize @ovcs. Populate @ovcs->fragments with node information from
* allocates and builds an overlay info array containing it, ready * the top level of @tree. The relevant top level nodes are the fragment
* for use using of_overlay_apply. * nodes and the __symbols__ node. Any other top level node will be ignored.
* *
* Returns 0 on success with the @cntp @ovinfop pointers valid, * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
* while on error a negative error value is returned. * detected in @tree, or -ENODEV if no valid nodes found.
*/ */
static int of_build_overlay_info(struct of_overlay *ov, static int init_overlay_changeset(struct overlay_changeset *ovcs,
struct device_node *tree) struct device_node *tree)
{ {
struct device_node *node; struct device_node *node;
struct of_overlay_info *ovinfo; struct fragment *fragment;
int cnt, err; struct fragment *fragments;
int cnt, ret;
cnt = 0; cnt = 0;
for_each_child_of_node(tree, node) for_each_child_of_node(tree, node)
...@@ -397,24 +443,25 @@ static int of_build_overlay_info(struct of_overlay *ov, ...@@ -397,24 +443,25 @@ static int of_build_overlay_info(struct of_overlay *ov,
if (of_get_child_by_name(tree, "__symbols__")) if (of_get_child_by_name(tree, "__symbols__"))
cnt++; cnt++;
ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL); fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL);
if (!ovinfo) if (!fragments)
return -ENOMEM; return -ENOMEM;
cnt = 0; cnt = 0;
for_each_child_of_node(tree, node) { for_each_child_of_node(tree, node) {
err = of_fill_overlay_info(ov, node, &ovinfo[cnt]); ret = of_fill_overlay_info(ovcs, node, &fragments[cnt]);
if (!err) if (!ret)
cnt++; cnt++;
} }
node = of_get_child_by_name(tree, "__symbols__"); node = of_get_child_by_name(tree, "__symbols__");
if (node) { if (node) {
ovinfo[cnt].overlay = node; fragment = &fragments[cnt];
ovinfo[cnt].target = of_find_node_by_path("/__symbols__"); fragment->overlay = node;
ovinfo[cnt].is_symbols_node = 1; fragment->target = of_find_node_by_path("/__symbols__");
fragment->is_symbols_node = 1;
if (!ovinfo[cnt].target) { if (!fragment->target) {
pr_err("no symbols in root of device tree.\n"); pr_err("no symbols in root of device tree.\n");
return -EINVAL; return -EINVAL;
} }
...@@ -423,137 +470,127 @@ static int of_build_overlay_info(struct of_overlay *ov, ...@@ -423,137 +470,127 @@ static int of_build_overlay_info(struct of_overlay *ov,
} }
if (!cnt) { if (!cnt) {
kfree(ovinfo); kfree(fragments);
return -ENODEV; return -ENODEV;
} }
ov->count = cnt; ovcs->count = cnt;
ov->ovinfo_tab = ovinfo; ovcs->fragments = fragments;
return 0; return 0;
} }
/** /**
* of_free_overlay_info() - Free an overlay info array * free_overlay_fragments() - Free a fragments array
* @ov Overlay to free the overlay info from * @ovcs Overlay to free the overlay info from
* @ovinfo_tab: Array of overlay_info's to free
* *
* Releases the memory of a previously allocated ovinfo array * Frees the memory of an ovcs->fragments[] array.
* by of_build_overlay_info.
* Returns 0, or an error if the arguments are bogus.
*/ */
static int of_free_overlay_info(struct of_overlay *ov) static void free_overlay_fragments(struct overlay_changeset *ovcs)
{ {
struct of_overlay_info *ovinfo;
int i; int i;
/* do it in reverse */ /* do it in reverse */
for (i = ov->count - 1; i >= 0; i--) { for (i = ovcs->count - 1; i >= 0; i--) {
ovinfo = &ov->ovinfo_tab[i]; of_node_put(ovcs->fragments[i].target);
of_node_put(ovcs->fragments[i].overlay);
of_node_put(ovinfo->target);
of_node_put(ovinfo->overlay);
} }
kfree(ov->ovinfo_tab);
return 0; kfree(ovcs->fragments);
} }
static LIST_HEAD(ov_list); static LIST_HEAD(ovcs_list);
static DEFINE_IDR(ov_idr); static DEFINE_IDR(ovcs_idr);
/** /**
* of_overlay_create() - Create and apply an overlay * of_overlay_apply() - Create and apply an overlay changeset
* @tree: Device node containing all the overlays * @tree: Expanded overlay device tree
* *
* Creates and applies an overlay while also keeping track * Creates and applies an overlay changeset. If successful, the overlay
* of the overlay in a list. This list can be used to prevent * changeset is added to the overlay changeset list.
* illegal overlay removals.
* *
* Returns the id of the created overlay, or a negative error number * Returns the id of the created overlay changeset, or a negative error number
*/ */
int of_overlay_create(struct device_node *tree) int of_overlay_apply(struct device_node *tree)
{ {
struct of_overlay *ov; struct overlay_changeset *ovcs;
int err, id; int id, ret;
ov = kzalloc(sizeof(*ov), GFP_KERNEL); ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
if (!ov) if (!ovcs)
return -ENOMEM; return -ENOMEM;
ov->id = -1; ovcs->id = -1;
INIT_LIST_HEAD(&ov->node); INIT_LIST_HEAD(&ovcs->ovcs_list);
of_changeset_init(&ov->cset); of_changeset_init(&ovcs->cset);
mutex_lock(&of_mutex); mutex_lock(&of_mutex);
id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL); id = idr_alloc(&ovcs_idr, ovcs, 0, 0, GFP_KERNEL);
if (id < 0) { if (id < 0) {
err = id; ret = id;
goto err_destroy_trans; goto err_destroy_trans;
} }
ov->id = id; ovcs->id = id;
err = of_build_overlay_info(ov, tree); ret = init_overlay_changeset(ovcs, tree);
if (err) { if (ret) {
pr_err("of_build_overlay_info() failed for tree@%pOF\n", pr_err("init_overlay_changeset() failed for tree@%pOF\n",
tree); tree);
goto err_free_idr; goto err_free_idr;
} }
err = of_overlay_notify(ov, OF_OVERLAY_PRE_APPLY); ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
if (err < 0) { if (ret < 0) {
pr_err("%s: Pre-apply notifier failed (err=%d)\n", pr_err("%s: Pre-apply notifier failed (ret=%d)\n",
__func__, err); __func__, ret);
goto err_free_idr; goto err_free_overlay_fragments;
} }
err = of_overlay_apply(ov); ret = build_changeset(ovcs);
if (err) if (ret)
goto err_abort_trans; goto err_free_overlay_fragments;
err = __of_changeset_apply(&ov->cset);
if (err)
goto err_revert_overlay;
ret = __of_changeset_apply(&ovcs->cset);
if (ret)
goto err_free_overlay_fragments;
list_add_tail(&ov->node, &ov_list); list_add_tail(&ovcs->ovcs_list, &ovcs_list);
of_overlay_notify(ov, OF_OVERLAY_POST_APPLY); overlay_notify(ovcs, OF_OVERLAY_POST_APPLY);
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
return id; return id;
err_revert_overlay: err_free_overlay_fragments:
err_abort_trans: free_overlay_fragments(ovcs);
of_free_overlay_info(ov);
err_free_idr: err_free_idr:
idr_remove(&ov_idr, ov->id); idr_remove(&ovcs_idr, ovcs->id);
err_destroy_trans: err_destroy_trans:
of_changeset_destroy(&ov->cset); of_changeset_destroy(&ovcs->cset);
kfree(ov); kfree(ovcs);
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
return err; return ret;
} }
EXPORT_SYMBOL_GPL(of_overlay_create); EXPORT_SYMBOL_GPL(of_overlay_apply);
/* /*
* check whether the given node, lies under the given tree * Find @np in @tree.
* return 1 if under tree, else 0 *
* Returns 1 if @np is @tree or is contained in @tree, else 0
*/ */
static int overlay_subtree_check(struct device_node *tree, static int find_node(struct device_node *tree, struct device_node *np)
struct device_node *dn)
{ {
struct device_node *child; struct device_node *child;
if (tree == dn) if (tree == np)
return 1; return 1;
for_each_child_of_node(tree, child) { for_each_child_of_node(tree, child) {
if (overlay_subtree_check(child, dn)) { if (find_node(child, np)) {
of_node_put(child); of_node_put(child);
return 1; return 1;
} }
...@@ -563,30 +600,32 @@ static int overlay_subtree_check(struct device_node *tree, ...@@ -563,30 +600,32 @@ static int overlay_subtree_check(struct device_node *tree,
} }
/* /*
* check whether this overlay is the topmost * Is @remove_ce_np a child of or the same as any
* return 1 if topmost, else 0 * node in an overlay changeset more topmost than @remove_ovcs?
*
* Returns 1 if found, else 0
*/ */
static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn) static int node_in_later_cs(struct overlay_changeset *remove_ovcs,
struct device_node *remove_ce_np)
{ {
struct of_overlay *ovt; struct overlay_changeset *ovcs;
struct of_changeset_entry *ce; struct of_changeset_entry *ce;
list_for_each_entry_reverse(ovt, &ov_list, node) { list_for_each_entry_reverse(ovcs, &ovcs_list, ovcs_list) {
/* if we hit ourselves, we're done */ if (ovcs == remove_ovcs)
if (ovt == ov)
break; break;
/* check against each subtree affected by this overlay */ list_for_each_entry(ce, &ovcs->cset.entries, node) {
list_for_each_entry(ce, &ovt->cset.entries, node) { if (find_node(ce->np, remove_ce_np)) {
if (overlay_subtree_check(ce->np, dn)) {
pr_err("%s: #%d clashes #%d @%pOF\n", pr_err("%s: #%d clashes #%d @%pOF\n",
__func__, ov->id, ovt->id, dn); __func__, remove_ovcs->id, ovcs->id,
return 0; remove_ce_np);
return 1;
} }
} }
} }
return 1; return 0;
} }
/* /*
...@@ -599,13 +638,13 @@ static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn) ...@@ -599,13 +638,13 @@ static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn)
* the one closest to the tail. If another overlay has affected this * the one closest to the tail. If another overlay has affected this
* device node and is closest to the tail, then removal is not permited. * device node and is closest to the tail, then removal is not permited.
*/ */
static int overlay_removal_is_ok(struct of_overlay *ov) static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
{ {
struct of_changeset_entry *ce; struct of_changeset_entry *remove_ce;
list_for_each_entry(ce, &ov->cset.entries, node) { list_for_each_entry(remove_ce, &remove_ovcs->cset.entries, node) {
if (!overlay_is_topmost(ov, ce->np)) { if (node_in_later_cs(remove_ovcs, remove_ce->np)) {
pr_err("overlay #%d is not topmost\n", ov->id); pr_err("overlay #%d is not topmost\n", remove_ovcs->id);
return 0; return 0;
} }
} }
...@@ -614,74 +653,73 @@ static int overlay_removal_is_ok(struct of_overlay *ov) ...@@ -614,74 +653,73 @@ static int overlay_removal_is_ok(struct of_overlay *ov)
} }
/** /**
* of_overlay_destroy() - Removes an overlay * of_overlay_remove() - Revert and free an overlay changeset
* @id: Overlay id number returned by a previous call to of_overlay_create * @ovcs_id: Overlay changeset id number
* *
* Removes an overlay if it is permissible. * Removes an overlay if it is permissible. ovcs_id was previously returned
* by of_overlay_apply().
* *
* Returns 0 on success, or a negative error number * Returns 0 on success, or a negative error number
*/ */
int of_overlay_destroy(int id) int of_overlay_remove(int ovcs_id)
{ {
struct of_overlay *ov; struct overlay_changeset *ovcs;
int err; int ret = 0;
mutex_lock(&of_mutex); mutex_lock(&of_mutex);
ov = idr_find(&ov_idr, id); ovcs = idr_find(&ovcs_idr, ovcs_id);
if (!ov) { if (!ovcs) {
err = -ENODEV; ret = -ENODEV;
pr_err("destroy: Could not find overlay #%d\n", id); pr_err("remove: Could not find overlay #%d\n", ovcs_id);
goto out; goto out;
} }
if (!overlay_removal_is_ok(ov)) { if (!overlay_removal_is_ok(ovcs)) {
err = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
of_overlay_notify(ov, OF_OVERLAY_PRE_REMOVE); overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE);
list_del(&ov->node); list_del(&ovcs->ovcs_list);
__of_changeset_revert(&ov->cset); __of_changeset_revert(&ovcs->cset);
of_overlay_notify(ov, OF_OVERLAY_POST_REMOVE); overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE);
of_free_overlay_info(ov); free_overlay_fragments(ovcs);
idr_remove(&ov_idr, id); idr_remove(&ovcs_idr, ovcs_id);
of_changeset_destroy(&ov->cset); of_changeset_destroy(&ovcs->cset);
kfree(ov); kfree(ovcs);
err = 0;
out: out:
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
return err; return ret;
} }
EXPORT_SYMBOL_GPL(of_overlay_destroy); EXPORT_SYMBOL_GPL(of_overlay_remove);
/** /**
* of_overlay_destroy_all() - Removes all overlays from the system * of_overlay_remove_all() - Reverts and frees all overlay changesets
* *
* Removes all overlays from the system in the correct order. * Removes all overlays from the system in the correct order.
* *
* Returns 0 on success, or a negative error number * Returns 0 on success, or a negative error number
*/ */
int of_overlay_destroy_all(void) int of_overlay_remove_all(void)
{ {
struct of_overlay *ov, *ovn; struct overlay_changeset *ovcs, *ovcs_n;
mutex_lock(&of_mutex); mutex_lock(&of_mutex);
/* the tail of list is guaranteed to be safe to remove */ /* the tail of list is guaranteed to be safe to remove */
list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) { list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) {
list_del(&ov->node); list_del(&ovcs->ovcs_list);
__of_changeset_revert(&ov->cset); __of_changeset_revert(&ovcs->cset);
of_free_overlay_info(ov); free_overlay_fragments(ovcs);
idr_remove(&ov_idr, ov->id); idr_remove(&ovcs_idr, ovcs->id);
kfree(ov); kfree(ovcs);
} }
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(of_overlay_destroy_all); EXPORT_SYMBOL_GPL(of_overlay_remove_all);
...@@ -1230,7 +1230,7 @@ static void of_unittest_destroy_tracked_overlays(void) ...@@ -1230,7 +1230,7 @@ static void of_unittest_destroy_tracked_overlays(void)
if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id))) if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
continue; continue;
ret = of_overlay_destroy(id + overlay_first_id); ret = of_overlay_remove(id + overlay_first_id);
if (ret == -ENODEV) { if (ret == -ENODEV) {
pr_warn("%s: no overlay to destroy for #%d\n", pr_warn("%s: no overlay to destroy for #%d\n",
__func__, id + overlay_first_id); __func__, id + overlay_first_id);
...@@ -1262,7 +1262,7 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr, ...@@ -1262,7 +1262,7 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
goto out; goto out;
} }
ret = of_overlay_create(np); ret = of_overlay_apply(np);
if (ret < 0) { if (ret < 0) {
unittest(0, "could not create overlay from \"%s\"\n", unittest(0, "could not create overlay from \"%s\"\n",
overlay_path(overlay_nr)); overlay_path(overlay_nr));
...@@ -1347,7 +1347,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr, ...@@ -1347,7 +1347,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
return -EINVAL; return -EINVAL;
} }
ret = of_overlay_destroy(ov_id); ret = of_overlay_remove(ov_id);
if (ret != 0) { if (ret != 0) {
unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
overlay_path(overlay_nr), overlay_path(overlay_nr),
...@@ -1476,7 +1476,7 @@ static void of_unittest_overlay_6(void) ...@@ -1476,7 +1476,7 @@ static void of_unittest_overlay_6(void)
return; return;
} }
ret = of_overlay_create(np); ret = of_overlay_apply(np);
if (ret < 0) { if (ret < 0) {
unittest(0, "could not create overlay from \"%s\"\n", unittest(0, "could not create overlay from \"%s\"\n",
overlay_path(overlay_nr + i)); overlay_path(overlay_nr + i));
...@@ -1500,7 +1500,7 @@ static void of_unittest_overlay_6(void) ...@@ -1500,7 +1500,7 @@ static void of_unittest_overlay_6(void)
} }
for (i = 1; i >= 0; i--) { for (i = 1; i >= 0; i--) {
ret = of_overlay_destroy(ov_id[i]); ret = of_overlay_remove(ov_id[i]);
if (ret != 0) { if (ret != 0) {
unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
overlay_path(overlay_nr + i), overlay_path(overlay_nr + i),
...@@ -1546,7 +1546,7 @@ static void of_unittest_overlay_8(void) ...@@ -1546,7 +1546,7 @@ static void of_unittest_overlay_8(void)
return; return;
} }
ret = of_overlay_create(np); ret = of_overlay_apply(np);
if (ret < 0) { if (ret < 0) {
unittest(0, "could not create overlay from \"%s\"\n", unittest(0, "could not create overlay from \"%s\"\n",
overlay_path(overlay_nr + i)); overlay_path(overlay_nr + i));
...@@ -1557,7 +1557,7 @@ static void of_unittest_overlay_8(void) ...@@ -1557,7 +1557,7 @@ static void of_unittest_overlay_8(void)
} }
/* now try to remove first overlay (it should fail) */ /* now try to remove first overlay (it should fail) */
ret = of_overlay_destroy(ov_id[0]); ret = of_overlay_remove(ov_id[0]);
if (ret == 0) { if (ret == 0) {
unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
overlay_path(overlay_nr + 0), overlay_path(overlay_nr + 0),
...@@ -1568,7 +1568,7 @@ static void of_unittest_overlay_8(void) ...@@ -1568,7 +1568,7 @@ static void of_unittest_overlay_8(void)
/* removing them in order should work */ /* removing them in order should work */
for (i = 1; i >= 0; i--) { for (i = 1; i >= 0; i--) {
ret = of_overlay_destroy(ov_id[i]); ret = of_overlay_remove(ov_id[i]);
if (ret != 0) { if (ret != 0) {
unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
overlay_path(overlay_nr + i), overlay_path(overlay_nr + i),
...@@ -2149,9 +2149,9 @@ static int __init overlay_data_add(int onum) ...@@ -2149,9 +2149,9 @@ static int __init overlay_data_add(int onum)
goto out_free_np_overlay; goto out_free_np_overlay;
} }
ret = of_overlay_create(info->np_overlay); ret = of_overlay_apply(info->np_overlay);
if (ret < 0) { if (ret < 0) {
pr_err("of_overlay_create() (ret=%d), %d\n", ret, onum); pr_err("of_overlay_apply() (ret=%d), %d\n", ret, onum);
goto out_free_np_overlay; goto out_free_np_overlay;
} else { } else {
info->overlay_id = ret; info->overlay_id = ret;
......
...@@ -1312,26 +1312,26 @@ struct of_overlay_notify_data { ...@@ -1312,26 +1312,26 @@ struct of_overlay_notify_data {
#ifdef CONFIG_OF_OVERLAY #ifdef CONFIG_OF_OVERLAY
/* ID based overlays; the API for external users */ /* ID based overlays; the API for external users */
int of_overlay_create(struct device_node *tree); int of_overlay_apply(struct device_node *tree);
int of_overlay_destroy(int id); int of_overlay_remove(int id);
int of_overlay_destroy_all(void); int of_overlay_remove_all(void);
int of_overlay_notifier_register(struct notifier_block *nb); int of_overlay_notifier_register(struct notifier_block *nb);
int of_overlay_notifier_unregister(struct notifier_block *nb); int of_overlay_notifier_unregister(struct notifier_block *nb);
#else #else
static inline int of_overlay_create(struct device_node *tree) static inline int of_overlay_apply(struct device_node *tree)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
static inline int of_overlay_destroy(int id) static inline int of_overlay_remove(int id)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
static inline int of_overlay_destroy_all(void) static inline int of_overlay_remove_all(void)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
......
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