|
@@ -58,6 +58,41 @@ struct of_overlay {
|
|
static int of_overlay_apply_one(struct of_overlay *ov,
|
|
static int of_overlay_apply_one(struct of_overlay *ov,
|
|
struct device_node *target, const struct device_node *overlay);
|
|
struct device_node *target, const struct device_node *overlay);
|
|
|
|
|
|
|
|
+static BLOCKING_NOTIFIER_HEAD(of_overlay_chain);
|
|
|
|
+
|
|
|
|
+int of_overlay_notifier_register(struct notifier_block *nb)
|
|
|
|
+{
|
|
|
|
+ return blocking_notifier_chain_register(&of_overlay_chain, nb);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(of_overlay_notifier_register);
|
|
|
|
+
|
|
|
|
+int of_overlay_notifier_unregister(struct notifier_block *nb)
|
|
|
|
+{
|
|
|
|
+ return blocking_notifier_chain_unregister(&of_overlay_chain, nb);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister);
|
|
|
|
+
|
|
|
|
+static int of_overlay_notify(struct of_overlay *ov,
|
|
|
|
+ enum of_overlay_notify_action action)
|
|
|
|
+{
|
|
|
|
+ struct of_overlay_notify_data nd;
|
|
|
|
+ int i, ret;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < ov->count; i++) {
|
|
|
|
+ struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
|
|
|
|
+
|
|
|
|
+ nd.target = ovinfo->target;
|
|
|
|
+ nd.overlay = ovinfo->overlay;
|
|
|
|
+
|
|
|
|
+ ret = blocking_notifier_call_chain(&of_overlay_chain,
|
|
|
|
+ action, &nd);
|
|
|
|
+ if (ret)
|
|
|
|
+ return notifier_to_errno(ret);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int of_overlay_apply_single_property(struct of_overlay *ov,
|
|
static int of_overlay_apply_single_property(struct of_overlay *ov,
|
|
struct device_node *target, struct property *prop)
|
|
struct device_node *target, struct property *prop)
|
|
{
|
|
{
|
|
@@ -368,6 +403,13 @@ int of_overlay_create(struct device_node *tree)
|
|
goto err_free_idr;
|
|
goto err_free_idr;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ err = of_overlay_notify(ov, OF_OVERLAY_PRE_APPLY);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ pr_err("%s: Pre-apply notifier failed (err=%d)\n",
|
|
|
|
+ __func__, err);
|
|
|
|
+ goto err_free_idr;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* apply the overlay */
|
|
/* apply the overlay */
|
|
err = of_overlay_apply(ov);
|
|
err = of_overlay_apply(ov);
|
|
if (err)
|
|
if (err)
|
|
@@ -382,6 +424,8 @@ int of_overlay_create(struct device_node *tree)
|
|
/* add to the tail of the overlay list */
|
|
/* add to the tail of the overlay list */
|
|
list_add_tail(&ov->node, &ov_list);
|
|
list_add_tail(&ov->node, &ov_list);
|
|
|
|
|
|
|
|
+ of_overlay_notify(ov, OF_OVERLAY_POST_APPLY);
|
|
|
|
+
|
|
mutex_unlock(&of_mutex);
|
|
mutex_unlock(&of_mutex);
|
|
|
|
|
|
return id;
|
|
return id;
|
|
@@ -498,9 +542,10 @@ int of_overlay_destroy(int id)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
+ of_overlay_notify(ov, OF_OVERLAY_PRE_REMOVE);
|
|
list_del(&ov->node);
|
|
list_del(&ov->node);
|
|
__of_changeset_revert(&ov->cset);
|
|
__of_changeset_revert(&ov->cset);
|
|
|
|
+ of_overlay_notify(ov, OF_OVERLAY_POST_REMOVE);
|
|
of_free_overlay_info(ov);
|
|
of_free_overlay_info(ov);
|
|
idr_remove(&ov_idr, id);
|
|
idr_remove(&ov_idr, id);
|
|
of_changeset_destroy(&ov->cset);
|
|
of_changeset_destroy(&ov->cset);
|