summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2015-09-01 09:43:55 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2015-09-01 09:43:55 +0200
commit67e0a30e77c0dadfb225eef7e9bdcccdcae4d679 (patch)
treeaa1887ec66dc1e48eaeacca93ac38b55a49a3f99 /common
parentb7ab2081b1f1f13f0823bb6e8e33884510e105d7 (diff)
parentce36b4a05e275dcc12e74e96ddae99c21faad466 (diff)
downloadbarebox-67e0a30e77c0dadfb225eef7e9bdcccdcae4d679.tar.gz
barebox-67e0a30e77c0dadfb225eef7e9bdcccdcae4d679.tar.xz
Merge branch 'for-next/restart'
Diffstat (limited to 'common')
-rw-r--r--common/Makefile1
-rw-r--r--common/misc.c3
-rw-r--r--common/reset_source.c31
-rw-r--r--common/restart.c112
4 files changed, 142 insertions, 5 deletions
diff --git a/common/Makefile b/common/Makefile
index ed131c8c56..1e7a08190c 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -8,6 +8,7 @@ obj-y += misc.o
obj-pbl-y += memsize.o
obj-y += resource.o
obj-y += bootsource.o
+obj-y += restart.o
obj-$(CONFIG_AUTO_COMPLETE) += complete.o
obj-$(CONFIG_BANNER) += version.o
obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o
diff --git a/common/misc.c b/common/misc.c
index 6da71c7ab7..5532349e43 100644
--- a/common/misc.c
+++ b/common/misc.c
@@ -24,6 +24,7 @@
#include <environment.h>
#include <led.h>
#include <of.h>
+#include <restart.h>
int errno;
EXPORT_SYMBOL(errno);
@@ -206,7 +207,7 @@ void __noreturn panic(const char *fmt, ...)
hang();
} else {
udelay(100000); /* allow messages to go out */
- reset_cpu(0);
+ restart_machine();
}
}
EXPORT_SYMBOL(panic);
diff --git a/common/reset_source.c b/common/reset_source.c
index 80002a93e6..0a69f90a6e 100644
--- a/common/reset_source.c
+++ b/common/reset_source.c
@@ -11,6 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "reset-source: " fmt
#include <common.h>
#include <init.h>
@@ -30,6 +31,7 @@ static const char * const reset_src_names[] = {
};
static enum reset_src_type reset_source;
+static unsigned int reset_source_priority;
enum reset_src_type reset_source_get(void)
{
@@ -37,20 +39,41 @@ enum reset_src_type reset_source_get(void)
}
EXPORT_SYMBOL(reset_source_get);
-void reset_source_set(enum reset_src_type st)
+void reset_source_set_priority(enum reset_src_type st, unsigned int priority)
{
+ if (priority <= reset_source_priority)
+ return;
+
reset_source = st;
+ reset_source_priority = priority;
- globalvar_add_simple("system.reset", reset_src_names[reset_source]);
+ pr_debug("Setting reset source to %s with priority %d\n",
+ reset_src_names[reset_source], priority);
}
EXPORT_SYMBOL(reset_source_set);
-/* ensure this runs after the 'global' device is already registerd */
static int reset_source_init(void)
{
- reset_source_set(reset_source);
+ globalvar_add_simple_enum("system.reset", (unsigned int *)&reset_source,
+ reset_src_names, ARRAY_SIZE(reset_src_names));
return 0;
}
coredevice_initcall(reset_source_init);
+
+/**
+ * of_get_reset_source_priority() - get the desired reset source priority from
+ * device tree
+ * @node: The device_node to read the property from
+ *
+ * return: The priority
+ */
+unsigned int of_get_reset_source_priority(struct device_node *node)
+{
+ unsigned int priority = RESET_SOURCE_DEFAULT_PRIORITY;
+
+ of_property_read_u32(node, "reset-source-priority", &priority);
+
+ return priority;
+}
diff --git a/common/restart.c b/common/restart.c
new file mode 100644
index 0000000000..8fd5ffd1a2
--- /dev/null
+++ b/common/restart.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#define pr_fmt(fmt) "restart: " fmt
+
+#include <common.h>
+#include <restart.h>
+#include <malloc.h>
+#include <of.h>
+
+static LIST_HEAD(restart_handler_list);
+
+/**
+ * restart_handler_register() - register a handler for restarting the system
+ * @rst: The handler struct
+ *
+ * This adds @rst to the list of registered restart handlers.
+ *
+ * return: 0 for success or negative error code
+ */
+int restart_handler_register(struct restart_handler *rst)
+{
+ if (!rst->name)
+ rst->name = RESTART_DEFAULT_NAME;
+ if (!rst->priority)
+ rst->priority = RESTART_DEFAULT_PRIORITY;
+
+ list_add_tail(&rst->list, &restart_handler_list);
+
+ pr_debug("registering restart handler \"%s\" with priority %d\n",
+ rst->name, rst->priority);
+
+ return 0;
+}
+
+/**
+ * restart_handler_register_fn() - register a handler function
+ * @restart_fn: The restart function
+ *
+ * convenience wrapper for restart_handler_register() to register a handler
+ * with given function and default values otherwise.
+ *
+ * return: 0 for success or negative error code
+ */
+int restart_handler_register_fn(void (*restart_fn)(struct restart_handler *))
+{
+ struct restart_handler *rst;
+ int ret;
+
+ rst = xzalloc(sizeof(*rst));
+
+ rst->restart = restart_fn;
+
+ ret = restart_handler_register(rst);
+
+ if (ret)
+ free(rst);
+
+ return ret;
+}
+
+/**
+ * restart_machine() - reset the whole system
+ */
+void __noreturn restart_machine(void)
+{
+ struct restart_handler *rst = NULL, *tmp;
+ unsigned int priority = 0;
+
+ list_for_each_entry(tmp, &restart_handler_list, list) {
+ if (tmp->priority > priority) {
+ priority = tmp->priority;
+ rst = tmp;
+ }
+ }
+
+ if (rst) {
+ pr_debug("%s: using restart handler %s\n", __func__, rst->name);
+ console_flush();
+ rst->restart(rst);
+ }
+
+ hang();
+}
+
+/**
+ * of_get_restart_priority() - get the desired restart priority from device tree
+ * @node: The device_node to read the property from
+ *
+ * return: The priority
+ */
+unsigned int of_get_restart_priority(struct device_node *node)
+{
+ unsigned int priority = RESTART_DEFAULT_PRIORITY;
+
+ of_property_read_u32(node, "restart-priority", &priority);
+
+ return priority;
+}