This replaces the reset_cpu() function which every SoC or board must provide with registered handlers. This makes it possible to have multiple reset functions for boards which have multiple ways to reset the machine. Also boards which have no way at all to reset the machine no longer have to provide a dummy reset_cpu() function. The problem this solves is that some machines have external PMICs or similar to reset the system which have to be preferred over the internal SoC reset, because the PMIC can reset not only the SoC but also the external devices. To pick the right way to reset a machine each handler has a priority. The default priority is 100 and all currently existing restart handlers are registered with this priority. of_get_restart_priority() allows to retrieve the priority from the device tree which makes it possible for boards to give certain restart handlers a higher priority in order to use this one instead of the default one. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
113 lines
2.6 KiB
C
113 lines
2.6 KiB
C
/*
|
|
* 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;
|
|
}
|