summaryrefslogtreecommitdiffstats
path: root/common/restart.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/restart.c')
-rw-r--r--common/restart.c112
1 files changed, 112 insertions, 0 deletions
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;
+}