From: Alan Tull <atull@opensource.altera.com>
To: Pantelis Antoniou <pantelis.antoniou@konsulko.com>,
Rob Herring <robh+dt@kernel.org>
Cc: Frank Rowand <frowand.list@gmail.com>,
Grant Likely <grant.likely@linaro.org>,
<devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
Moritz Fischer <moritz.fischer@ettus.com>,
Pantelis Antoniou <pantelis.antoniou@gmail.com>,
Alan Tull <delicious.quinoa@gmail.com>,
Dinh Nguyen <dinguyen@opensource.altera.com>,
Alan Tull <atull@opensource.altera.com>
Subject: [PATCH 1/1] of/overlay: of overlay callbacks
Date: Wed, 17 Feb 2016 11:41:25 -0600 [thread overview]
Message-ID: <1455730885-1514-2-git-send-email-atull@opensource.altera.com> (raw)
In-Reply-To: <1455730885-1514-1-git-send-email-atull@opensource.altera.com>
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@opensource.altera.com>
---
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
next prev parent reply other threads:[~2016-02-17 17:43 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-17 17:41 [PATCH 0/1] " Alan Tull
2016-02-17 17:41 ` Alan Tull [this message]
2016-02-18 5:13 ` [PATCH 1/1] of/overlay: " Moritz Fischer
2016-02-18 15:10 ` atull
2016-02-22 2:55 ` Rob Herring
2016-02-22 15:38 ` Pantelis Antoniou
2016-02-22 21:40 ` atull
2016-02-24 22:36 ` atull
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1455730885-1514-2-git-send-email-atull@opensource.altera.com \
--to=atull@opensource.altera.com \
--cc=delicious.quinoa@gmail.com \
--cc=devicetree@vger.kernel.org \
--cc=dinguyen@opensource.altera.com \
--cc=frowand.list@gmail.com \
--cc=grant.likely@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=moritz.fischer@ettus.com \
--cc=pantelis.antoniou@gmail.com \
--cc=pantelis.antoniou@konsulko.com \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome