xref: /linux-6.15/kernel/reboot.c (revision e016173f)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
215d94b82SRobin Holt /*
315d94b82SRobin Holt  *  linux/kernel/reboot.c
415d94b82SRobin Holt  *
515d94b82SRobin Holt  *  Copyright (C) 2013  Linus Torvalds
615d94b82SRobin Holt  */
715d94b82SRobin Holt 
8972ee83dSRobin Holt #define pr_fmt(fmt)	"reboot: " fmt
9972ee83dSRobin Holt 
10dfa19b11SMatti Vaittinen #include <linux/atomic.h>
111b3a5d02SRobin Holt #include <linux/ctype.h>
1215d94b82SRobin Holt #include <linux/export.h>
1315d94b82SRobin Holt #include <linux/kexec.h>
1415d94b82SRobin Holt #include <linux/kmod.h>
1515d94b82SRobin Holt #include <linux/kmsg_dump.h>
1615d94b82SRobin Holt #include <linux/reboot.h>
1715d94b82SRobin Holt #include <linux/suspend.h>
1815d94b82SRobin Holt #include <linux/syscalls.h>
1915d94b82SRobin Holt #include <linux/syscore_ops.h>
2015d94b82SRobin Holt #include <linux/uaccess.h>
2115d94b82SRobin Holt 
2215d94b82SRobin Holt /*
2315d94b82SRobin Holt  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
2415d94b82SRobin Holt  */
2515d94b82SRobin Holt 
2606d17766Stangmeng static int C_A_D = 1;
2715d94b82SRobin Holt struct pid *cad_pid;
2815d94b82SRobin Holt EXPORT_SYMBOL(cad_pid);
2915d94b82SRobin Holt 
30fb37409aSMike Rapoport #if defined(CONFIG_ARM)
311b3a5d02SRobin Holt #define DEFAULT_REBOOT_MODE		= REBOOT_HARD
321b3a5d02SRobin Holt #else
331b3a5d02SRobin Holt #define DEFAULT_REBOOT_MODE
341b3a5d02SRobin Holt #endif
351b3a5d02SRobin Holt enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
36d46b3f5bSShawn Guo EXPORT_SYMBOL_GPL(reboot_mode);
37b287a25aSAaro Koskinen enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED;
381b3a5d02SRobin Holt 
39*e016173fSAhmad Fatoum static enum hw_protection_action hw_protection_action = HWPROT_ACT_SHUTDOWN;
40*e016173fSAhmad Fatoum 
41e2f0b88eSChuansheng Liu /*
42e2f0b88eSChuansheng Liu  * This variable is used privately to keep track of whether or not
43e2f0b88eSChuansheng Liu  * reboot_type is still set to its default value (i.e., reboot= hasn't
44e2f0b88eSChuansheng Liu  * been set on the command line).  This is needed so that we can
45e2f0b88eSChuansheng Liu  * suppress DMI scanning for reboot quirks.  Without it, it's
46e2f0b88eSChuansheng Liu  * impossible to override a faulty reboot quirk without recompiling.
47e2f0b88eSChuansheng Liu  */
48e2f0b88eSChuansheng Liu int reboot_default = 1;
491b3a5d02SRobin Holt int reboot_cpu;
501b3a5d02SRobin Holt enum reboot_type reboot_type = BOOT_ACPI;
511b3a5d02SRobin Holt int reboot_force;
521b3a5d02SRobin Holt 
53232edc2fSDmitry Osipenko struct sys_off_handler {
54232edc2fSDmitry Osipenko 	struct notifier_block nb;
55232edc2fSDmitry Osipenko 	int (*sys_off_cb)(struct sys_off_data *data);
56232edc2fSDmitry Osipenko 	void *cb_data;
57232edc2fSDmitry Osipenko 	enum sys_off_mode mode;
58232edc2fSDmitry Osipenko 	bool blocking;
59232edc2fSDmitry Osipenko 	void *list;
60db2d6038SBenjamin Bara 	struct device *dev;
61232edc2fSDmitry Osipenko };
6215d94b82SRobin Holt 
6315d94b82SRobin Holt /*
64a9a1d6adSDongmin Lee  * This variable is used to indicate if a halt was initiated instead of a
65a9a1d6adSDongmin Lee  * reboot when the reboot call was invoked with LINUX_REBOOT_CMD_POWER_OFF, but
66a9a1d6adSDongmin Lee  * the system cannot be powered off. This allowes kernel_halt() to notify users
67a9a1d6adSDongmin Lee  * of that.
68a9a1d6adSDongmin Lee  */
69a9a1d6adSDongmin Lee static bool poweroff_fallback_to_halt;
70a9a1d6adSDongmin Lee 
71a9a1d6adSDongmin Lee /*
725d34b41aSDmitry Osipenko  * Temporary stub that prevents linkage failure while we're in process
735d34b41aSDmitry Osipenko  * of removing all uses of legacy pm_power_off() around the kernel.
745d34b41aSDmitry Osipenko  */
755d34b41aSDmitry Osipenko void __weak (*pm_power_off)(void);
7615d94b82SRobin Holt 
77f2fa0fd4SThomas Weißschuh /*
78f2fa0fd4SThomas Weißschuh  *	Notifier list for kernel code which wants to be called
79f2fa0fd4SThomas Weißschuh  *	at shutdown. This is used to stop any idling DMA operations
80f2fa0fd4SThomas Weißschuh  *	and the like.
81f2fa0fd4SThomas Weißschuh  */
82f2fa0fd4SThomas Weißschuh static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
83f2fa0fd4SThomas Weißschuh 
8415d94b82SRobin Holt /**
8515d94b82SRobin Holt  *	emergency_restart - reboot the system
8615d94b82SRobin Holt  *
8715d94b82SRobin Holt  *	Without shutting down any hardware or taking any locks
8815d94b82SRobin Holt  *	reboot the system.  This is called when we know we are in
8915d94b82SRobin Holt  *	trouble so this is our best effort to reboot.  This is
9015d94b82SRobin Holt  *	safe to call in interrupt context.
9115d94b82SRobin Holt  */
emergency_restart(void)9215d94b82SRobin Holt void emergency_restart(void)
9315d94b82SRobin Holt {
9415d94b82SRobin Holt 	kmsg_dump(KMSG_DUMP_EMERG);
9560466c06SBenjamin Bara 	system_state = SYSTEM_RESTART;
9615d94b82SRobin Holt 	machine_emergency_restart();
9715d94b82SRobin Holt }
9815d94b82SRobin Holt EXPORT_SYMBOL_GPL(emergency_restart);
9915d94b82SRobin Holt 
kernel_restart_prepare(char * cmd)10015d94b82SRobin Holt void kernel_restart_prepare(char *cmd)
10115d94b82SRobin Holt {
10215d94b82SRobin Holt 	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
10315d94b82SRobin Holt 	system_state = SYSTEM_RESTART;
10415d94b82SRobin Holt 	usermodehelper_disable();
10515d94b82SRobin Holt 	device_shutdown();
10615d94b82SRobin Holt }
10715d94b82SRobin Holt 
10815d94b82SRobin Holt /**
10915d94b82SRobin Holt  *	register_reboot_notifier - Register function to be called at reboot time
11015d94b82SRobin Holt  *	@nb: Info about notifier function to be called
11115d94b82SRobin Holt  *
11215d94b82SRobin Holt  *	Registers a function with the list of functions
11315d94b82SRobin Holt  *	to be called at reboot time.
11415d94b82SRobin Holt  *
11515d94b82SRobin Holt  *	Currently always returns zero, as blocking_notifier_chain_register()
11615d94b82SRobin Holt  *	always returns zero.
11715d94b82SRobin Holt  */
register_reboot_notifier(struct notifier_block * nb)11815d94b82SRobin Holt int register_reboot_notifier(struct notifier_block *nb)
11915d94b82SRobin Holt {
12015d94b82SRobin Holt 	return blocking_notifier_chain_register(&reboot_notifier_list, nb);
12115d94b82SRobin Holt }
12215d94b82SRobin Holt EXPORT_SYMBOL(register_reboot_notifier);
12315d94b82SRobin Holt 
12415d94b82SRobin Holt /**
12515d94b82SRobin Holt  *	unregister_reboot_notifier - Unregister previously registered reboot notifier
12615d94b82SRobin Holt  *	@nb: Hook to be unregistered
12715d94b82SRobin Holt  *
12815d94b82SRobin Holt  *	Unregisters a previously registered reboot
12915d94b82SRobin Holt  *	notifier function.
13015d94b82SRobin Holt  *
13115d94b82SRobin Holt  *	Returns zero on success, or %-ENOENT on failure.
13215d94b82SRobin Holt  */
unregister_reboot_notifier(struct notifier_block * nb)13315d94b82SRobin Holt int unregister_reboot_notifier(struct notifier_block *nb)
13415d94b82SRobin Holt {
13515d94b82SRobin Holt 	return blocking_notifier_chain_unregister(&reboot_notifier_list, nb);
13615d94b82SRobin Holt }
13715d94b82SRobin Holt EXPORT_SYMBOL(unregister_reboot_notifier);
13815d94b82SRobin Holt 
devm_unregister_reboot_notifier(struct device * dev,void * res)1392d8364baSAndrey Smirnov static void devm_unregister_reboot_notifier(struct device *dev, void *res)
1402d8364baSAndrey Smirnov {
1412d8364baSAndrey Smirnov 	WARN_ON(unregister_reboot_notifier(*(struct notifier_block **)res));
1422d8364baSAndrey Smirnov }
1432d8364baSAndrey Smirnov 
devm_register_reboot_notifier(struct device * dev,struct notifier_block * nb)1442d8364baSAndrey Smirnov int devm_register_reboot_notifier(struct device *dev, struct notifier_block *nb)
1452d8364baSAndrey Smirnov {
1462d8364baSAndrey Smirnov 	struct notifier_block **rcnb;
1472d8364baSAndrey Smirnov 	int ret;
1482d8364baSAndrey Smirnov 
1492d8364baSAndrey Smirnov 	rcnb = devres_alloc(devm_unregister_reboot_notifier,
1502d8364baSAndrey Smirnov 			    sizeof(*rcnb), GFP_KERNEL);
1512d8364baSAndrey Smirnov 	if (!rcnb)
1522d8364baSAndrey Smirnov 		return -ENOMEM;
1532d8364baSAndrey Smirnov 
1542d8364baSAndrey Smirnov 	ret = register_reboot_notifier(nb);
1552d8364baSAndrey Smirnov 	if (!ret) {
1562d8364baSAndrey Smirnov 		*rcnb = nb;
1572d8364baSAndrey Smirnov 		devres_add(dev, rcnb);
1582d8364baSAndrey Smirnov 	} else {
1592d8364baSAndrey Smirnov 		devres_free(rcnb);
1602d8364baSAndrey Smirnov 	}
1612d8364baSAndrey Smirnov 
1622d8364baSAndrey Smirnov 	return ret;
1632d8364baSAndrey Smirnov }
1642d8364baSAndrey Smirnov EXPORT_SYMBOL(devm_register_reboot_notifier);
1652d8364baSAndrey Smirnov 
166b63adb97SGuenter Roeck /*
167b63adb97SGuenter Roeck  *	Notifier list for kernel code which wants to be called
168b63adb97SGuenter Roeck  *	to restart the system.
169b63adb97SGuenter Roeck  */
170b63adb97SGuenter Roeck static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
171b63adb97SGuenter Roeck 
172b63adb97SGuenter Roeck /**
173b63adb97SGuenter Roeck  *	register_restart_handler - Register function to be called to reset
174b63adb97SGuenter Roeck  *				   the system
175b63adb97SGuenter Roeck  *	@nb: Info about handler function to be called
176b63adb97SGuenter Roeck  *	@nb->priority:	Handler priority. Handlers should follow the
177b63adb97SGuenter Roeck  *			following guidelines for setting priorities.
178b63adb97SGuenter Roeck  *			0:	Restart handler of last resort,
179b63adb97SGuenter Roeck  *				with limited restart capabilities
180b63adb97SGuenter Roeck  *			128:	Default restart handler; use if no other
181b63adb97SGuenter Roeck  *				restart handler is expected to be available,
182b63adb97SGuenter Roeck  *				and/or if restart functionality is
183b63adb97SGuenter Roeck  *				sufficient to restart the entire system
184b63adb97SGuenter Roeck  *			255:	Highest priority restart handler, will
185b63adb97SGuenter Roeck  *				preempt all other restart handlers
186b63adb97SGuenter Roeck  *
187b63adb97SGuenter Roeck  *	Registers a function with code to be called to restart the
188b63adb97SGuenter Roeck  *	system.
189b63adb97SGuenter Roeck  *
190b63adb97SGuenter Roeck  *	Registered functions will be called from machine_restart as last
191b63adb97SGuenter Roeck  *	step of the restart sequence (if the architecture specific
192b63adb97SGuenter Roeck  *	machine_restart function calls do_kernel_restart - see below
193b63adb97SGuenter Roeck  *	for details).
194b63adb97SGuenter Roeck  *	Registered functions are expected to restart the system immediately.
195b63adb97SGuenter Roeck  *	If more than one function is registered, the restart handler priority
196b63adb97SGuenter Roeck  *	selects which function will be called first.
197b63adb97SGuenter Roeck  *
198b63adb97SGuenter Roeck  *	Restart handlers are expected to be registered from non-architecture
199b63adb97SGuenter Roeck  *	code, typically from drivers. A typical use case would be a system
200b63adb97SGuenter Roeck  *	where restart functionality is provided through a watchdog. Multiple
201b63adb97SGuenter Roeck  *	restart handlers may exist; for example, one restart handler might
202b63adb97SGuenter Roeck  *	restart the entire system, while another only restarts the CPU.
203b63adb97SGuenter Roeck  *	In such cases, the restart handler which only restarts part of the
204b63adb97SGuenter Roeck  *	hardware is expected to register with low priority to ensure that
205b63adb97SGuenter Roeck  *	it only runs if no other means to restart the system is available.
206b63adb97SGuenter Roeck  *
207b63adb97SGuenter Roeck  *	Currently always returns zero, as atomic_notifier_chain_register()
208b63adb97SGuenter Roeck  *	always returns zero.
209b63adb97SGuenter Roeck  */
register_restart_handler(struct notifier_block * nb)210b63adb97SGuenter Roeck int register_restart_handler(struct notifier_block *nb)
211b63adb97SGuenter Roeck {
212b63adb97SGuenter Roeck 	return atomic_notifier_chain_register(&restart_handler_list, nb);
213b63adb97SGuenter Roeck }
214b63adb97SGuenter Roeck EXPORT_SYMBOL(register_restart_handler);
215b63adb97SGuenter Roeck 
216b63adb97SGuenter Roeck /**
217b63adb97SGuenter Roeck  *	unregister_restart_handler - Unregister previously registered
218b63adb97SGuenter Roeck  *				     restart handler
219b63adb97SGuenter Roeck  *	@nb: Hook to be unregistered
220b63adb97SGuenter Roeck  *
221b63adb97SGuenter Roeck  *	Unregisters a previously registered restart handler function.
222b63adb97SGuenter Roeck  *
223b63adb97SGuenter Roeck  *	Returns zero on success, or %-ENOENT on failure.
224b63adb97SGuenter Roeck  */
unregister_restart_handler(struct notifier_block * nb)225b63adb97SGuenter Roeck int unregister_restart_handler(struct notifier_block *nb)
226b63adb97SGuenter Roeck {
227b63adb97SGuenter Roeck 	return atomic_notifier_chain_unregister(&restart_handler_list, nb);
228b63adb97SGuenter Roeck }
229b63adb97SGuenter Roeck EXPORT_SYMBOL(unregister_restart_handler);
230b63adb97SGuenter Roeck 
231b63adb97SGuenter Roeck /**
232b63adb97SGuenter Roeck  *	do_kernel_restart - Execute kernel restart handler call chain
233b63adb97SGuenter Roeck  *
234aafb1245SAhmad Fatoum  *	@cmd: pointer to buffer containing command to execute for restart
235aafb1245SAhmad Fatoum  *		or %NULL
236aafb1245SAhmad Fatoum  *
237b63adb97SGuenter Roeck  *	Calls functions registered with register_restart_handler.
238b63adb97SGuenter Roeck  *
239b63adb97SGuenter Roeck  *	Expected to be called from machine_restart as last step of the restart
240b63adb97SGuenter Roeck  *	sequence.
241b63adb97SGuenter Roeck  *
242b63adb97SGuenter Roeck  *	Restarts the system immediately if a restart handler function has been
243b63adb97SGuenter Roeck  *	registered. Otherwise does nothing.
244b63adb97SGuenter Roeck  */
do_kernel_restart(char * cmd)245b63adb97SGuenter Roeck void do_kernel_restart(char *cmd)
246b63adb97SGuenter Roeck {
247b63adb97SGuenter Roeck 	atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);
248b63adb97SGuenter Roeck }
249b63adb97SGuenter Roeck 
migrate_to_reboot_cpu(void)250c97102baSVivek Goyal void migrate_to_reboot_cpu(void)
25115d94b82SRobin Holt {
25215d94b82SRobin Holt 	/* The boot cpu is always logical cpu 0 */
2531b3a5d02SRobin Holt 	int cpu = reboot_cpu;
25415d94b82SRobin Holt 
25515d94b82SRobin Holt 	cpu_hotplug_disable();
25615d94b82SRobin Holt 
25715d94b82SRobin Holt 	/* Make certain the cpu I'm about to reboot on is online */
25815d94b82SRobin Holt 	if (!cpu_online(cpu))
25915d94b82SRobin Holt 		cpu = cpumask_first(cpu_online_mask);
26015d94b82SRobin Holt 
26115d94b82SRobin Holt 	/* Prevent races with other tasks migrating this task */
26215d94b82SRobin Holt 	current->flags |= PF_NO_SETAFFINITY;
26315d94b82SRobin Holt 
26415d94b82SRobin Holt 	/* Make certain I only run on the appropriate processor */
26515d94b82SRobin Holt 	set_cpus_allowed_ptr(current, cpumask_of(cpu));
26615d94b82SRobin Holt }
26715d94b82SRobin Holt 
268e7fd8b68SKai-Heng Feng /*
269e7fd8b68SKai-Heng Feng  *	Notifier list for kernel code which wants to be called
270e7fd8b68SKai-Heng Feng  *	to prepare system for restart.
271e7fd8b68SKai-Heng Feng  */
272e7fd8b68SKai-Heng Feng static BLOCKING_NOTIFIER_HEAD(restart_prep_handler_list);
273e7fd8b68SKai-Heng Feng 
do_kernel_restart_prepare(void)274e7fd8b68SKai-Heng Feng static void do_kernel_restart_prepare(void)
275e7fd8b68SKai-Heng Feng {
276e7fd8b68SKai-Heng Feng 	blocking_notifier_call_chain(&restart_prep_handler_list, 0, NULL);
277e7fd8b68SKai-Heng Feng }
278e7fd8b68SKai-Heng Feng 
27915d94b82SRobin Holt /**
28015d94b82SRobin Holt  *	kernel_restart - reboot the system
28115d94b82SRobin Holt  *	@cmd: pointer to buffer containing command to execute for restart
28215d94b82SRobin Holt  *		or %NULL
28315d94b82SRobin Holt  *
28415d94b82SRobin Holt  *	Shutdown everything and perform a clean reboot.
28515d94b82SRobin Holt  *	This is not safe to call in interrupt context.
28615d94b82SRobin Holt  */
kernel_restart(char * cmd)28715d94b82SRobin Holt void kernel_restart(char *cmd)
28815d94b82SRobin Holt {
28915d94b82SRobin Holt 	kernel_restart_prepare(cmd);
290e7fd8b68SKai-Heng Feng 	do_kernel_restart_prepare();
29115d94b82SRobin Holt 	migrate_to_reboot_cpu();
29215d94b82SRobin Holt 	syscore_shutdown();
29315d94b82SRobin Holt 	if (!cmd)
294972ee83dSRobin Holt 		pr_emerg("Restarting system\n");
29515d94b82SRobin Holt 	else
296972ee83dSRobin Holt 		pr_emerg("Restarting system with command '%s'\n", cmd);
2976d3cf962SKees Cook 	kmsg_dump(KMSG_DUMP_SHUTDOWN);
29815d94b82SRobin Holt 	machine_restart(cmd);
29915d94b82SRobin Holt }
30015d94b82SRobin Holt EXPORT_SYMBOL_GPL(kernel_restart);
30115d94b82SRobin Holt 
kernel_shutdown_prepare(enum system_states state)30215d94b82SRobin Holt static void kernel_shutdown_prepare(enum system_states state)
30315d94b82SRobin Holt {
30415d94b82SRobin Holt 	blocking_notifier_call_chain(&reboot_notifier_list,
30515d94b82SRobin Holt 		(state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);
30615d94b82SRobin Holt 	system_state = state;
30715d94b82SRobin Holt 	usermodehelper_disable();
30815d94b82SRobin Holt 	device_shutdown();
30915d94b82SRobin Holt }
31015d94b82SRobin Holt /**
31115d94b82SRobin Holt  *	kernel_halt - halt the system
31215d94b82SRobin Holt  *
31315d94b82SRobin Holt  *	Shutdown everything and perform a clean system halt.
31415d94b82SRobin Holt  */
kernel_halt(void)31515d94b82SRobin Holt void kernel_halt(void)
31615d94b82SRobin Holt {
31715d94b82SRobin Holt 	kernel_shutdown_prepare(SYSTEM_HALT);
31815d94b82SRobin Holt 	migrate_to_reboot_cpu();
31915d94b82SRobin Holt 	syscore_shutdown();
320a9a1d6adSDongmin Lee 	if (poweroff_fallback_to_halt)
321a9a1d6adSDongmin Lee 		pr_emerg("Power off not available: System halted instead\n");
322a9a1d6adSDongmin Lee 	else
323972ee83dSRobin Holt 		pr_emerg("System halted\n");
3246d3cf962SKees Cook 	kmsg_dump(KMSG_DUMP_SHUTDOWN);
32515d94b82SRobin Holt 	machine_halt();
32615d94b82SRobin Holt }
32715d94b82SRobin Holt EXPORT_SYMBOL_GPL(kernel_halt);
32815d94b82SRobin Holt 
329232edc2fSDmitry Osipenko /*
330232edc2fSDmitry Osipenko  *	Notifier list for kernel code which wants to be called
331232edc2fSDmitry Osipenko  *	to prepare system for power off.
332232edc2fSDmitry Osipenko  */
333232edc2fSDmitry Osipenko static BLOCKING_NOTIFIER_HEAD(power_off_prep_handler_list);
334232edc2fSDmitry Osipenko 
335232edc2fSDmitry Osipenko /*
336232edc2fSDmitry Osipenko  *	Notifier list for kernel code which wants to be called
337232edc2fSDmitry Osipenko  *	to power off system.
338232edc2fSDmitry Osipenko  */
339232edc2fSDmitry Osipenko static ATOMIC_NOTIFIER_HEAD(power_off_handler_list);
340232edc2fSDmitry Osipenko 
sys_off_notify(struct notifier_block * nb,unsigned long mode,void * cmd)341232edc2fSDmitry Osipenko static int sys_off_notify(struct notifier_block *nb,
342232edc2fSDmitry Osipenko 			  unsigned long mode, void *cmd)
343232edc2fSDmitry Osipenko {
344232edc2fSDmitry Osipenko 	struct sys_off_handler *handler;
345232edc2fSDmitry Osipenko 	struct sys_off_data data = {};
346232edc2fSDmitry Osipenko 
347232edc2fSDmitry Osipenko 	handler = container_of(nb, struct sys_off_handler, nb);
348232edc2fSDmitry Osipenko 	data.cb_data = handler->cb_data;
349232edc2fSDmitry Osipenko 	data.mode = mode;
350232edc2fSDmitry Osipenko 	data.cmd = cmd;
351db2d6038SBenjamin Bara 	data.dev = handler->dev;
352232edc2fSDmitry Osipenko 
353232edc2fSDmitry Osipenko 	return handler->sys_off_cb(&data);
354232edc2fSDmitry Osipenko }
355232edc2fSDmitry Osipenko 
356587b9bfeSDmitry Osipenko static struct sys_off_handler platform_sys_off_handler;
357587b9bfeSDmitry Osipenko 
alloc_sys_off_handler(int priority)358587b9bfeSDmitry Osipenko static struct sys_off_handler *alloc_sys_off_handler(int priority)
359587b9bfeSDmitry Osipenko {
360587b9bfeSDmitry Osipenko 	struct sys_off_handler *handler;
3612b8c612cSDmitry Osipenko 	gfp_t flags;
362587b9bfeSDmitry Osipenko 
363587b9bfeSDmitry Osipenko 	/*
364587b9bfeSDmitry Osipenko 	 * Platforms like m68k can't allocate sys_off handler dynamically
365587b9bfeSDmitry Osipenko 	 * at the early boot time because memory allocator isn't available yet.
366587b9bfeSDmitry Osipenko 	 */
367587b9bfeSDmitry Osipenko 	if (priority == SYS_OFF_PRIO_PLATFORM) {
368587b9bfeSDmitry Osipenko 		handler = &platform_sys_off_handler;
369587b9bfeSDmitry Osipenko 		if (handler->cb_data)
370587b9bfeSDmitry Osipenko 			return ERR_PTR(-EBUSY);
371587b9bfeSDmitry Osipenko 	} else {
3722b8c612cSDmitry Osipenko 		if (system_state > SYSTEM_RUNNING)
3732b8c612cSDmitry Osipenko 			flags = GFP_ATOMIC;
3742b8c612cSDmitry Osipenko 		else
3752b8c612cSDmitry Osipenko 			flags = GFP_KERNEL;
3762b8c612cSDmitry Osipenko 
3772b8c612cSDmitry Osipenko 		handler = kzalloc(sizeof(*handler), flags);
378587b9bfeSDmitry Osipenko 		if (!handler)
379587b9bfeSDmitry Osipenko 			return ERR_PTR(-ENOMEM);
380587b9bfeSDmitry Osipenko 	}
381587b9bfeSDmitry Osipenko 
382587b9bfeSDmitry Osipenko 	return handler;
383587b9bfeSDmitry Osipenko }
384587b9bfeSDmitry Osipenko 
free_sys_off_handler(struct sys_off_handler * handler)385587b9bfeSDmitry Osipenko static void free_sys_off_handler(struct sys_off_handler *handler)
386587b9bfeSDmitry Osipenko {
387587b9bfeSDmitry Osipenko 	if (handler == &platform_sys_off_handler)
388587b9bfeSDmitry Osipenko 		memset(handler, 0, sizeof(*handler));
389587b9bfeSDmitry Osipenko 	else
390587b9bfeSDmitry Osipenko 		kfree(handler);
391587b9bfeSDmitry Osipenko }
392587b9bfeSDmitry Osipenko 
393232edc2fSDmitry Osipenko /**
394232edc2fSDmitry Osipenko  *	register_sys_off_handler - Register sys-off handler
395232edc2fSDmitry Osipenko  *	@mode: Sys-off mode
396232edc2fSDmitry Osipenko  *	@priority: Handler priority
397232edc2fSDmitry Osipenko  *	@callback: Callback function
398232edc2fSDmitry Osipenko  *	@cb_data: Callback argument
399232edc2fSDmitry Osipenko  *
400232edc2fSDmitry Osipenko  *	Registers system power-off or restart handler that will be invoked
401232edc2fSDmitry Osipenko  *	at the step corresponding to the given sys-off mode. Handler's callback
402232edc2fSDmitry Osipenko  *	should return NOTIFY_DONE to permit execution of the next handler in
403232edc2fSDmitry Osipenko  *	the call chain or NOTIFY_STOP to break the chain (in error case for
404232edc2fSDmitry Osipenko  *	example).
405232edc2fSDmitry Osipenko  *
406232edc2fSDmitry Osipenko  *	Multiple handlers can be registered at the default priority level.
407232edc2fSDmitry Osipenko  *
408232edc2fSDmitry Osipenko  *	Only one handler can be registered at the non-default priority level,
409232edc2fSDmitry Osipenko  *	otherwise ERR_PTR(-EBUSY) is returned.
410232edc2fSDmitry Osipenko  *
411232edc2fSDmitry Osipenko  *	Returns a new instance of struct sys_off_handler on success, or
412232edc2fSDmitry Osipenko  *	an ERR_PTR()-encoded error code otherwise.
413232edc2fSDmitry Osipenko  */
414232edc2fSDmitry Osipenko struct sys_off_handler *
register_sys_off_handler(enum sys_off_mode mode,int priority,int (* callback)(struct sys_off_data * data),void * cb_data)415232edc2fSDmitry Osipenko register_sys_off_handler(enum sys_off_mode mode,
416232edc2fSDmitry Osipenko 			 int priority,
417232edc2fSDmitry Osipenko 			 int (*callback)(struct sys_off_data *data),
418232edc2fSDmitry Osipenko 			 void *cb_data)
419232edc2fSDmitry Osipenko {
420232edc2fSDmitry Osipenko 	struct sys_off_handler *handler;
421232edc2fSDmitry Osipenko 	int err;
422232edc2fSDmitry Osipenko 
423587b9bfeSDmitry Osipenko 	handler = alloc_sys_off_handler(priority);
424587b9bfeSDmitry Osipenko 	if (IS_ERR(handler))
425587b9bfeSDmitry Osipenko 		return handler;
426232edc2fSDmitry Osipenko 
427232edc2fSDmitry Osipenko 	switch (mode) {
428232edc2fSDmitry Osipenko 	case SYS_OFF_MODE_POWER_OFF_PREPARE:
429232edc2fSDmitry Osipenko 		handler->list = &power_off_prep_handler_list;
430232edc2fSDmitry Osipenko 		handler->blocking = true;
431232edc2fSDmitry Osipenko 		break;
432232edc2fSDmitry Osipenko 
433232edc2fSDmitry Osipenko 	case SYS_OFF_MODE_POWER_OFF:
434232edc2fSDmitry Osipenko 		handler->list = &power_off_handler_list;
435232edc2fSDmitry Osipenko 		break;
436232edc2fSDmitry Osipenko 
437e7fd8b68SKai-Heng Feng 	case SYS_OFF_MODE_RESTART_PREPARE:
438e7fd8b68SKai-Heng Feng 		handler->list = &restart_prep_handler_list;
439e7fd8b68SKai-Heng Feng 		handler->blocking = true;
440e7fd8b68SKai-Heng Feng 		break;
441e7fd8b68SKai-Heng Feng 
442232edc2fSDmitry Osipenko 	case SYS_OFF_MODE_RESTART:
443232edc2fSDmitry Osipenko 		handler->list = &restart_handler_list;
444232edc2fSDmitry Osipenko 		break;
445232edc2fSDmitry Osipenko 
446232edc2fSDmitry Osipenko 	default:
447587b9bfeSDmitry Osipenko 		free_sys_off_handler(handler);
448232edc2fSDmitry Osipenko 		return ERR_PTR(-EINVAL);
449232edc2fSDmitry Osipenko 	}
450232edc2fSDmitry Osipenko 
451232edc2fSDmitry Osipenko 	handler->nb.notifier_call = sys_off_notify;
452232edc2fSDmitry Osipenko 	handler->nb.priority = priority;
453232edc2fSDmitry Osipenko 	handler->sys_off_cb = callback;
454232edc2fSDmitry Osipenko 	handler->cb_data = cb_data;
455232edc2fSDmitry Osipenko 	handler->mode = mode;
456232edc2fSDmitry Osipenko 
457232edc2fSDmitry Osipenko 	if (handler->blocking) {
458232edc2fSDmitry Osipenko 		if (priority == SYS_OFF_PRIO_DEFAULT)
459232edc2fSDmitry Osipenko 			err = blocking_notifier_chain_register(handler->list,
460232edc2fSDmitry Osipenko 							       &handler->nb);
461232edc2fSDmitry Osipenko 		else
462232edc2fSDmitry Osipenko 			err = blocking_notifier_chain_register_unique_prio(handler->list,
463232edc2fSDmitry Osipenko 									   &handler->nb);
464232edc2fSDmitry Osipenko 	} else {
465232edc2fSDmitry Osipenko 		if (priority == SYS_OFF_PRIO_DEFAULT)
466232edc2fSDmitry Osipenko 			err = atomic_notifier_chain_register(handler->list,
467232edc2fSDmitry Osipenko 							     &handler->nb);
468232edc2fSDmitry Osipenko 		else
469232edc2fSDmitry Osipenko 			err = atomic_notifier_chain_register_unique_prio(handler->list,
470232edc2fSDmitry Osipenko 									 &handler->nb);
471232edc2fSDmitry Osipenko 	}
472232edc2fSDmitry Osipenko 
473232edc2fSDmitry Osipenko 	if (err) {
474587b9bfeSDmitry Osipenko 		free_sys_off_handler(handler);
475232edc2fSDmitry Osipenko 		return ERR_PTR(err);
476232edc2fSDmitry Osipenko 	}
477232edc2fSDmitry Osipenko 
478232edc2fSDmitry Osipenko 	return handler;
479232edc2fSDmitry Osipenko }
480232edc2fSDmitry Osipenko EXPORT_SYMBOL_GPL(register_sys_off_handler);
481232edc2fSDmitry Osipenko 
482232edc2fSDmitry Osipenko /**
483232edc2fSDmitry Osipenko  *	unregister_sys_off_handler - Unregister sys-off handler
484232edc2fSDmitry Osipenko  *	@handler: Sys-off handler
485232edc2fSDmitry Osipenko  *
486232edc2fSDmitry Osipenko  *	Unregisters given sys-off handler.
487232edc2fSDmitry Osipenko  */
unregister_sys_off_handler(struct sys_off_handler * handler)488232edc2fSDmitry Osipenko void unregister_sys_off_handler(struct sys_off_handler *handler)
489232edc2fSDmitry Osipenko {
490232edc2fSDmitry Osipenko 	int err;
491232edc2fSDmitry Osipenko 
4922b8c612cSDmitry Osipenko 	if (IS_ERR_OR_NULL(handler))
493232edc2fSDmitry Osipenko 		return;
494232edc2fSDmitry Osipenko 
495232edc2fSDmitry Osipenko 	if (handler->blocking)
496232edc2fSDmitry Osipenko 		err = blocking_notifier_chain_unregister(handler->list,
497232edc2fSDmitry Osipenko 							 &handler->nb);
498232edc2fSDmitry Osipenko 	else
499232edc2fSDmitry Osipenko 		err = atomic_notifier_chain_unregister(handler->list,
500232edc2fSDmitry Osipenko 						       &handler->nb);
501232edc2fSDmitry Osipenko 
502232edc2fSDmitry Osipenko 	/* sanity check, shall never happen */
503232edc2fSDmitry Osipenko 	WARN_ON(err);
504232edc2fSDmitry Osipenko 
505587b9bfeSDmitry Osipenko 	free_sys_off_handler(handler);
506232edc2fSDmitry Osipenko }
507232edc2fSDmitry Osipenko EXPORT_SYMBOL_GPL(unregister_sys_off_handler);
508232edc2fSDmitry Osipenko 
devm_unregister_sys_off_handler(void * data)509232edc2fSDmitry Osipenko static void devm_unregister_sys_off_handler(void *data)
510232edc2fSDmitry Osipenko {
511232edc2fSDmitry Osipenko 	struct sys_off_handler *handler = data;
512232edc2fSDmitry Osipenko 
513232edc2fSDmitry Osipenko 	unregister_sys_off_handler(handler);
514232edc2fSDmitry Osipenko }
515232edc2fSDmitry Osipenko 
516232edc2fSDmitry Osipenko /**
517232edc2fSDmitry Osipenko  *	devm_register_sys_off_handler - Register sys-off handler
518232edc2fSDmitry Osipenko  *	@dev: Device that registers handler
519232edc2fSDmitry Osipenko  *	@mode: Sys-off mode
520232edc2fSDmitry Osipenko  *	@priority: Handler priority
521232edc2fSDmitry Osipenko  *	@callback: Callback function
522232edc2fSDmitry Osipenko  *	@cb_data: Callback argument
523232edc2fSDmitry Osipenko  *
524232edc2fSDmitry Osipenko  *	Registers resource-managed sys-off handler.
525232edc2fSDmitry Osipenko  *
526232edc2fSDmitry Osipenko  *	Returns zero on success, or error code on failure.
527232edc2fSDmitry Osipenko  */
devm_register_sys_off_handler(struct device * dev,enum sys_off_mode mode,int priority,int (* callback)(struct sys_off_data * data),void * cb_data)528232edc2fSDmitry Osipenko int devm_register_sys_off_handler(struct device *dev,
529232edc2fSDmitry Osipenko 				  enum sys_off_mode mode,
530232edc2fSDmitry Osipenko 				  int priority,
531232edc2fSDmitry Osipenko 				  int (*callback)(struct sys_off_data *data),
532232edc2fSDmitry Osipenko 				  void *cb_data)
533232edc2fSDmitry Osipenko {
534232edc2fSDmitry Osipenko 	struct sys_off_handler *handler;
535232edc2fSDmitry Osipenko 
536232edc2fSDmitry Osipenko 	handler = register_sys_off_handler(mode, priority, callback, cb_data);
537232edc2fSDmitry Osipenko 	if (IS_ERR(handler))
538232edc2fSDmitry Osipenko 		return PTR_ERR(handler);
539db2d6038SBenjamin Bara 	handler->dev = dev;
540232edc2fSDmitry Osipenko 
541232edc2fSDmitry Osipenko 	return devm_add_action_or_reset(dev, devm_unregister_sys_off_handler,
542232edc2fSDmitry Osipenko 					handler);
543232edc2fSDmitry Osipenko }
544232edc2fSDmitry Osipenko EXPORT_SYMBOL_GPL(devm_register_sys_off_handler);
545232edc2fSDmitry Osipenko 
546d2c54153SDmitry Osipenko /**
547d2c54153SDmitry Osipenko  *	devm_register_power_off_handler - Register power-off handler
548d2c54153SDmitry Osipenko  *	@dev: Device that registers callback
549d2c54153SDmitry Osipenko  *	@callback: Callback function
550d2c54153SDmitry Osipenko  *	@cb_data: Callback's argument
551d2c54153SDmitry Osipenko  *
552d2c54153SDmitry Osipenko  *	Registers resource-managed sys-off handler with a default priority
553d2c54153SDmitry Osipenko  *	and using power-off mode.
554d2c54153SDmitry Osipenko  *
555d2c54153SDmitry Osipenko  *	Returns zero on success, or error code on failure.
556d2c54153SDmitry Osipenko  */
devm_register_power_off_handler(struct device * dev,int (* callback)(struct sys_off_data * data),void * cb_data)557d2c54153SDmitry Osipenko int devm_register_power_off_handler(struct device *dev,
558d2c54153SDmitry Osipenko 				    int (*callback)(struct sys_off_data *data),
559d2c54153SDmitry Osipenko 				    void *cb_data)
560d2c54153SDmitry Osipenko {
561d2c54153SDmitry Osipenko 	return devm_register_sys_off_handler(dev,
562d2c54153SDmitry Osipenko 					     SYS_OFF_MODE_POWER_OFF,
563d2c54153SDmitry Osipenko 					     SYS_OFF_PRIO_DEFAULT,
564d2c54153SDmitry Osipenko 					     callback, cb_data);
565d2c54153SDmitry Osipenko }
566d2c54153SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_register_power_off_handler);
567d2c54153SDmitry Osipenko 
5686779db97SDmitry Osipenko /**
5696779db97SDmitry Osipenko  *	devm_register_restart_handler - Register restart handler
5706779db97SDmitry Osipenko  *	@dev: Device that registers callback
5716779db97SDmitry Osipenko  *	@callback: Callback function
5726779db97SDmitry Osipenko  *	@cb_data: Callback's argument
5736779db97SDmitry Osipenko  *
5746779db97SDmitry Osipenko  *	Registers resource-managed sys-off handler with a default priority
5756779db97SDmitry Osipenko  *	and using restart mode.
5766779db97SDmitry Osipenko  *
5776779db97SDmitry Osipenko  *	Returns zero on success, or error code on failure.
5786779db97SDmitry Osipenko  */
devm_register_restart_handler(struct device * dev,int (* callback)(struct sys_off_data * data),void * cb_data)5796779db97SDmitry Osipenko int devm_register_restart_handler(struct device *dev,
5806779db97SDmitry Osipenko 				  int (*callback)(struct sys_off_data *data),
5816779db97SDmitry Osipenko 				  void *cb_data)
5826779db97SDmitry Osipenko {
5836779db97SDmitry Osipenko 	return devm_register_sys_off_handler(dev,
5846779db97SDmitry Osipenko 					     SYS_OFF_MODE_RESTART,
5856779db97SDmitry Osipenko 					     SYS_OFF_PRIO_DEFAULT,
5866779db97SDmitry Osipenko 					     callback, cb_data);
5876779db97SDmitry Osipenko }
5886779db97SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_register_restart_handler);
5896779db97SDmitry Osipenko 
590fb61375eSDmitry Osipenko static struct sys_off_handler *platform_power_off_handler;
591fb61375eSDmitry Osipenko 
platform_power_off_notify(struct sys_off_data * data)592fb61375eSDmitry Osipenko static int platform_power_off_notify(struct sys_off_data *data)
593fb61375eSDmitry Osipenko {
594fb61375eSDmitry Osipenko 	void (*platform_power_power_off_cb)(void) = data->cb_data;
595fb61375eSDmitry Osipenko 
596fb61375eSDmitry Osipenko 	platform_power_power_off_cb();
597fb61375eSDmitry Osipenko 
598fb61375eSDmitry Osipenko 	return NOTIFY_DONE;
599fb61375eSDmitry Osipenko }
600fb61375eSDmitry Osipenko 
601fb61375eSDmitry Osipenko /**
602fb61375eSDmitry Osipenko  *	register_platform_power_off - Register platform-level power-off callback
603fb61375eSDmitry Osipenko  *	@power_off: Power-off callback
604fb61375eSDmitry Osipenko  *
605fb61375eSDmitry Osipenko  *	Registers power-off callback that will be called as last step
606fb61375eSDmitry Osipenko  *	of the power-off sequence. This callback is expected to be invoked
607fb61375eSDmitry Osipenko  *	for the last resort. Only one platform power-off callback is allowed
608fb61375eSDmitry Osipenko  *	to be registered at a time.
609fb61375eSDmitry Osipenko  *
610fb61375eSDmitry Osipenko  *	Returns zero on success, or error code on failure.
611fb61375eSDmitry Osipenko  */
register_platform_power_off(void (* power_off)(void))612fb61375eSDmitry Osipenko int register_platform_power_off(void (*power_off)(void))
613fb61375eSDmitry Osipenko {
614fb61375eSDmitry Osipenko 	struct sys_off_handler *handler;
615fb61375eSDmitry Osipenko 
616fb61375eSDmitry Osipenko 	handler = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
617fb61375eSDmitry Osipenko 					   SYS_OFF_PRIO_PLATFORM,
618fb61375eSDmitry Osipenko 					   platform_power_off_notify,
619fb61375eSDmitry Osipenko 					   power_off);
620fb61375eSDmitry Osipenko 	if (IS_ERR(handler))
621fb61375eSDmitry Osipenko 		return PTR_ERR(handler);
622fb61375eSDmitry Osipenko 
623fb61375eSDmitry Osipenko 	platform_power_off_handler = handler;
624fb61375eSDmitry Osipenko 
625fb61375eSDmitry Osipenko 	return 0;
626fb61375eSDmitry Osipenko }
627fb61375eSDmitry Osipenko EXPORT_SYMBOL_GPL(register_platform_power_off);
628fb61375eSDmitry Osipenko 
629fb61375eSDmitry Osipenko /**
630fb61375eSDmitry Osipenko  *	unregister_platform_power_off - Unregister platform-level power-off callback
631fb61375eSDmitry Osipenko  *	@power_off: Power-off callback
632fb61375eSDmitry Osipenko  *
633fb61375eSDmitry Osipenko  *	Unregisters previously registered platform power-off callback.
634fb61375eSDmitry Osipenko  */
unregister_platform_power_off(void (* power_off)(void))635fb61375eSDmitry Osipenko void unregister_platform_power_off(void (*power_off)(void))
636fb61375eSDmitry Osipenko {
637fb61375eSDmitry Osipenko 	if (platform_power_off_handler &&
638fb61375eSDmitry Osipenko 	    platform_power_off_handler->cb_data == power_off) {
639fb61375eSDmitry Osipenko 		unregister_sys_off_handler(platform_power_off_handler);
640fb61375eSDmitry Osipenko 		platform_power_off_handler = NULL;
641fb61375eSDmitry Osipenko 	}
642fb61375eSDmitry Osipenko }
643fb61375eSDmitry Osipenko EXPORT_SYMBOL_GPL(unregister_platform_power_off);
644fb61375eSDmitry Osipenko 
legacy_pm_power_off(struct sys_off_data * data)6457b9a3de9SDmitry Osipenko static int legacy_pm_power_off(struct sys_off_data *data)
6467b9a3de9SDmitry Osipenko {
6477b9a3de9SDmitry Osipenko 	if (pm_power_off)
6487b9a3de9SDmitry Osipenko 		pm_power_off();
6497b9a3de9SDmitry Osipenko 
6507b9a3de9SDmitry Osipenko 	return NOTIFY_DONE;
6517b9a3de9SDmitry Osipenko }
6527b9a3de9SDmitry Osipenko 
do_kernel_power_off_prepare(void)6537b9a3de9SDmitry Osipenko static void do_kernel_power_off_prepare(void)
6547b9a3de9SDmitry Osipenko {
6557b9a3de9SDmitry Osipenko 	blocking_notifier_call_chain(&power_off_prep_handler_list, 0, NULL);
6567b9a3de9SDmitry Osipenko }
6577b9a3de9SDmitry Osipenko 
65815d94b82SRobin Holt /**
6592b6aa733SDmitry Osipenko  *	do_kernel_power_off - Execute kernel power-off handler call chain
6602b6aa733SDmitry Osipenko  *
6612b6aa733SDmitry Osipenko  *	Expected to be called as last step of the power-off sequence.
6622b6aa733SDmitry Osipenko  *
6632b6aa733SDmitry Osipenko  *	Powers off the system immediately if a power-off handler function has
6642b6aa733SDmitry Osipenko  *	been registered. Otherwise does nothing.
6652b6aa733SDmitry Osipenko  */
do_kernel_power_off(void)6662b6aa733SDmitry Osipenko void do_kernel_power_off(void)
6672b6aa733SDmitry Osipenko {
6682b8c612cSDmitry Osipenko 	struct sys_off_handler *sys_off = NULL;
6692b8c612cSDmitry Osipenko 
6702b8c612cSDmitry Osipenko 	/*
6712b8c612cSDmitry Osipenko 	 * Register sys-off handlers for legacy PM callback. This allows
6722b8c612cSDmitry Osipenko 	 * legacy PM callbacks temporary co-exist with the new sys-off API.
6732b8c612cSDmitry Osipenko 	 *
6742b8c612cSDmitry Osipenko 	 * TODO: Remove legacy handlers once all legacy PM users will be
6752b8c612cSDmitry Osipenko 	 *       switched to the sys-off based APIs.
6762b8c612cSDmitry Osipenko 	 */
6772b8c612cSDmitry Osipenko 	if (pm_power_off)
6782b8c612cSDmitry Osipenko 		sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
6792b8c612cSDmitry Osipenko 						   SYS_OFF_PRIO_DEFAULT,
6802b8c612cSDmitry Osipenko 						   legacy_pm_power_off, NULL);
6812b8c612cSDmitry Osipenko 
6822b6aa733SDmitry Osipenko 	atomic_notifier_call_chain(&power_off_handler_list, 0, NULL);
6832b8c612cSDmitry Osipenko 
6842b8c612cSDmitry Osipenko 	unregister_sys_off_handler(sys_off);
6852b6aa733SDmitry Osipenko }
6862b6aa733SDmitry Osipenko 
6872b6aa733SDmitry Osipenko /**
6880e2110d2SDmitry Osipenko  *	kernel_can_power_off - check whether system can be powered off
6890e2110d2SDmitry Osipenko  *
6900e2110d2SDmitry Osipenko  *	Returns true if power-off handler is registered and system can be
6910e2110d2SDmitry Osipenko  *	powered off, false otherwise.
6920e2110d2SDmitry Osipenko  */
kernel_can_power_off(void)6930e2110d2SDmitry Osipenko bool kernel_can_power_off(void)
6940e2110d2SDmitry Osipenko {
6952b8c612cSDmitry Osipenko 	return !atomic_notifier_call_chain_is_empty(&power_off_handler_list) ||
6962b8c612cSDmitry Osipenko 		pm_power_off;
6970e2110d2SDmitry Osipenko }
6980e2110d2SDmitry Osipenko EXPORT_SYMBOL_GPL(kernel_can_power_off);
6990e2110d2SDmitry Osipenko 
70015d94b82SRobin Holt /**
70115d94b82SRobin Holt  *	kernel_power_off - power_off the system
70215d94b82SRobin Holt  *
70315d94b82SRobin Holt  *	Shutdown everything and perform a clean system power_off.
70415d94b82SRobin Holt  */
kernel_power_off(void)70515d94b82SRobin Holt void kernel_power_off(void)
70615d94b82SRobin Holt {
70715d94b82SRobin Holt 	kernel_shutdown_prepare(SYSTEM_POWER_OFF);
7087b9a3de9SDmitry Osipenko 	do_kernel_power_off_prepare();
70915d94b82SRobin Holt 	migrate_to_reboot_cpu();
71015d94b82SRobin Holt 	syscore_shutdown();
711972ee83dSRobin Holt 	pr_emerg("Power down\n");
7126d3cf962SKees Cook 	pr_flush(1000, true);
71315d94b82SRobin Holt 	kmsg_dump(KMSG_DUMP_SHUTDOWN);
71415d94b82SRobin Holt 	machine_power_off();
71515d94b82SRobin Holt }
71615d94b82SRobin Holt EXPORT_SYMBOL_GPL(kernel_power_off);
71755f2503cSPingfan Liu 
71815d94b82SRobin Holt DEFINE_MUTEX(system_transition_mutex);
71915d94b82SRobin Holt 
72015d94b82SRobin Holt /*
72115d94b82SRobin Holt  * Reboot system call: for obvious reasons only root may call it,
72215d94b82SRobin Holt  * and even root needs to set up some magic numbers in the registers
72315d94b82SRobin Holt  * so that some mistake won't make this reboot the whole machine.
72415d94b82SRobin Holt  * You can also set the meaning of the ctrl-alt-del-key here.
72515d94b82SRobin Holt  *
72615d94b82SRobin Holt  * reboot doesn't sync: do that yourself before calling this.
72715d94b82SRobin Holt  */
SYSCALL_DEFINE4(reboot,int,magic1,int,magic2,unsigned int,cmd,void __user *,arg)72815d94b82SRobin Holt SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
72915d94b82SRobin Holt 		void __user *, arg)
73015d94b82SRobin Holt {
73115d94b82SRobin Holt 	struct pid_namespace *pid_ns = task_active_pid_ns(current);
73215d94b82SRobin Holt 	char buffer[256];
73315d94b82SRobin Holt 	int ret = 0;
73415d94b82SRobin Holt 
73515d94b82SRobin Holt 	/* We only trust the superuser with rebooting the system. */
73615d94b82SRobin Holt 	if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
73715d94b82SRobin Holt 		return -EPERM;
73815d94b82SRobin Holt 
73915d94b82SRobin Holt 	/* For safety, we require "magic" arguments. */
74015d94b82SRobin Holt 	if (magic1 != LINUX_REBOOT_MAGIC1 ||
74115d94b82SRobin Holt 			(magic2 != LINUX_REBOOT_MAGIC2 &&
74215d94b82SRobin Holt 			magic2 != LINUX_REBOOT_MAGIC2A &&
74315d94b82SRobin Holt 			magic2 != LINUX_REBOOT_MAGIC2B &&
74415d94b82SRobin Holt 			magic2 != LINUX_REBOOT_MAGIC2C))
74515d94b82SRobin Holt 		return -EINVAL;
74615d94b82SRobin Holt 
74715d94b82SRobin Holt 	/*
74815d94b82SRobin Holt 	 * If pid namespaces are enabled and the current task is in a child
74915d94b82SRobin Holt 	 * pid_namespace, the command is handled by reboot_pid_ns() which will
75015d94b82SRobin Holt 	 * call do_exit().
75115d94b82SRobin Holt 	 */
75215d94b82SRobin Holt 	ret = reboot_pid_ns(pid_ns, cmd);
75315d94b82SRobin Holt 	if (ret)
75415d94b82SRobin Holt 		return ret;
75515d94b82SRobin Holt 
75615d94b82SRobin Holt 	/* Instead of trying to make the power_off code look like
75715d94b82SRobin Holt 	 * halt when pm_power_off is not set do it the easy way.
758a9a1d6adSDongmin Lee 	 */
759a9a1d6adSDongmin Lee 	if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !kernel_can_power_off()) {
76015d94b82SRobin Holt 		poweroff_fallback_to_halt = true;
761a9a1d6adSDongmin Lee 		cmd = LINUX_REBOOT_CMD_HALT;
76215d94b82SRobin Holt 	}
76355f2503cSPingfan Liu 
76415d94b82SRobin Holt 	mutex_lock(&system_transition_mutex);
76515d94b82SRobin Holt 	switch (cmd) {
76615d94b82SRobin Holt 	case LINUX_REBOOT_CMD_RESTART:
76715d94b82SRobin Holt 		kernel_restart(NULL);
76815d94b82SRobin Holt 		break;
76915d94b82SRobin Holt 
77015d94b82SRobin Holt 	case LINUX_REBOOT_CMD_CAD_ON:
77115d94b82SRobin Holt 		C_A_D = 1;
77215d94b82SRobin Holt 		break;
77315d94b82SRobin Holt 
77415d94b82SRobin Holt 	case LINUX_REBOOT_CMD_CAD_OFF:
77515d94b82SRobin Holt 		C_A_D = 0;
77615d94b82SRobin Holt 		break;
77715d94b82SRobin Holt 
77815d94b82SRobin Holt 	case LINUX_REBOOT_CMD_HALT:
77915d94b82SRobin Holt 		kernel_halt();
78015d94b82SRobin Holt 		do_exit(0);
78115d94b82SRobin Holt 
78215d94b82SRobin Holt 	case LINUX_REBOOT_CMD_POWER_OFF:
78315d94b82SRobin Holt 		kernel_power_off();
78415d94b82SRobin Holt 		do_exit(0);
78515d94b82SRobin Holt 		break;
78615d94b82SRobin Holt 
787972ee83dSRobin Holt 	case LINUX_REBOOT_CMD_RESTART2:
788972ee83dSRobin Holt 		ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
78915d94b82SRobin Holt 		if (ret < 0) {
79015d94b82SRobin Holt 			ret = -EFAULT;
79115d94b82SRobin Holt 			break;
79215d94b82SRobin Holt 		}
79315d94b82SRobin Holt 		buffer[sizeof(buffer) - 1] = '\0';
79415d94b82SRobin Holt 
79515d94b82SRobin Holt 		kernel_restart(buffer);
79615d94b82SRobin Holt 		break;
7972965faa5SDave Young 
79815d94b82SRobin Holt #ifdef CONFIG_KEXEC_CORE
79915d94b82SRobin Holt 	case LINUX_REBOOT_CMD_KEXEC:
80015d94b82SRobin Holt 		ret = kernel_kexec();
80115d94b82SRobin Holt 		break;
80215d94b82SRobin Holt #endif
80315d94b82SRobin Holt 
80415d94b82SRobin Holt #ifdef CONFIG_HIBERNATION
80515d94b82SRobin Holt 	case LINUX_REBOOT_CMD_SW_SUSPEND:
80615d94b82SRobin Holt 		ret = hibernate();
80715d94b82SRobin Holt 		break;
80815d94b82SRobin Holt #endif
80915d94b82SRobin Holt 
81015d94b82SRobin Holt 	default:
81115d94b82SRobin Holt 		ret = -EINVAL;
81215d94b82SRobin Holt 		break;
81355f2503cSPingfan Liu 	}
81415d94b82SRobin Holt 	mutex_unlock(&system_transition_mutex);
81515d94b82SRobin Holt 	return ret;
81615d94b82SRobin Holt }
81715d94b82SRobin Holt 
deferred_cad(struct work_struct * dummy)81815d94b82SRobin Holt static void deferred_cad(struct work_struct *dummy)
81915d94b82SRobin Holt {
82015d94b82SRobin Holt 	kernel_restart(NULL);
82115d94b82SRobin Holt }
82215d94b82SRobin Holt 
82315d94b82SRobin Holt /*
82415d94b82SRobin Holt  * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
82515d94b82SRobin Holt  * As it's called within an interrupt, it may NOT sync: the only choice
82615d94b82SRobin Holt  * is whether to reboot at once, or just ignore the ctrl-alt-del.
82715d94b82SRobin Holt  */
ctrl_alt_del(void)82815d94b82SRobin Holt void ctrl_alt_del(void)
82915d94b82SRobin Holt {
83015d94b82SRobin Holt 	static DECLARE_WORK(cad_work, deferred_cad);
83115d94b82SRobin Holt 
83215d94b82SRobin Holt 	if (C_A_D)
83315d94b82SRobin Holt 		schedule_work(&cad_work);
83415d94b82SRobin Holt 	else
83515d94b82SRobin Holt 		kill_cad_pid(SIGINT, 1);
83615d94b82SRobin Holt }
83706d17766Stangmeng 
83806d17766Stangmeng #define POWEROFF_CMD_PATH_LEN  256
8397a54f46bSJoel Stanley static char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
84015d94b82SRobin Holt static const char reboot_cmd[] = "/sbin/reboot";
8417a54f46bSJoel Stanley 
run_cmd(const char * cmd)84215d94b82SRobin Holt static int run_cmd(const char *cmd)
84315d94b82SRobin Holt {
84415d94b82SRobin Holt 	char **argv;
84515d94b82SRobin Holt 	static char *envp[] = {
84615d94b82SRobin Holt 		"HOME=/",
84715d94b82SRobin Holt 		"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
84815d94b82SRobin Holt 		NULL
84915d94b82SRobin Holt 	};
8507a54f46bSJoel Stanley 	int ret;
85115d94b82SRobin Holt 	argv = argv_split(GFP_KERNEL, cmd, NULL);
85215d94b82SRobin Holt 	if (argv) {
85315d94b82SRobin Holt 		ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
85415d94b82SRobin Holt 		argv_free(argv);
85515d94b82SRobin Holt 	} else {
85615d94b82SRobin Holt 		ret = -ENOMEM;
85715d94b82SRobin Holt 	}
8587a54f46bSJoel Stanley 
8597a54f46bSJoel Stanley 	return ret;
8607a54f46bSJoel Stanley }
8617a54f46bSJoel Stanley 
__orderly_reboot(void)8627a54f46bSJoel Stanley static int __orderly_reboot(void)
8637a54f46bSJoel Stanley {
8647a54f46bSJoel Stanley 	int ret;
8657a54f46bSJoel Stanley 
8667a54f46bSJoel Stanley 	ret = run_cmd(reboot_cmd);
8677a54f46bSJoel Stanley 
8687a54f46bSJoel Stanley 	if (ret) {
8697a54f46bSJoel Stanley 		pr_warn("Failed to start orderly reboot: forcing the issue\n");
8707a54f46bSJoel Stanley 		emergency_sync();
8717a54f46bSJoel Stanley 		kernel_restart(NULL);
8727a54f46bSJoel Stanley 	}
8737a54f46bSJoel Stanley 
8747a54f46bSJoel Stanley 	return ret;
8757a54f46bSJoel Stanley }
8767a54f46bSJoel Stanley 
__orderly_poweroff(bool force)8777a54f46bSJoel Stanley static int __orderly_poweroff(bool force)
8787a54f46bSJoel Stanley {
8797a54f46bSJoel Stanley 	int ret;
8807a54f46bSJoel Stanley 
8817a54f46bSJoel Stanley 	ret = run_cmd(poweroff_cmd);
88215d94b82SRobin Holt 
883972ee83dSRobin Holt 	if (ret && force) {
8847a54f46bSJoel Stanley 		pr_warn("Failed to start orderly shutdown: forcing the issue\n");
88515d94b82SRobin Holt 
88615d94b82SRobin Holt 		/*
88715d94b82SRobin Holt 		 * I guess this should try to kick off some daemon to sync and
88815d94b82SRobin Holt 		 * poweroff asap.  Or not even bother syncing if we're doing an
88915d94b82SRobin Holt 		 * emergency shutdown?
89015d94b82SRobin Holt 		 */
89115d94b82SRobin Holt 		emergency_sync();
89215d94b82SRobin Holt 		kernel_power_off();
89315d94b82SRobin Holt 	}
89415d94b82SRobin Holt 
89515d94b82SRobin Holt 	return ret;
89615d94b82SRobin Holt }
89715d94b82SRobin Holt 
89815d94b82SRobin Holt static bool poweroff_force;
89915d94b82SRobin Holt 
poweroff_work_func(struct work_struct * work)90015d94b82SRobin Holt static void poweroff_work_func(struct work_struct *work)
90115d94b82SRobin Holt {
90215d94b82SRobin Holt 	__orderly_poweroff(poweroff_force);
90315d94b82SRobin Holt }
90415d94b82SRobin Holt 
90515d94b82SRobin Holt static DECLARE_WORK(poweroff_work, poweroff_work_func);
90615d94b82SRobin Holt 
90715d94b82SRobin Holt /**
90815d94b82SRobin Holt  * orderly_poweroff - Trigger an orderly system poweroff
90915d94b82SRobin Holt  * @force: force poweroff if command execution fails
91015d94b82SRobin Holt  *
91115d94b82SRobin Holt  * This may be called from any context to trigger a system shutdown.
91215d94b82SRobin Holt  * If the orderly shutdown fails, it will force an immediate shutdown.
9137a54f46bSJoel Stanley  */
orderly_poweroff(bool force)91415d94b82SRobin Holt void orderly_poweroff(bool force)
91515d94b82SRobin Holt {
91615d94b82SRobin Holt 	if (force) /* do not override the pending "true" */
91715d94b82SRobin Holt 		poweroff_force = true;
91815d94b82SRobin Holt 	schedule_work(&poweroff_work);
91915d94b82SRobin Holt }
9201b3a5d02SRobin Holt EXPORT_SYMBOL_GPL(orderly_poweroff);
9217a54f46bSJoel Stanley 
reboot_work_func(struct work_struct * work)9227a54f46bSJoel Stanley static void reboot_work_func(struct work_struct *work)
9237a54f46bSJoel Stanley {
9247a54f46bSJoel Stanley 	__orderly_reboot();
9257a54f46bSJoel Stanley }
9267a54f46bSJoel Stanley 
9277a54f46bSJoel Stanley static DECLARE_WORK(reboot_work, reboot_work_func);
9287a54f46bSJoel Stanley 
9297a54f46bSJoel Stanley /**
9307a54f46bSJoel Stanley  * orderly_reboot - Trigger an orderly system reboot
9317a54f46bSJoel Stanley  *
9327a54f46bSJoel Stanley  * This may be called from any context to trigger a system reboot.
9337a54f46bSJoel Stanley  * If the orderly reboot fails, it will force an immediate reboot.
9347a54f46bSJoel Stanley  */
orderly_reboot(void)9357a54f46bSJoel Stanley void orderly_reboot(void)
9367a54f46bSJoel Stanley {
9377a54f46bSJoel Stanley 	schedule_work(&reboot_work);
9387a54f46bSJoel Stanley }
9397a54f46bSJoel Stanley EXPORT_SYMBOL_GPL(orderly_reboot);
940bbf0ec4fSAhmad Fatoum 
hw_protection_action_str(enum hw_protection_action action)941bbf0ec4fSAhmad Fatoum static const char *hw_protection_action_str(enum hw_protection_action action)
942bbf0ec4fSAhmad Fatoum {
943bbf0ec4fSAhmad Fatoum 	switch (action) {
944bbf0ec4fSAhmad Fatoum 	case HWPROT_ACT_SHUTDOWN:
945bbf0ec4fSAhmad Fatoum 		return "shutdown";
946bbf0ec4fSAhmad Fatoum 	case HWPROT_ACT_REBOOT:
947bbf0ec4fSAhmad Fatoum 		return "reboot";
948bbf0ec4fSAhmad Fatoum 	default:
949bbf0ec4fSAhmad Fatoum 		return "undefined";
950bbf0ec4fSAhmad Fatoum 	}
951bbf0ec4fSAhmad Fatoum }
952bbf0ec4fSAhmad Fatoum 
953bbf0ec4fSAhmad Fatoum static enum hw_protection_action hw_failure_emergency_action;
954dfa19b11SMatti Vaittinen 
955bbf0ec4fSAhmad Fatoum /**
956bbf0ec4fSAhmad Fatoum  * hw_failure_emergency_action_func - emergency action work after a known delay
957dfa19b11SMatti Vaittinen  * @work: work_struct associated with the emergency action function
958dfa19b11SMatti Vaittinen  *
959bbf0ec4fSAhmad Fatoum  * This function is called in very critical situations to force
960dfa19b11SMatti Vaittinen  * a kernel poweroff or reboot after a configurable timeout value.
961bbf0ec4fSAhmad Fatoum  */
hw_failure_emergency_action_func(struct work_struct * work)962dfa19b11SMatti Vaittinen static void hw_failure_emergency_action_func(struct work_struct *work)
963bbf0ec4fSAhmad Fatoum {
964bbf0ec4fSAhmad Fatoum 	const char *action_str = hw_protection_action_str(hw_failure_emergency_action);
965bbf0ec4fSAhmad Fatoum 
966bbf0ec4fSAhmad Fatoum 	pr_emerg("Hardware protection timed-out. Trying forced %s\n",
967bbf0ec4fSAhmad Fatoum 		 action_str);
968dfa19b11SMatti Vaittinen 
969bbf0ec4fSAhmad Fatoum 	/*
970bbf0ec4fSAhmad Fatoum 	 * We have reached here after the emergency action waiting period has
971bbf0ec4fSAhmad Fatoum 	 * expired. This means orderly_poweroff/reboot has not been able to
972dfa19b11SMatti Vaittinen 	 * shut off the system for some reason.
973bbf0ec4fSAhmad Fatoum 	 *
974dfa19b11SMatti Vaittinen 	 * Try to shut off the system immediately if possible
975bbf0ec4fSAhmad Fatoum 	 */
976bbf0ec4fSAhmad Fatoum 
977bbf0ec4fSAhmad Fatoum 	if (hw_failure_emergency_action == HWPROT_ACT_REBOOT)
978bbf0ec4fSAhmad Fatoum 		kernel_restart(NULL);
979dfa19b11SMatti Vaittinen 	else
980dfa19b11SMatti Vaittinen 		kernel_power_off();
981dfa19b11SMatti Vaittinen 
982dfa19b11SMatti Vaittinen 	/*
983dfa19b11SMatti Vaittinen 	 * Worst of the worst case trigger emergency restart
984bbf0ec4fSAhmad Fatoum 	 */
985bbf0ec4fSAhmad Fatoum 	pr_emerg("Hardware protection %s failed. Trying emergency restart\n",
986dfa19b11SMatti Vaittinen 		 action_str);
987dfa19b11SMatti Vaittinen 	emergency_restart();
988dfa19b11SMatti Vaittinen }
989bbf0ec4fSAhmad Fatoum 
990bbf0ec4fSAhmad Fatoum static DECLARE_DELAYED_WORK(hw_failure_emergency_action_work,
991dfa19b11SMatti Vaittinen 			    hw_failure_emergency_action_func);
992dfa19b11SMatti Vaittinen 
993bbf0ec4fSAhmad Fatoum /**
994bbf0ec4fSAhmad Fatoum  * hw_failure_emergency_schedule - Schedule an emergency system shutdown or reboot
995bbf0ec4fSAhmad Fatoum  *
996bbf0ec4fSAhmad Fatoum  * @action:		The hardware protection action to be taken
997dfa19b11SMatti Vaittinen  * @action_delay_ms:	Time in milliseconds to elapse before triggering action
998dfa19b11SMatti Vaittinen  *
999bbf0ec4fSAhmad Fatoum  * This may be called from any critical situation to trigger a system shutdown
1000bbf0ec4fSAhmad Fatoum  * or reboot after a given period of time.
1001dfa19b11SMatti Vaittinen  * If time is negative this is not scheduled.
1002bbf0ec4fSAhmad Fatoum  */
hw_failure_emergency_schedule(enum hw_protection_action action,int action_delay_ms)1003bbf0ec4fSAhmad Fatoum static void hw_failure_emergency_schedule(enum hw_protection_action action,
1004dfa19b11SMatti Vaittinen 					  int action_delay_ms)
1005bbf0ec4fSAhmad Fatoum {
1006dfa19b11SMatti Vaittinen 	if (action_delay_ms <= 0)
1007bbf0ec4fSAhmad Fatoum 		return;
1008bbf0ec4fSAhmad Fatoum 	hw_failure_emergency_action = action;
1009bbf0ec4fSAhmad Fatoum 	schedule_delayed_work(&hw_failure_emergency_action_work,
1010dfa19b11SMatti Vaittinen 			      msecs_to_jiffies(action_delay_ms));
1011dfa19b11SMatti Vaittinen }
1012dfa19b11SMatti Vaittinen 
101381cab0f9SAhmad Fatoum /**
1014dfa19b11SMatti Vaittinen  * __hw_protection_trigger - Trigger an emergency system shutdown or reboot
101579fa723bSFabio Estevam  *
101679fa723bSFabio Estevam  * @reason:		Reason of emergency shutdown or reboot to be printed.
101779fa723bSFabio Estevam  * @ms_until_forced:	Time to wait for orderly shutdown or reboot before
101879fa723bSFabio Estevam  *			triggering it. Negative value disables the forced
1019318f05a0SAhmad Fatoum  *			shutdown or reboot.
1020dfa19b11SMatti Vaittinen  * @action:		The hardware protection action to be taken.
102179fa723bSFabio Estevam  *
102279fa723bSFabio Estevam  * Initiate an emergency system shutdown or reboot in order to protect
102379fa723bSFabio Estevam  * hardware from further damage. Usage examples include a thermal protection.
102479fa723bSFabio Estevam  * NOTE: The request is ignored if protection shutdown or reboot is already
102579fa723bSFabio Estevam  * pending even if the previous request has given a large timeout for forced
1026dfa19b11SMatti Vaittinen  * shutdown/reboot.
102781cab0f9SAhmad Fatoum  */
__hw_protection_trigger(const char * reason,int ms_until_forced,enum hw_protection_action action)1028318f05a0SAhmad Fatoum void __hw_protection_trigger(const char *reason, int ms_until_forced,
1029dfa19b11SMatti Vaittinen 			     enum hw_protection_action action)
1030dfa19b11SMatti Vaittinen {
1031dfa19b11SMatti Vaittinen 	static atomic_t allow_proceed = ATOMIC_INIT(1);
1032*e016173fSAhmad Fatoum 
1033*e016173fSAhmad Fatoum 	if (action == HWPROT_ACT_DEFAULT)
1034*e016173fSAhmad Fatoum 		action = hw_protection_action;
103596201a8aSAhmad Fatoum 
103696201a8aSAhmad Fatoum 	pr_emerg("HARDWARE PROTECTION %s (%s)\n",
1037dfa19b11SMatti Vaittinen 		 hw_protection_action_str(action), reason);
1038dfa19b11SMatti Vaittinen 
1039dfa19b11SMatti Vaittinen 	/* Shutdown should be initiated only once. */
104007a22b61SPetr Mladek 	if (!atomic_dec_and_test(&allow_proceed))
1041dfa19b11SMatti Vaittinen 		return;
1042dfa19b11SMatti Vaittinen 
1043dfa19b11SMatti Vaittinen 	/*
1044dfa19b11SMatti Vaittinen 	 * Queue a backup emergency shutdown in the event of
1045dfa19b11SMatti Vaittinen 	 * orderly_poweroff failure
1046bbf0ec4fSAhmad Fatoum 	 */
1047318f05a0SAhmad Fatoum 	hw_failure_emergency_schedule(action, ms_until_forced);
104879fa723bSFabio Estevam 	if (action == HWPROT_ACT_REBOOT)
1049318f05a0SAhmad Fatoum 		orderly_reboot();
1050318f05a0SAhmad Fatoum 	else
1051dfa19b11SMatti Vaittinen 		orderly_poweroff(true);
105281cab0f9SAhmad Fatoum }
1053dfa19b11SMatti Vaittinen EXPORT_SYMBOL_GPL(__hw_protection_trigger);
1054*e016173fSAhmad Fatoum 
hw_protection_action_parse(const char * str,enum hw_protection_action * action)1055*e016173fSAhmad Fatoum static bool hw_protection_action_parse(const char *str,
1056*e016173fSAhmad Fatoum 				       enum hw_protection_action *action)
1057*e016173fSAhmad Fatoum {
1058*e016173fSAhmad Fatoum 	if (sysfs_streq(str, "shutdown"))
1059*e016173fSAhmad Fatoum 		*action = HWPROT_ACT_SHUTDOWN;
1060*e016173fSAhmad Fatoum 	else if (sysfs_streq(str, "reboot"))
1061*e016173fSAhmad Fatoum 		*action = HWPROT_ACT_REBOOT;
1062*e016173fSAhmad Fatoum 	else
1063*e016173fSAhmad Fatoum 		return false;
1064*e016173fSAhmad Fatoum 
1065*e016173fSAhmad Fatoum 	return true;
1066*e016173fSAhmad Fatoum }
1067*e016173fSAhmad Fatoum 
hw_protection_setup(char * str)1068*e016173fSAhmad Fatoum static int __init hw_protection_setup(char *str)
1069*e016173fSAhmad Fatoum {
1070*e016173fSAhmad Fatoum 	hw_protection_action_parse(str, &hw_protection_action);
1071*e016173fSAhmad Fatoum 	return 1;
1072*e016173fSAhmad Fatoum }
1073*e016173fSAhmad Fatoum __setup("hw_protection=", hw_protection_setup);
1074*e016173fSAhmad Fatoum 
1075*e016173fSAhmad Fatoum #ifdef CONFIG_SYSFS
hw_protection_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1076*e016173fSAhmad Fatoum static ssize_t hw_protection_show(struct kobject *kobj,
1077*e016173fSAhmad Fatoum 				  struct kobj_attribute *attr, char *buf)
1078*e016173fSAhmad Fatoum {
1079*e016173fSAhmad Fatoum 	return sysfs_emit(buf, "%s\n",
1080*e016173fSAhmad Fatoum 			  hw_protection_action_str(hw_protection_action));
1081*e016173fSAhmad Fatoum }
hw_protection_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1082*e016173fSAhmad Fatoum static ssize_t hw_protection_store(struct kobject *kobj,
1083*e016173fSAhmad Fatoum 				   struct kobj_attribute *attr, const char *buf,
1084*e016173fSAhmad Fatoum 				   size_t count)
1085*e016173fSAhmad Fatoum {
1086*e016173fSAhmad Fatoum 	if (!capable(CAP_SYS_ADMIN))
1087*e016173fSAhmad Fatoum 		return -EPERM;
1088*e016173fSAhmad Fatoum 
1089*e016173fSAhmad Fatoum 	if (!hw_protection_action_parse(buf, &hw_protection_action))
1090*e016173fSAhmad Fatoum 		return -EINVAL;
1091*e016173fSAhmad Fatoum 
1092*e016173fSAhmad Fatoum 	return count;
1093*e016173fSAhmad Fatoum }
1094*e016173fSAhmad Fatoum static struct kobj_attribute hw_protection_attr = __ATTR_RW(hw_protection);
1095*e016173fSAhmad Fatoum #endif
10961b3a5d02SRobin Holt 
reboot_setup(char * str)10971b3a5d02SRobin Holt static int __init reboot_setup(char *str)
10981b3a5d02SRobin Holt {
1099b287a25aSAaro Koskinen 	for (;;) {
1100b287a25aSAaro Koskinen 		enum reboot_mode *mode;
11011b3a5d02SRobin Holt 
11021b3a5d02SRobin Holt 		/*
11031b3a5d02SRobin Holt 		 * Having anything passed on the command line via
11041b3a5d02SRobin Holt 		 * reboot= will cause us to disable DMI checking
11051b3a5d02SRobin Holt 		 * below.
11061b3a5d02SRobin Holt 		 */
11071b3a5d02SRobin Holt 		reboot_default = 0;
1108b287a25aSAaro Koskinen 
1109b287a25aSAaro Koskinen 		if (!strncmp(str, "panic_", 6)) {
1110b287a25aSAaro Koskinen 			mode = &panic_reboot_mode;
1111b287a25aSAaro Koskinen 			str += 6;
1112b287a25aSAaro Koskinen 		} else {
1113b287a25aSAaro Koskinen 			mode = &reboot_mode;
1114b287a25aSAaro Koskinen 		}
11151b3a5d02SRobin Holt 
11161b3a5d02SRobin Holt 		switch (*str) {
1117b287a25aSAaro Koskinen 		case 'w':
11181b3a5d02SRobin Holt 			*mode = REBOOT_WARM;
11191b3a5d02SRobin Holt 			break;
11201b3a5d02SRobin Holt 
1121b287a25aSAaro Koskinen 		case 'c':
11221b3a5d02SRobin Holt 			*mode = REBOOT_COLD;
11231b3a5d02SRobin Holt 			break;
11241b3a5d02SRobin Holt 
1125b287a25aSAaro Koskinen 		case 'h':
11261b3a5d02SRobin Holt 			*mode = REBOOT_HARD;
11271b3a5d02SRobin Holt 			break;
11281b3a5d02SRobin Holt 
1129f9a90501SMatteo Croce 		case 's':
1130f9a90501SMatteo Croce 			/*
1131f9a90501SMatteo Croce 			 * reboot_cpu is s[mp]#### with #### being the processor
1132f9a90501SMatteo Croce 			 * to be used for rebooting. Skip 's' or 'smp' prefix.
1133f9a90501SMatteo Croce 			 */
1134f9a90501SMatteo Croce 			str += str[1] == 'm' && str[2] == 'p' ? 3 : 1;
1135f9a90501SMatteo Croce 
1136f9a90501SMatteo Croce 			if (isdigit(str[0])) {
1137f9a90501SMatteo Croce 				int cpu = simple_strtoul(str, NULL, 0);
1138f9a90501SMatteo Croce 
1139df5b0ab3SMatteo Croce 				if (cpu >= num_possible_cpus()) {
1140df5b0ab3SMatteo Croce 					pr_err("Ignoring the CPU number in reboot= option. "
1141f9a90501SMatteo Croce 					"CPU %d exceeds possible cpu number %d\n",
1142df5b0ab3SMatteo Croce 					cpu, num_possible_cpus());
1143df5b0ab3SMatteo Croce 					break;
1144f9a90501SMatteo Croce 				}
1145f9a90501SMatteo Croce 				reboot_cpu = cpu;
1146f9a90501SMatteo Croce 			} else
11471b3a5d02SRobin Holt 				*mode = REBOOT_SOFT;
11488b92c4ffSMatteo Croce 			break;
11491b3a5d02SRobin Holt 
1150b287a25aSAaro Koskinen 		case 'g':
11511b3a5d02SRobin Holt 			*mode = REBOOT_GPIO;
11521b3a5d02SRobin Holt 			break;
11531b3a5d02SRobin Holt 
11541b3a5d02SRobin Holt 		case 'b':
11551b3a5d02SRobin Holt 		case 'a':
11561b3a5d02SRobin Holt 		case 'k':
11571b3a5d02SRobin Holt 		case 't':
11581b3a5d02SRobin Holt 		case 'e':
11591b3a5d02SRobin Holt 		case 'p':
11601b3a5d02SRobin Holt 			reboot_type = *str;
11611b3a5d02SRobin Holt 			break;
11621b3a5d02SRobin Holt 
11631b3a5d02SRobin Holt 		case 'f':
11641b3a5d02SRobin Holt 			reboot_force = 1;
11651b3a5d02SRobin Holt 			break;
11661b3a5d02SRobin Holt 		}
11671b3a5d02SRobin Holt 
11681b3a5d02SRobin Holt 		str = strchr(str, ',');
11691b3a5d02SRobin Holt 		if (str)
11701b3a5d02SRobin Holt 			str++;
11711b3a5d02SRobin Holt 		else
11721b3a5d02SRobin Holt 			break;
11731b3a5d02SRobin Holt 	}
11741b3a5d02SRobin Holt 	return 1;
11751b3a5d02SRobin Holt }
11762c622ed0SMatteo Croce __setup("reboot=", reboot_setup);
11772c622ed0SMatteo Croce 
11782c622ed0SMatteo Croce #ifdef CONFIG_SYSFS
11792c622ed0SMatteo Croce 
11802c622ed0SMatteo Croce #define REBOOT_COLD_STR		"cold"
11812c622ed0SMatteo Croce #define REBOOT_WARM_STR		"warm"
11822c622ed0SMatteo Croce #define REBOOT_HARD_STR		"hard"
11832c622ed0SMatteo Croce #define REBOOT_SOFT_STR		"soft"
11842c622ed0SMatteo Croce #define REBOOT_GPIO_STR		"gpio"
11852c622ed0SMatteo Croce #define REBOOT_UNDEFINED_STR	"undefined"
11862c622ed0SMatteo Croce 
11872c622ed0SMatteo Croce #define BOOT_TRIPLE_STR		"triple"
11882c622ed0SMatteo Croce #define BOOT_KBD_STR		"kbd"
11892c622ed0SMatteo Croce #define BOOT_BIOS_STR		"bios"
11902c622ed0SMatteo Croce #define BOOT_ACPI_STR		"acpi"
11910c5c0179SMatteo Croce #define BOOT_EFI_STR		"efi"
11922c622ed0SMatteo Croce #define BOOT_PCI_STR		"pci"
11932c622ed0SMatteo Croce 
mode_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)11942c622ed0SMatteo Croce static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
11952c622ed0SMatteo Croce {
11962c622ed0SMatteo Croce 	const char *val;
11972c622ed0SMatteo Croce 
11982c622ed0SMatteo Croce 	switch (reboot_mode) {
11992c622ed0SMatteo Croce 	case REBOOT_COLD:
12002c622ed0SMatteo Croce 		val = REBOOT_COLD_STR;
12012c622ed0SMatteo Croce 		break;
12022c622ed0SMatteo Croce 	case REBOOT_WARM:
12032c622ed0SMatteo Croce 		val = REBOOT_WARM_STR;
12042c622ed0SMatteo Croce 		break;
12052c622ed0SMatteo Croce 	case REBOOT_HARD:
12062c622ed0SMatteo Croce 		val = REBOOT_HARD_STR;
12072c622ed0SMatteo Croce 		break;
12082c622ed0SMatteo Croce 	case REBOOT_SOFT:
12092c622ed0SMatteo Croce 		val = REBOOT_SOFT_STR;
12102c622ed0SMatteo Croce 		break;
12112c622ed0SMatteo Croce 	case REBOOT_GPIO:
12122c622ed0SMatteo Croce 		val = REBOOT_GPIO_STR;
12132c622ed0SMatteo Croce 		break;
12142c622ed0SMatteo Croce 	default:
12152c622ed0SMatteo Croce 		val = REBOOT_UNDEFINED_STR;
12162c622ed0SMatteo Croce 	}
121745dac195Szhangguopeng 
12182c622ed0SMatteo Croce 	return sysfs_emit(buf, "%s\n", val);
12192c622ed0SMatteo Croce }
mode_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)12202c622ed0SMatteo Croce static ssize_t mode_store(struct kobject *kobj, struct kobj_attribute *attr,
12212c622ed0SMatteo Croce 			  const char *buf, size_t count)
12222c622ed0SMatteo Croce {
12232c622ed0SMatteo Croce 	if (!capable(CAP_SYS_BOOT))
12242c622ed0SMatteo Croce 		return -EPERM;
12252c622ed0SMatteo Croce 
12262c622ed0SMatteo Croce 	if (!strncmp(buf, REBOOT_COLD_STR, strlen(REBOOT_COLD_STR)))
12272c622ed0SMatteo Croce 		reboot_mode = REBOOT_COLD;
12282c622ed0SMatteo Croce 	else if (!strncmp(buf, REBOOT_WARM_STR, strlen(REBOOT_WARM_STR)))
12292c622ed0SMatteo Croce 		reboot_mode = REBOOT_WARM;
12302c622ed0SMatteo Croce 	else if (!strncmp(buf, REBOOT_HARD_STR, strlen(REBOOT_HARD_STR)))
12312c622ed0SMatteo Croce 		reboot_mode = REBOOT_HARD;
12322c622ed0SMatteo Croce 	else if (!strncmp(buf, REBOOT_SOFT_STR, strlen(REBOOT_SOFT_STR)))
12332c622ed0SMatteo Croce 		reboot_mode = REBOOT_SOFT;
12342c622ed0SMatteo Croce 	else if (!strncmp(buf, REBOOT_GPIO_STR, strlen(REBOOT_GPIO_STR)))
12352c622ed0SMatteo Croce 		reboot_mode = REBOOT_GPIO;
12362c622ed0SMatteo Croce 	else
12372c622ed0SMatteo Croce 		return -EINVAL;
12381a9d079fSMatteo Croce 
12391a9d079fSMatteo Croce 	reboot_default = 0;
12402c622ed0SMatteo Croce 
12412c622ed0SMatteo Croce 	return count;
12422c622ed0SMatteo Croce }
12432c622ed0SMatteo Croce static struct kobj_attribute reboot_mode_attr = __ATTR_RW(mode);
124440247e55SMatteo Croce 
124540247e55SMatteo Croce #ifdef CONFIG_X86
force_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)124640247e55SMatteo Croce static ssize_t force_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
124745dac195Szhangguopeng {
124840247e55SMatteo Croce 	return sysfs_emit(buf, "%d\n", reboot_force);
124940247e55SMatteo Croce }
force_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)125040247e55SMatteo Croce static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
125140247e55SMatteo Croce 			  const char *buf, size_t count)
125240247e55SMatteo Croce {
125340247e55SMatteo Croce 	bool res;
125440247e55SMatteo Croce 
125540247e55SMatteo Croce 	if (!capable(CAP_SYS_BOOT))
125640247e55SMatteo Croce 		return -EPERM;
125740247e55SMatteo Croce 
125840247e55SMatteo Croce 	if (kstrtobool(buf, &res))
125940247e55SMatteo Croce 		return -EINVAL;
126040247e55SMatteo Croce 
126140247e55SMatteo Croce 	reboot_default = 0;
126240247e55SMatteo Croce 	reboot_force = res;
126340247e55SMatteo Croce 
126440247e55SMatteo Croce 	return count;
126540247e55SMatteo Croce }
126640247e55SMatteo Croce static struct kobj_attribute reboot_force_attr = __ATTR_RW(force);
12672c622ed0SMatteo Croce 
type_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)12682c622ed0SMatteo Croce static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
12692c622ed0SMatteo Croce {
12702c622ed0SMatteo Croce 	const char *val;
12712c622ed0SMatteo Croce 
12722c622ed0SMatteo Croce 	switch (reboot_type) {
12732c622ed0SMatteo Croce 	case BOOT_TRIPLE:
12742c622ed0SMatteo Croce 		val = BOOT_TRIPLE_STR;
12752c622ed0SMatteo Croce 		break;
12762c622ed0SMatteo Croce 	case BOOT_KBD:
12772c622ed0SMatteo Croce 		val = BOOT_KBD_STR;
12782c622ed0SMatteo Croce 		break;
12792c622ed0SMatteo Croce 	case BOOT_BIOS:
12802c622ed0SMatteo Croce 		val = BOOT_BIOS_STR;
12812c622ed0SMatteo Croce 		break;
12822c622ed0SMatteo Croce 	case BOOT_ACPI:
12832c622ed0SMatteo Croce 		val = BOOT_ACPI_STR;
12842c622ed0SMatteo Croce 		break;
12852c622ed0SMatteo Croce 	case BOOT_EFI:
12862c622ed0SMatteo Croce 		val = BOOT_EFI_STR;
12872c622ed0SMatteo Croce 		break;
12880c5c0179SMatteo Croce 	case BOOT_CF9_FORCE:
12892c622ed0SMatteo Croce 		val = BOOT_PCI_STR;
12902c622ed0SMatteo Croce 		break;
12912c622ed0SMatteo Croce 	default:
12922c622ed0SMatteo Croce 		val = REBOOT_UNDEFINED_STR;
12932c622ed0SMatteo Croce 	}
129445dac195Szhangguopeng 
12952c622ed0SMatteo Croce 	return sysfs_emit(buf, "%s\n", val);
12962c622ed0SMatteo Croce }
type_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)12972c622ed0SMatteo Croce static ssize_t type_store(struct kobject *kobj, struct kobj_attribute *attr,
12982c622ed0SMatteo Croce 			  const char *buf, size_t count)
12992c622ed0SMatteo Croce {
13002c622ed0SMatteo Croce 	if (!capable(CAP_SYS_BOOT))
13012c622ed0SMatteo Croce 		return -EPERM;
13022c622ed0SMatteo Croce 
13032c622ed0SMatteo Croce 	if (!strncmp(buf, BOOT_TRIPLE_STR, strlen(BOOT_TRIPLE_STR)))
13042c622ed0SMatteo Croce 		reboot_type = BOOT_TRIPLE;
13052c622ed0SMatteo Croce 	else if (!strncmp(buf, BOOT_KBD_STR, strlen(BOOT_KBD_STR)))
13062c622ed0SMatteo Croce 		reboot_type = BOOT_KBD;
13072c622ed0SMatteo Croce 	else if (!strncmp(buf, BOOT_BIOS_STR, strlen(BOOT_BIOS_STR)))
13082c622ed0SMatteo Croce 		reboot_type = BOOT_BIOS;
13092c622ed0SMatteo Croce 	else if (!strncmp(buf, BOOT_ACPI_STR, strlen(BOOT_ACPI_STR)))
13102c622ed0SMatteo Croce 		reboot_type = BOOT_ACPI;
13112c622ed0SMatteo Croce 	else if (!strncmp(buf, BOOT_EFI_STR, strlen(BOOT_EFI_STR)))
13120c5c0179SMatteo Croce 		reboot_type = BOOT_EFI;
13132c622ed0SMatteo Croce 	else if (!strncmp(buf, BOOT_PCI_STR, strlen(BOOT_PCI_STR)))
13142c622ed0SMatteo Croce 		reboot_type = BOOT_CF9_FORCE;
13152c622ed0SMatteo Croce 	else
13162c622ed0SMatteo Croce 		return -EINVAL;
13171a9d079fSMatteo Croce 
13181a9d079fSMatteo Croce 	reboot_default = 0;
13192c622ed0SMatteo Croce 
13202c622ed0SMatteo Croce 	return count;
13212c622ed0SMatteo Croce }
132240247e55SMatteo Croce static struct kobj_attribute reboot_type_attr = __ATTR_RW(type);
13232c622ed0SMatteo Croce #endif
132440247e55SMatteo Croce 
13252c622ed0SMatteo Croce #ifdef CONFIG_SMP
cpu_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)13262c622ed0SMatteo Croce static ssize_t cpu_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
132745dac195Szhangguopeng {
13282c622ed0SMatteo Croce 	return sysfs_emit(buf, "%d\n", reboot_cpu);
13292c622ed0SMatteo Croce }
cpu_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)13302c622ed0SMatteo Croce static ssize_t cpu_store(struct kobject *kobj, struct kobj_attribute *attr,
13312c622ed0SMatteo Croce 			  const char *buf, size_t count)
13322c622ed0SMatteo Croce {
13332c622ed0SMatteo Croce 	unsigned int cpunum;
13342c622ed0SMatteo Croce 	int rc;
13352c622ed0SMatteo Croce 
13362c622ed0SMatteo Croce 	if (!capable(CAP_SYS_BOOT))
13372c622ed0SMatteo Croce 		return -EPERM;
13382c622ed0SMatteo Croce 
13392c622ed0SMatteo Croce 	rc = kstrtouint(buf, 0, &cpunum);
13402c622ed0SMatteo Croce 
13412c622ed0SMatteo Croce 	if (rc)
13422c622ed0SMatteo Croce 		return rc;
13432c622ed0SMatteo Croce 
13442c622ed0SMatteo Croce 	if (cpunum >= num_possible_cpus())
13452c622ed0SMatteo Croce 		return -ERANGE;
13461a9d079fSMatteo Croce 
13472c622ed0SMatteo Croce 	reboot_default = 0;
13482c622ed0SMatteo Croce 	reboot_cpu = cpunum;
13492c622ed0SMatteo Croce 
13502c622ed0SMatteo Croce 	return count;
13512c622ed0SMatteo Croce }
135240247e55SMatteo Croce static struct kobj_attribute reboot_cpu_attr = __ATTR_RW(cpu);
13532c622ed0SMatteo Croce #endif
13542c622ed0SMatteo Croce 
1355*e016173fSAhmad Fatoum static struct attribute *reboot_attrs[] = {
13562c622ed0SMatteo Croce 	&hw_protection_attr.attr,
135740247e55SMatteo Croce 	&reboot_mode_attr.attr,
13582c622ed0SMatteo Croce #ifdef CONFIG_X86
135940247e55SMatteo Croce 	&reboot_force_attr.attr,
136040247e55SMatteo Croce 	&reboot_type_attr.attr,
136140247e55SMatteo Croce #endif
136240247e55SMatteo Croce #ifdef CONFIG_SMP
136340247e55SMatteo Croce 	&reboot_cpu_attr.attr,
13642c622ed0SMatteo Croce #endif
13652c622ed0SMatteo Croce 	NULL,
13662c622ed0SMatteo Croce };
1367764aaf44SYueHaibing 
13681751f872SJoel Granados #ifdef CONFIG_SYSCTL
1369764aaf44SYueHaibing static const struct ctl_table kern_reboot_table[] = {
1370764aaf44SYueHaibing 	{
1371764aaf44SYueHaibing 		.procname       = "poweroff_cmd",
1372764aaf44SYueHaibing 		.data           = &poweroff_cmd,
1373764aaf44SYueHaibing 		.maxlen         = POWEROFF_CMD_PATH_LEN,
1374764aaf44SYueHaibing 		.mode           = 0644,
1375764aaf44SYueHaibing 		.proc_handler   = proc_dostring,
1376764aaf44SYueHaibing 	},
1377764aaf44SYueHaibing 	{
1378764aaf44SYueHaibing 		.procname       = "ctrl-alt-del",
1379764aaf44SYueHaibing 		.data           = &C_A_D,
1380764aaf44SYueHaibing 		.maxlen         = sizeof(int),
1381764aaf44SYueHaibing 		.mode           = 0644,
1382764aaf44SYueHaibing 		.proc_handler   = proc_dointvec,
1383764aaf44SYueHaibing 	},
1384764aaf44SYueHaibing };
1385764aaf44SYueHaibing 
kernel_reboot_sysctls_init(void)1386764aaf44SYueHaibing static void __init kernel_reboot_sysctls_init(void)
1387764aaf44SYueHaibing {
1388764aaf44SYueHaibing 	register_sysctl_init("kernel", kern_reboot_table);
1389764aaf44SYueHaibing }
1390764aaf44SYueHaibing #else
1391764aaf44SYueHaibing #define kernel_reboot_sysctls_init() do { } while (0)
1392764aaf44SYueHaibing #endif /* CONFIG_SYSCTL */
13932c622ed0SMatteo Croce 
13942c622ed0SMatteo Croce static const struct attribute_group reboot_attr_group = {
13952c622ed0SMatteo Croce 	.attrs = reboot_attrs,
13962c622ed0SMatteo Croce };
13972c622ed0SMatteo Croce 
reboot_ksysfs_init(void)13982c622ed0SMatteo Croce static int __init reboot_ksysfs_init(void)
13992c622ed0SMatteo Croce {
14002c622ed0SMatteo Croce 	struct kobject *reboot_kobj;
14012c622ed0SMatteo Croce 	int ret;
14022c622ed0SMatteo Croce 
14032c622ed0SMatteo Croce 	reboot_kobj = kobject_create_and_add("reboot", kernel_kobj);
14042c622ed0SMatteo Croce 	if (!reboot_kobj)
14052c622ed0SMatteo Croce 		return -ENOMEM;
14062c622ed0SMatteo Croce 
14072c622ed0SMatteo Croce 	ret = sysfs_create_group(reboot_kobj, &reboot_attr_group);
14082c622ed0SMatteo Croce 	if (ret) {
14092c622ed0SMatteo Croce 		kobject_put(reboot_kobj);
14102c622ed0SMatteo Croce 		return ret;
14112c622ed0SMatteo Croce 	}
141206d17766Stangmeng 
141306d17766Stangmeng 	kernel_reboot_sysctls_init();
14142c622ed0SMatteo Croce 
14152c622ed0SMatteo Croce 	return 0;
14162c622ed0SMatteo Croce }
14172c622ed0SMatteo Croce late_initcall(reboot_ksysfs_init);
14182c622ed0SMatteo Croce 
1419 #endif
1420