* [PATCH] of overlay callbacks
@ 2016-02-16 18:37 Alan Tull
[not found] ` <1455647861-31973-1-git-send-email-atull-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
0 siblings, 1 reply; 2+ messages in thread
From: Alan Tull @ 2016-02-16 18:37 UTC (permalink / raw)
To: Pantelis Antoniou, Rob Herring
Cc: Frank Rowand, Grant Likely, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Moritz Fischer, Alan Tull,
Dinh Nguyen, Alan Tull
Adding functionality for registering callbacks with the
of overlay code.
When DT overlays are being added, some drivers/subsystems
will want to know about the changes before they go into the
live tree. Similarly there is a need for post-remove
callbacks.
Each handler is registered with a of_device_id. When
an overlay target matches a handler's id, the handler
gets called.
The following 4 cases are handled: pre-apply, post-apply,
pre-remove, and post-remove.
This is useful for me as I can apply an FPGA overlay that
contains the file name that I want to program the FPGA with
and the child device information. My FPGA code gets the
pre-apply callback and attempts to program the FPGA. If
the programming failed, the callback can return an error
and prevent the overlay from being applied.
I've tested this with code that uses pre-apply and post-remove
handlers. Tested on next-20160216 and Pantelis' current
bbb-overlays branch.
Alan Tull (1):
of/overlay: of overlay callbacks
drivers/of/overlay.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/of.h | 31 +++++++++++++++++
2 files changed, 120 insertions(+), 1 deletion(-)
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH] of/overlay: of overlay callbacks
[not found] ` <1455647861-31973-1-git-send-email-atull-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
@ 2016-02-16 18:37 ` Alan Tull
0 siblings, 0 replies; 2+ messages in thread
From: Alan Tull @ 2016-02-16 18:37 UTC (permalink / raw)
To: Pantelis Antoniou, Rob Herring
Cc: Frank Rowand, Grant Likely, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Moritz Fischer, Alan Tull,
Dinh Nguyen, Alan Tull
Add overlay callback functionality.
When DT overlays are being added, some drivers/subsystems
will want to know about the changes before they go into the
live tree. Similarly there is a need for post-remove
callbacks.
Each handler is registered with a of_device_id. When
an overlay target matches a handler's id, the handler
gets called.
The following 4 cases are handled: pre-apply, post-apply,
pre-remove, and post-remove.
Signed-off-by: Alan Tull <atull-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
---
drivers/of/overlay.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/of.h | 31 +++++++++++++++++
2 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 8225081..ee88e4e 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -20,9 +20,13 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/idr.h>
+#include <linux/list.h>
#include "of_private.h"
+static DEFINE_SPINLOCK(of_overlay_handler_lock);
+static LIST_HEAD(of_overlay_handler_list);
+
/**
* struct of_overlay_info - Holds a single overlay info
* @target: target of the overlay operation
@@ -56,6 +60,80 @@ struct of_overlay {
static int of_overlay_apply_one(struct of_overlay *ov,
struct device_node *target, const struct device_node *overlay);
+/*
+ * Send overlay callbacks to handlers that match. This call is blocking. In
+ * the case OF_OVERLAY_PRE_APPLY, return error for the first handler that fails.
+ * Otherwise, notify all the matching handlers and return success.
+ */
+static int send_overlay_callbacks(struct of_overlay *ov, int type)
+{
+ int i, ret;
+
+ spin_lock(&of_overlay_handler_lock);
+
+ for (i = 0; i < ov->count; i++) {
+ struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
+ struct of_overlay_handler *handler;
+ int (*callback)(struct of_overlay_msg *msg);
+ struct of_overlay_msg msg_data;
+
+ msg_data.target = ovinfo->target;
+ msg_data.overlay = ovinfo->overlay;
+
+ list_for_each_entry(handler, &of_overlay_handler_list, node) {
+ msg_data.priv = handler->priv;
+ switch (type) {
+ case OF_OVERLAY_PRE_APPLY:
+ callback = handler->pre_apply_callback;
+ break;
+ case OF_OVERLAY_POST_APPLY:
+ callback = handler->post_apply_callback;
+ break;
+ case OF_OVERLAY_PRE_REMOVE:
+ callback = handler->pre_remove_callback;
+ break;
+ case OF_OVERLAY_POST_REMOVE:
+ callback = handler->post_remove_callback;
+ break;
+ default:
+ continue;
+ };
+ if (!callback)
+ continue;
+ if (of_match_node(handler->of_match, ovinfo->target)) {
+ ret = callback(&msg_data);
+ if ((ret < 0) && (type == OF_OVERLAY_PRE_APPLY)) {
+ spin_unlock(&of_overlay_handler_lock);
+ return ret;
+ }
+ continue;
+ }
+ }
+ }
+
+ spin_unlock(&of_overlay_handler_lock);
+
+ return 0;
+}
+
+int of_overlay_handler_register(struct of_overlay_handler *handler)
+{
+ spin_lock(&of_overlay_handler_lock);
+ list_add_tail(&handler->node, &of_overlay_handler_list);
+ spin_unlock(&of_overlay_handler_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_overlay_handler_register);
+
+void of_overlay_handler_unregister(struct of_overlay_handler *handler)
+{
+ spin_lock(&of_overlay_handler_lock);
+ list_del(&handler->node);
+ spin_unlock(&of_overlay_handler_lock);
+}
+EXPORT_SYMBOL_GPL(of_overlay_handler_unregister);
+
static int of_overlay_apply_single_property(struct of_overlay *ov,
struct device_node *target, struct property *prop)
{
@@ -370,6 +448,13 @@ int of_overlay_create(struct device_node *tree)
goto err_free_idr;
}
+ err = send_overlay_callbacks(ov, OF_OVERLAY_PRE_APPLY);
+ if (err < 0) {
+ pr_err("%s: Pre apply handler failed (err=%d)\n",
+ __func__, err);
+ goto err_free_idr;
+ }
+
/* apply the overlay */
err = of_overlay_apply(ov);
if (err) {
@@ -389,6 +474,8 @@ int of_overlay_create(struct device_node *tree)
/* add to the tail of the overlay list */
list_add_tail(&ov->node, &ov_list);
+ send_overlay_callbacks(ov, OF_OVERLAY_POST_APPLY);
+
mutex_unlock(&of_mutex);
return id;
@@ -509,9 +596,10 @@ int of_overlay_destroy(int id)
goto out;
}
-
+ send_overlay_callbacks(ov, OF_OVERLAY_PRE_REMOVE);
list_del(&ov->node);
__of_changeset_revert(&ov->cset);
+ send_overlay_callbacks(ov, OF_OVERLAY_POST_REMOVE);
of_free_overlay_info(ov);
idr_remove(&ov_idr, id);
of_changeset_destroy(&ov->cset);
diff --git a/include/linux/of.h b/include/linux/of.h
index dc6e396..def9481 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -101,9 +101,33 @@ static inline int of_node_is_attached(struct device_node *node)
return node && node->kobj.state_in_sysfs;
}
+/* Callback types */
+#define OF_OVERLAY_PRE_APPLY (0)
+#define OF_OVERLAY_POST_APPLY (1)
+#define OF_OVERLAY_PRE_REMOVE (2)
+#define OF_OVERLAY_POST_REMOVE (3)
+
+struct of_overlay_msg {
+ struct device_node *overlay;
+ struct device_node *target;
+ void *priv;
+};
+
+struct of_overlay_handler {
+ int (*pre_apply_callback)(struct of_overlay_msg *msg);
+ int (*post_apply_callback)(struct of_overlay_msg *msg);
+ int (*pre_remove_callback)(struct of_overlay_msg *msg);
+ int (*post_remove_callback)(struct of_overlay_msg *msg);
+ const struct of_device_id *of_match;
+ struct list_head node;
+ void *priv;
+};
+
#ifdef CONFIG_OF_DYNAMIC
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);
+extern int of_overlay_handler_register(struct of_overlay_handler *handler);
+extern void of_overlay_handler_unregister(struct of_overlay_handler *handler);
#else /* CONFIG_OF_DYNAMIC */
/* Dummy ref counting routines - to be implemented later */
static inline struct device_node *of_node_get(struct device_node *node)
@@ -111,6 +135,13 @@ static inline struct device_node *of_node_get(struct device_node *node)
return node;
}
static inline void of_node_put(struct device_node *node) { }
+static int of_overlay_handler_register(struct of_overlay_handler *handler)
+{
+ return -EINVAL;
+}
+static void of_overlay_handler_unregister(struct of_overlay_handler *handler)
+{
+}
#endif /* !CONFIG_OF_DYNAMIC */
/* Pointer for first entry in chain of all nodes. */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2016-02-16 18:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-16 18:37 [PATCH] of overlay callbacks Alan Tull
[not found] ` <1455647861-31973-1-git-send-email-atull-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
2016-02-16 18:37 ` [PATCH] of/overlay: " Alan Tull
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).