summaryrefslogtreecommitdiff
path: root/drivers/remoteproc
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2020-03-23 22:29:02 -0700
committerBjorn Andersson <bjorn.andersson@linaro.org>2020-03-25 22:29:45 -0700
commitdc5192c449368eed3385f4405670aa3ed21d6270 (patch)
tree9875fe39fdbebb01dd5649cf2dbfee809ccead83 /drivers/remoteproc
parentc0abe2ca3605e4c4fb25bf69d0218c63baf71d2b (diff)
remoteproc: Introduce "panic" callback in ops
Introduce generic support for handling kernel panics in remoteproc drivers, in order to allow operations needed for aiding in post mortem system debugging, such as flushing caches etc. The function can return a number of milliseconds needed by the remote to "settle" and the core will wait the longest returned duration before returning from the panic handler. Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org> Link: https://lore.kernel.org/r/20200324052904.738594-3-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/remoteproc_core.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 7ee976ee2044..e12a54e67588 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -16,6 +16,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -45,6 +46,7 @@
static DEFINE_MUTEX(rproc_list_mutex);
static LIST_HEAD(rproc_list);
+static struct notifier_block rproc_panic_nb;
typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
void *, int offset, int avail);
@@ -2236,10 +2238,50 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
}
EXPORT_SYMBOL(rproc_report_crash);
+static int rproc_panic_handler(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ unsigned int longest = 0;
+ struct rproc *rproc;
+ unsigned int d;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(rproc, &rproc_list, node) {
+ if (!rproc->ops->panic || rproc->state != RPROC_RUNNING)
+ continue;
+
+ d = rproc->ops->panic(rproc);
+ longest = max(longest, d);
+ }
+ rcu_read_unlock();
+
+ /*
+ * Delay for the longest requested duration before returning. This can
+ * be used by the remoteproc drivers to give the remote processor time
+ * to perform any requested operations (such as flush caches), when
+ * it's not possible to signal the Linux side due to the panic.
+ */
+ mdelay(longest);
+
+ return NOTIFY_DONE;
+}
+
+static void __init rproc_init_panic(void)
+{
+ rproc_panic_nb.notifier_call = rproc_panic_handler;
+ atomic_notifier_chain_register(&panic_notifier_list, &rproc_panic_nb);
+}
+
+static void __exit rproc_exit_panic(void)
+{
+ atomic_notifier_chain_unregister(&panic_notifier_list, &rproc_panic_nb);
+}
+
static int __init remoteproc_init(void)
{
rproc_init_sysfs();
rproc_init_debugfs();
+ rproc_init_panic();
return 0;
}
@@ -2249,6 +2291,7 @@ static void __exit remoteproc_exit(void)
{
ida_destroy(&rproc_dev_index);
+ rproc_exit_panic();
rproc_exit_debugfs();
rproc_exit_sysfs();
}