Commit b63adb979583ef185718d774d8162387db5589c0

Authored by Guenter Roeck
1 parent 52addcf9d6

kernel: add support for kernel restart handler call chain

Various drivers implement architecture and/or device specific means to
restart (reset) the system.  Various mechanisms have been implemented to
support those schemes.  The best known mechanism is arm_pm_restart, which
is a function pointer to be set either from platform specific code or from
drivers.  Another mechanism is to use hardware watchdogs to issue a reset;
this mechanism is used if there is no other method available to reset a
board or system.  Two examples are alim7101_wdt, which currently uses the
reboot notifier to trigger a reset, and moxart_wdt, which registers the
arm_pm_restart function.

The existing mechanisms have a number of drawbacks.  Typically only one
scheme to restart the system is supported (at least if arm_pm_restart is
used).  At least in theory there can be multiple means to restart the
system, some of which may be less desirable (for example one mechanism may
only reset the CPU, while another may reset the entire system).  Using
arm_pm_restart can also be racy if the function pointer is set from a
driver, as the driver may be in the process of being unloaded when
arm_pm_restart is called.  Using the reboot notifier is always racy, as it
is unknown if and when other functions using the reboot notifier have
completed execution by the time the watchdog fires.

Introduce a system restart handler call chain to solve the described
problems.  This call chain is expected to be executed from the
architecture specific machine_restart() function.  Drivers providing
system restart functionality (such as the watchdog drivers mentioned
above) are expected to register with this call chain.  By using the
priority field in the notifier block, callers can control restart handler
execution sequence and thus ensure that the restart handler with the
optimal restart capabilities for a given system is called first.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Wim Van Sebroeck <wim@iguana.be>
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Jonas Jensen <jonas.jensen@gmail.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

Showing 2 changed files with 84 additions and 0 deletions Side-by-side Diff

include/linux/reboot.h
... ... @@ -38,6 +38,9 @@
38 38 extern int register_reboot_notifier(struct notifier_block *);
39 39 extern int unregister_reboot_notifier(struct notifier_block *);
40 40  
  41 +extern int register_restart_handler(struct notifier_block *);
  42 +extern int unregister_restart_handler(struct notifier_block *);
  43 +extern void do_kernel_restart(char *cmd);
41 44  
42 45 /*
43 46 * Architecture-specific implementations of sys_reboot commands.
... ... @@ -104,6 +104,87 @@
104 104 }
105 105 EXPORT_SYMBOL(unregister_reboot_notifier);
106 106  
  107 +/*
  108 + * Notifier list for kernel code which wants to be called
  109 + * to restart the system.
  110 + */
  111 +static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
  112 +
  113 +/**
  114 + * register_restart_handler - Register function to be called to reset
  115 + * the system
  116 + * @nb: Info about handler function to be called
  117 + * @nb->priority: Handler priority. Handlers should follow the
  118 + * following guidelines for setting priorities.
  119 + * 0: Restart handler of last resort,
  120 + * with limited restart capabilities
  121 + * 128: Default restart handler; use if no other
  122 + * restart handler is expected to be available,
  123 + * and/or if restart functionality is
  124 + * sufficient to restart the entire system
  125 + * 255: Highest priority restart handler, will
  126 + * preempt all other restart handlers
  127 + *
  128 + * Registers a function with code to be called to restart the
  129 + * system.
  130 + *
  131 + * Registered functions will be called from machine_restart as last
  132 + * step of the restart sequence (if the architecture specific
  133 + * machine_restart function calls do_kernel_restart - see below
  134 + * for details).
  135 + * Registered functions are expected to restart the system immediately.
  136 + * If more than one function is registered, the restart handler priority
  137 + * selects which function will be called first.
  138 + *
  139 + * Restart handlers are expected to be registered from non-architecture
  140 + * code, typically from drivers. A typical use case would be a system
  141 + * where restart functionality is provided through a watchdog. Multiple
  142 + * restart handlers may exist; for example, one restart handler might
  143 + * restart the entire system, while another only restarts the CPU.
  144 + * In such cases, the restart handler which only restarts part of the
  145 + * hardware is expected to register with low priority to ensure that
  146 + * it only runs if no other means to restart the system is available.
  147 + *
  148 + * Currently always returns zero, as atomic_notifier_chain_register()
  149 + * always returns zero.
  150 + */
  151 +int register_restart_handler(struct notifier_block *nb)
  152 +{
  153 + return atomic_notifier_chain_register(&restart_handler_list, nb);
  154 +}
  155 +EXPORT_SYMBOL(register_restart_handler);
  156 +
  157 +/**
  158 + * unregister_restart_handler - Unregister previously registered
  159 + * restart handler
  160 + * @nb: Hook to be unregistered
  161 + *
  162 + * Unregisters a previously registered restart handler function.
  163 + *
  164 + * Returns zero on success, or %-ENOENT on failure.
  165 + */
  166 +int unregister_restart_handler(struct notifier_block *nb)
  167 +{
  168 + return atomic_notifier_chain_unregister(&restart_handler_list, nb);
  169 +}
  170 +EXPORT_SYMBOL(unregister_restart_handler);
  171 +
  172 +/**
  173 + * do_kernel_restart - Execute kernel restart handler call chain
  174 + *
  175 + * Calls functions registered with register_restart_handler.
  176 + *
  177 + * Expected to be called from machine_restart as last step of the restart
  178 + * sequence.
  179 + *
  180 + * Restarts the system immediately if a restart handler function has been
  181 + * registered. Otherwise does nothing.
  182 + */
  183 +void do_kernel_restart(char *cmd)
  184 +{
  185 + atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);
  186 +}
  187 +
107 188 void migrate_to_reboot_cpu(void)
108 189 {
109 190 /* The boot cpu is always logical cpu 0 */