Commit 61b4de4e authored by Frank Rowand's avatar Frank Rowand Committed by Rob Herring

of: overlay: minor restructuring

Continue improving the readability of overlay.c.  The previous patches
renamed identifiers.  This patch is split out from the previous patches
to make the previous patches easier to review.

Changes are:
  - minor code restructuring
  - some initialization of an overlay changeset occurred outside of
    init_overlay_changeset(), move that into init_overlay_changeset()
  - consolidate freeing an overlay changeset into free_overlay_changeset()

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 42b2e94f
...@@ -55,6 +55,9 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs, ...@@ -55,6 +55,9 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs,
const struct device_node *overlay_node, const struct device_node *overlay_node,
bool is_symbols_node); bool is_symbols_node);
static LIST_HEAD(ovcs_list);
static DEFINE_IDR(ovcs_idr);
static BLOCKING_NOTIFIER_HEAD(overlay_notify_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)
...@@ -160,8 +163,6 @@ static struct property *dup_and_fixup_symbol_prop( ...@@ -160,8 +163,6 @@ static struct property *dup_and_fixup_symbol_prop(
kfree(new->value); kfree(new->value);
kfree(new); kfree(new);
return NULL; return NULL;
} }
/** /**
...@@ -258,13 +259,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs, ...@@ -258,13 +259,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs,
if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name))) if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
break; break;
if (tchild) { if (!tchild) {
if (node->phandle)
return -EINVAL;
ret = build_changeset_next_level(ovcs, tchild, node, 0);
of_node_put(tchild);
} else {
tchild = __of_node_dup(node, "%pOF/%s", tchild = __of_node_dup(node, "%pOF/%s",
target_node, node_kbasename); target_node, node_kbasename);
if (!tchild) if (!tchild)
...@@ -276,11 +271,15 @@ static int add_changeset_node(struct overlay_changeset *ovcs, ...@@ -276,11 +271,15 @@ static int add_changeset_node(struct overlay_changeset *ovcs,
if (ret) if (ret)
return ret; return ret;
ret = build_changeset_next_level(ovcs, tchild, node, 0); return build_changeset_next_level(ovcs, tchild, node, 0);
if (ret)
return ret;
} }
if (node->phandle)
return -EINVAL;
ret = build_changeset_next_level(ovcs, tchild, node, 0);
of_node_put(tchild);
return ret; return ret;
} }
...@@ -393,41 +392,6 @@ static struct device_node *find_target_node(struct device_node *info_node) ...@@ -393,41 +392,6 @@ static struct device_node *find_target_node(struct device_node *info_node)
return NULL; return NULL;
} }
/**
* of_fill_overlay_info() - Fill an overlay info structure
* @ov Overlay to fill
* @info_node: Device node containing the overlay
* @ovinfo: Pointer to the overlay info structure to fill
*
* Fills an overlay info structure with the overlay information
* from a device node. This device node must have a target property
* which contains a phandle of the overlay target node, and an
* __overlay__ child node which has the overlay contents.
* Both ovinfo->target & ovinfo->overlay have their references taken.
*
* Returns 0 on success, or a negative error value.
*/
static int of_fill_overlay_info(struct overlay_changeset *ovcset,
struct device_node *info_node, struct fragment *fragment)
{
fragment->overlay = of_get_child_by_name(info_node, "__overlay__");
if (!fragment->overlay)
goto err_fail;
fragment->target = find_target_node(info_node);
if (!fragment->target)
goto err_fail;
return 0;
err_fail:
of_node_put(fragment->target);
of_node_put(fragment->overlay);
memset(fragment, 0, sizeof(*fragment));
return -EINVAL;
}
/** /**
* init_overlay_changeset() - initialize overlay changeset from overlay tree * init_overlay_changeset() - initialize overlay changeset from overlay tree
* @ovcs Overlay changeset to build * @ovcs Overlay changeset to build
...@@ -438,32 +402,61 @@ static int of_fill_overlay_info(struct overlay_changeset *ovcset, ...@@ -438,32 +402,61 @@ static int of_fill_overlay_info(struct overlay_changeset *ovcset,
* nodes and the __symbols__ node. Any other top level node will be ignored. * nodes and the __symbols__ node. Any other top level node will be ignored.
* *
* Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
* detected in @tree, or -ENODEV if no valid nodes found. * detected in @tree, or -ENOSPC if idr_alloc() error.
*/ */
static int init_overlay_changeset(struct overlay_changeset *ovcs, 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, *overlay_node;
struct fragment *fragment; struct fragment *fragment;
struct fragment *fragments; struct fragment *fragments;
int cnt, ret; int cnt, ret;
INIT_LIST_HEAD(&ovcs->ovcs_list);
of_changeset_init(&ovcs->cset);
ovcs->id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL);
if (ovcs->id <= 0)
return ovcs->id;
cnt = 0; cnt = 0;
for_each_child_of_node(tree, node)
cnt++;
if (of_get_child_by_name(tree, "__symbols__")) /* fragment nodes */
for_each_child_of_node(tree, node) {
overlay_node = of_get_child_by_name(node, "__overlay__");
if (overlay_node) {
cnt++;
of_node_put(overlay_node);
}
}
node = of_get_child_by_name(tree, "__symbols__");
if (node) {
cnt++; cnt++;
of_node_put(node);
}
fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL); fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL);
if (!fragments) if (!fragments) {
return -ENOMEM; ret = -ENOMEM;
goto err_free_idr;
}
cnt = 0; cnt = 0;
for_each_child_of_node(tree, node) { for_each_child_of_node(tree, node) {
ret = of_fill_overlay_info(ovcs, node, &fragments[cnt]); fragment = &fragments[cnt];
if (!ret) fragment->overlay = of_get_child_by_name(node, "__overlay__");
cnt++; if (fragment->overlay) {
fragment->target = find_target_node(node);
if (!fragment->target) {
of_node_put(fragment->overlay);
ret = -EINVAL;
goto err_free_fragments;
} else {
cnt++;
}
}
} }
node = of_get_child_by_name(tree, "__symbols__"); node = of_get_child_by_name(tree, "__symbols__");
...@@ -475,44 +468,51 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, ...@@ -475,44 +468,51 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
if (!fragment->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; ret = -EINVAL;
goto err_free_fragments;
} }
cnt++; cnt++;
} }
if (!cnt) { if (!cnt) {
kfree(fragments); ret = -EINVAL;
return -ENODEV; goto err_free_fragments;
} }
ovcs->count = cnt; ovcs->count = cnt;
ovcs->fragments = fragments; ovcs->fragments = fragments;
return 0; return 0;
err_free_fragments:
kfree(fragments);
err_free_idr:
idr_remove(&ovcs_idr, ovcs->id);
return ret;
} }
/** static void free_overlay_changeset(struct overlay_changeset *ovcs)
* free_overlay_fragments() - Free a fragments array
* @ovcs Overlay to free the overlay info from
*
* Frees the memory of an ovcs->fragments[] array.
*/
static void free_overlay_fragments(struct overlay_changeset *ovcs)
{ {
int i; int i;
/* do it in reverse */ if (!ovcs->cset.entries.next)
for (i = ovcs->count - 1; i >= 0; i--) { return;
of_changeset_destroy(&ovcs->cset);
if (ovcs->id)
idr_remove(&ovcs_idr, ovcs->id);
for (i = 0; i < ovcs->count; i++) {
of_node_put(ovcs->fragments[i].target); of_node_put(ovcs->fragments[i].target);
of_node_put(ovcs->fragments[i].overlay); of_node_put(ovcs->fragments[i].overlay);
} }
kfree(ovcs->fragments); kfree(ovcs->fragments);
}
static LIST_HEAD(ovcs_list); kfree(ovcs);
static DEFINE_IDR(ovcs_idr); }
/** /**
* of_overlay_apply() - Create and apply an overlay changeset * of_overlay_apply() - Create and apply an overlay changeset
...@@ -526,47 +526,34 @@ static DEFINE_IDR(ovcs_idr); ...@@ -526,47 +526,34 @@ static DEFINE_IDR(ovcs_idr);
int of_overlay_apply(struct device_node *tree) int of_overlay_apply(struct device_node *tree)
{ {
struct overlay_changeset *ovcs; struct overlay_changeset *ovcs;
int id, ret; int ret;
ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
if (!ovcs) if (!ovcs)
return -ENOMEM; return -ENOMEM;
ovcs->id = -1;
INIT_LIST_HEAD(&ovcs->ovcs_list);
of_changeset_init(&ovcs->cset);
mutex_lock(&of_mutex); mutex_lock(&of_mutex);
id = idr_alloc(&ovcs_idr, ovcs, 0, 0, GFP_KERNEL);
if (id < 0) {
ret = id;
goto err_destroy_trans;
}
ovcs->id = id;
ret = init_overlay_changeset(ovcs, tree); ret = init_overlay_changeset(ovcs, tree);
if (ret) { if (ret) {
pr_err("init_overlay_changeset() failed for tree@%pOF\n", pr_err("init_overlay_changeset() failed, ret = %d\n", ret);
tree); goto err_free_overlay_changeset;
goto err_free_idr;
} }
ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
if (ret < 0) { if (ret < 0) {
pr_err("%s: Pre-apply notifier failed (ret=%d)\n", pr_err("%s: Pre-apply notifier failed (ret=%d)\n",
__func__, ret); __func__, ret);
goto err_free_overlay_fragments; goto err_free_overlay_changeset;
} }
ret = build_changeset(ovcs); ret = build_changeset(ovcs);
if (ret) if (ret)
goto err_free_overlay_fragments; goto err_free_overlay_changeset;
ret = __of_changeset_apply(&ovcs->cset); ret = __of_changeset_apply(&ovcs->cset);
if (ret) if (ret)
goto err_free_overlay_fragments; goto err_free_overlay_changeset;
list_add_tail(&ovcs->ovcs_list, &ovcs_list); list_add_tail(&ovcs->ovcs_list, &ovcs_list);
...@@ -574,15 +561,11 @@ int of_overlay_apply(struct device_node *tree) ...@@ -574,15 +561,11 @@ int of_overlay_apply(struct device_node *tree)
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
return id; return ovcs->id;
err_free_overlay_changeset:
free_overlay_changeset(ovcs);
err_free_overlay_fragments:
free_overlay_fragments(ovcs);
err_free_idr:
idr_remove(&ovcs_idr, ovcs->id);
err_destroy_trans:
of_changeset_destroy(&ovcs->cset);
kfree(ovcs);
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
return ret; return ret;
...@@ -693,13 +676,14 @@ int of_overlay_remove(int ovcs_id) ...@@ -693,13 +676,14 @@ int of_overlay_remove(int ovcs_id)
} }
overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE); overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE);
list_del(&ovcs->ovcs_list); list_del(&ovcs->ovcs_list);
__of_changeset_revert(&ovcs->cset); __of_changeset_revert(&ovcs->cset);
overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE); overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE);
free_overlay_fragments(ovcs);
idr_remove(&ovcs_idr, ovcs_id); free_overlay_changeset(ovcs);
of_changeset_destroy(&ovcs->cset);
kfree(ovcs);
out: out:
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
...@@ -718,20 +702,15 @@ EXPORT_SYMBOL_GPL(of_overlay_remove); ...@@ -718,20 +702,15 @@ EXPORT_SYMBOL_GPL(of_overlay_remove);
int of_overlay_remove_all(void) int of_overlay_remove_all(void)
{ {
struct overlay_changeset *ovcs, *ovcs_n; struct overlay_changeset *ovcs, *ovcs_n;
int ret;
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(ovcs, ovcs_n, &ovcs_list, ovcs_list) { list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) {
list_del(&ovcs->ovcs_list); ret = of_overlay_remove(ovcs->id);
__of_changeset_revert(&ovcs->cset); if (ret)
free_overlay_fragments(ovcs); return ret;
idr_remove(&ovcs_idr, ovcs->id);
kfree(ovcs);
} }
mutex_unlock(&of_mutex);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(of_overlay_remove_all); EXPORT_SYMBOL_GPL(of_overlay_remove_all);
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