diff options
-rw-r--r-- | arch/arm/kernel/process.c | 12 | ||||
-rw-r--r-- | arch/arm64/kernel/process.c | 3 | ||||
-rw-r--r-- | drivers/power/reset/restart-poweroff.c | 3 | ||||
-rw-r--r-- | drivers/watchdog/alim7101_wdt.c | 42 | ||||
-rw-r--r-- | drivers/watchdog/moxart_wdt.c | 32 | ||||
-rw-r--r-- | drivers/watchdog/sunxi_wdt.c | 31 | ||||
-rw-r--r-- | include/linux/reboot.h | 3 | ||||
-rw-r--r-- | kernel/reboot.c | 81 |
8 files changed, 165 insertions, 42 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index a0a691d1cbee..fe972a2f3df3 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -114,18 +114,13 @@ void soft_restart(unsigned long addr) | |||
114 | BUG(); | 114 | BUG(); |
115 | } | 115 | } |
116 | 116 | ||
117 | static void null_restart(enum reboot_mode reboot_mode, const char *cmd) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | /* | 117 | /* |
122 | * Function pointers to optional machine specific functions | 118 | * Function pointers to optional machine specific functions |
123 | */ | 119 | */ |
124 | void (*pm_power_off)(void); | 120 | void (*pm_power_off)(void); |
125 | EXPORT_SYMBOL(pm_power_off); | 121 | EXPORT_SYMBOL(pm_power_off); |
126 | 122 | ||
127 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd) = null_restart; | 123 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); |
128 | EXPORT_SYMBOL_GPL(arm_pm_restart); | ||
129 | 124 | ||
130 | /* | 125 | /* |
131 | * This is our default idle handler. | 126 | * This is our default idle handler. |
@@ -230,7 +225,10 @@ void machine_restart(char *cmd) | |||
230 | local_irq_disable(); | 225 | local_irq_disable(); |
231 | smp_send_stop(); | 226 | smp_send_stop(); |
232 | 227 | ||
233 | arm_pm_restart(reboot_mode, cmd); | 228 | if (arm_pm_restart) |
229 | arm_pm_restart(reboot_mode, cmd); | ||
230 | else | ||
231 | do_kernel_restart(cmd); | ||
234 | 232 | ||
235 | /* Give a grace period for failure to restart of 1s */ | 233 | /* Give a grace period for failure to restart of 1s */ |
236 | mdelay(1000); | 234 | mdelay(1000); |
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 89f41f7d27dd..c3065dbc4fa2 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c | |||
@@ -72,7 +72,6 @@ void (*pm_power_off)(void); | |||
72 | EXPORT_SYMBOL_GPL(pm_power_off); | 72 | EXPORT_SYMBOL_GPL(pm_power_off); |
73 | 73 | ||
74 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); | 74 | void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); |
75 | EXPORT_SYMBOL_GPL(arm_pm_restart); | ||
76 | 75 | ||
77 | /* | 76 | /* |
78 | * This is our default idle handler. | 77 | * This is our default idle handler. |
@@ -154,6 +153,8 @@ void machine_restart(char *cmd) | |||
154 | /* Now call the architecture specific reboot code. */ | 153 | /* Now call the architecture specific reboot code. */ |
155 | if (arm_pm_restart) | 154 | if (arm_pm_restart) |
156 | arm_pm_restart(reboot_mode, cmd); | 155 | arm_pm_restart(reboot_mode, cmd); |
156 | else | ||
157 | do_kernel_restart(cmd); | ||
157 | 158 | ||
158 | /* | 159 | /* |
159 | * Whoops - the architecture was unable to reboot. | 160 | * Whoops - the architecture was unable to reboot. |
diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index 3e51f8d29bfe..edd707ee7281 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c | |||
@@ -20,7 +20,8 @@ | |||
20 | 20 | ||
21 | static void restart_poweroff_do_poweroff(void) | 21 | static void restart_poweroff_do_poweroff(void) |
22 | { | 22 | { |
23 | arm_pm_restart(REBOOT_HARD, NULL); | 23 | reboot_mode = REBOOT_HARD; |
24 | machine_restart(NULL); | ||
24 | } | 25 | } |
25 | 26 | ||
26 | static int restart_poweroff_probe(struct platform_device *pdev) | 27 | static int restart_poweroff_probe(struct platform_device *pdev) |
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index 996b2f7d330e..665e0e7dfe1e 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c | |||
@@ -301,6 +301,28 @@ static struct miscdevice wdt_miscdev = { | |||
301 | .fops = &wdt_fops, | 301 | .fops = &wdt_fops, |
302 | }; | 302 | }; |
303 | 303 | ||
304 | static int wdt_restart_handle(struct notifier_block *this, unsigned long mode, | ||
305 | void *cmd) | ||
306 | { | ||
307 | /* | ||
308 | * Cobalt devices have no way of rebooting themselves other | ||
309 | * than getting the watchdog to pull reset, so we restart the | ||
310 | * watchdog on reboot with no heartbeat. | ||
311 | */ | ||
312 | wdt_change(WDT_ENABLE); | ||
313 | |||
314 | /* loop until the watchdog fires */ | ||
315 | while (true) | ||
316 | ; | ||
317 | |||
318 | return NOTIFY_DONE; | ||
319 | } | ||
320 | |||
321 | static struct notifier_block wdt_restart_handler = { | ||
322 | .notifier_call = wdt_restart_handle, | ||
323 | .priority = 128, | ||
324 | }; | ||
325 | |||
304 | /* | 326 | /* |
305 | * Notifier for system down | 327 | * Notifier for system down |
306 | */ | 328 | */ |
@@ -311,15 +333,6 @@ static int wdt_notify_sys(struct notifier_block *this, | |||
311 | if (code == SYS_DOWN || code == SYS_HALT) | 333 | if (code == SYS_DOWN || code == SYS_HALT) |
312 | wdt_turnoff(); | 334 | wdt_turnoff(); |
313 | 335 | ||
314 | if (code == SYS_RESTART) { | ||
315 | /* | ||
316 | * Cobalt devices have no way of rebooting themselves other | ||
317 | * than getting the watchdog to pull reset, so we restart the | ||
318 | * watchdog on reboot with no heartbeat | ||
319 | */ | ||
320 | wdt_change(WDT_ENABLE); | ||
321 | pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n"); | ||
322 | } | ||
323 | return NOTIFY_DONE; | 336 | return NOTIFY_DONE; |
324 | } | 337 | } |
325 | 338 | ||
@@ -338,6 +351,7 @@ static void __exit alim7101_wdt_unload(void) | |||
338 | /* Deregister */ | 351 | /* Deregister */ |
339 | misc_deregister(&wdt_miscdev); | 352 | misc_deregister(&wdt_miscdev); |
340 | unregister_reboot_notifier(&wdt_notifier); | 353 | unregister_reboot_notifier(&wdt_notifier); |
354 | unregister_restart_handler(&wdt_restart_handler); | ||
341 | pci_dev_put(alim7101_pmu); | 355 | pci_dev_put(alim7101_pmu); |
342 | } | 356 | } |
343 | 357 | ||
@@ -390,11 +404,17 @@ static int __init alim7101_wdt_init(void) | |||
390 | goto err_out; | 404 | goto err_out; |
391 | } | 405 | } |
392 | 406 | ||
407 | rc = register_restart_handler(&wdt_restart_handler); | ||
408 | if (rc) { | ||
409 | pr_err("cannot register restart handler (err=%d)\n", rc); | ||
410 | goto err_out_reboot; | ||
411 | } | ||
412 | |||
393 | rc = misc_register(&wdt_miscdev); | 413 | rc = misc_register(&wdt_miscdev); |
394 | if (rc) { | 414 | if (rc) { |
395 | pr_err("cannot register miscdev on minor=%d (err=%d)\n", | 415 | pr_err("cannot register miscdev on minor=%d (err=%d)\n", |
396 | wdt_miscdev.minor, rc); | 416 | wdt_miscdev.minor, rc); |
397 | goto err_out_reboot; | 417 | goto err_out_restart; |
398 | } | 418 | } |
399 | 419 | ||
400 | if (nowayout) | 420 | if (nowayout) |
@@ -404,6 +424,8 @@ static int __init alim7101_wdt_init(void) | |||
404 | timeout, nowayout); | 424 | timeout, nowayout); |
405 | return 0; | 425 | return 0; |
406 | 426 | ||
427 | err_out_restart: | ||
428 | unregister_restart_handler(&wdt_restart_handler); | ||
407 | err_out_reboot: | 429 | err_out_reboot: |
408 | unregister_reboot_notifier(&wdt_notifier); | 430 | unregister_reboot_notifier(&wdt_notifier); |
409 | err_out: | 431 | err_out: |
diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c index 4aa3a8a876fe..a64405b82596 100644 --- a/drivers/watchdog/moxart_wdt.c +++ b/drivers/watchdog/moxart_wdt.c | |||
@@ -15,12 +15,12 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/notifier.h> | ||
18 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/reboot.h> | ||
19 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
20 | #include <linux/moduleparam.h> | 22 | #include <linux/moduleparam.h> |
21 | 23 | ||
22 | #include <asm/system_misc.h> | ||
23 | |||
24 | #define REG_COUNT 0x4 | 24 | #define REG_COUNT 0x4 |
25 | #define REG_MODE 0x8 | 25 | #define REG_MODE 0x8 |
26 | #define REG_ENABLE 0xC | 26 | #define REG_ENABLE 0xC |
@@ -29,17 +29,22 @@ struct moxart_wdt_dev { | |||
29 | struct watchdog_device dev; | 29 | struct watchdog_device dev; |
30 | void __iomem *base; | 30 | void __iomem *base; |
31 | unsigned int clock_frequency; | 31 | unsigned int clock_frequency; |
32 | struct notifier_block restart_handler; | ||
32 | }; | 33 | }; |
33 | 34 | ||
34 | static struct moxart_wdt_dev *moxart_restart_ctx; | ||
35 | |||
36 | static int heartbeat; | 35 | static int heartbeat; |
37 | 36 | ||
38 | static void moxart_wdt_restart(enum reboot_mode reboot_mode, const char *cmd) | 37 | static int moxart_restart_handle(struct notifier_block *this, |
38 | unsigned long mode, void *cmd) | ||
39 | { | 39 | { |
40 | writel(1, moxart_restart_ctx->base + REG_COUNT); | 40 | struct moxart_wdt_dev *moxart_wdt = container_of(this, |
41 | writel(0x5ab9, moxart_restart_ctx->base + REG_MODE); | 41 | struct moxart_wdt_dev, |
42 | writel(0x03, moxart_restart_ctx->base + REG_ENABLE); | 42 | restart_handler); |
43 | writel(1, moxart_wdt->base + REG_COUNT); | ||
44 | writel(0x5ab9, moxart_wdt->base + REG_MODE); | ||
45 | writel(0x03, moxart_wdt->base + REG_ENABLE); | ||
46 | |||
47 | return NOTIFY_DONE; | ||
43 | } | 48 | } |
44 | 49 | ||
45 | static int moxart_wdt_stop(struct watchdog_device *wdt_dev) | 50 | static int moxart_wdt_stop(struct watchdog_device *wdt_dev) |
@@ -136,8 +141,12 @@ static int moxart_wdt_probe(struct platform_device *pdev) | |||
136 | if (err) | 141 | if (err) |
137 | return err; | 142 | return err; |
138 | 143 | ||
139 | moxart_restart_ctx = moxart_wdt; | 144 | moxart_wdt->restart_handler.notifier_call = moxart_restart_handle; |
140 | arm_pm_restart = moxart_wdt_restart; | 145 | moxart_wdt->restart_handler.priority = 128; |
146 | err = register_restart_handler(&moxart_wdt->restart_handler); | ||
147 | if (err) | ||
148 | dev_err(dev, "cannot register restart notifier (err=%d)\n", | ||
149 | err); | ||
141 | 150 | ||
142 | dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n", | 151 | dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n", |
143 | moxart_wdt->dev.timeout, nowayout); | 152 | moxart_wdt->dev.timeout, nowayout); |
@@ -149,9 +158,8 @@ static int moxart_wdt_remove(struct platform_device *pdev) | |||
149 | { | 158 | { |
150 | struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev); | 159 | struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev); |
151 | 160 | ||
152 | arm_pm_restart = NULL; | 161 | unregister_restart_handler(&moxart_wdt->restart_handler); |
153 | moxart_wdt_stop(&moxart_wdt->dev); | 162 | moxart_wdt_stop(&moxart_wdt->dev); |
154 | watchdog_unregister_device(&moxart_wdt->dev); | ||
155 | 163 | ||
156 | return 0; | 164 | return 0; |
157 | } | 165 | } |
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index 60deb9d304c0..480bb557f353 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c | |||
@@ -21,14 +21,13 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
24 | #include <linux/notifier.h> | ||
24 | #include <linux/of.h> | 25 | #include <linux/of.h> |
25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
26 | #include <linux/reboot.h> | 27 | #include <linux/reboot.h> |
27 | #include <linux/types.h> | 28 | #include <linux/types.h> |
28 | #include <linux/watchdog.h> | 29 | #include <linux/watchdog.h> |
29 | 30 | ||
30 | #include <asm/system_misc.h> | ||
31 | |||
32 | #define WDT_MAX_TIMEOUT 16 | 31 | #define WDT_MAX_TIMEOUT 16 |
33 | #define WDT_MIN_TIMEOUT 1 | 32 | #define WDT_MIN_TIMEOUT 1 |
34 | #define WDT_MODE_TIMEOUT(n) ((n) << 3) | 33 | #define WDT_MODE_TIMEOUT(n) ((n) << 3) |
@@ -50,6 +49,7 @@ static unsigned int timeout = WDT_MAX_TIMEOUT; | |||
50 | struct sunxi_wdt_dev { | 49 | struct sunxi_wdt_dev { |
51 | struct watchdog_device wdt_dev; | 50 | struct watchdog_device wdt_dev; |
52 | void __iomem *wdt_base; | 51 | void __iomem *wdt_base; |
52 | struct notifier_block restart_handler; | ||
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* | 55 | /* |
@@ -74,24 +74,29 @@ static const int wdt_timeout_map[] = { | |||
74 | [16] = 0xB, /* 16s */ | 74 | [16] = 0xB, /* 16s */ |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static void __iomem *reboot_wdt_base; | ||
78 | 77 | ||
79 | static void sun4i_wdt_restart(enum reboot_mode mode, const char *cmd) | 78 | static int sunxi_restart_handle(struct notifier_block *this, unsigned long mode, |
79 | void *cmd) | ||
80 | { | 80 | { |
81 | struct sunxi_wdt_dev *sunxi_wdt = container_of(this, | ||
82 | struct sunxi_wdt_dev, | ||
83 | restart_handler); | ||
84 | void __iomem *wdt_base = sunxi_wdt->wdt_base; | ||
85 | |||
81 | /* Enable timer and set reset bit in the watchdog */ | 86 | /* Enable timer and set reset bit in the watchdog */ |
82 | writel(WDT_MODE_EN | WDT_MODE_RST_EN, reboot_wdt_base + WDT_MODE); | 87 | writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE); |
83 | 88 | ||
84 | /* | 89 | /* |
85 | * Restart the watchdog. The default (and lowest) interval | 90 | * Restart the watchdog. The default (and lowest) interval |
86 | * value for the watchdog is 0.5s. | 91 | * value for the watchdog is 0.5s. |
87 | */ | 92 | */ |
88 | writel(WDT_CTRL_RELOAD, reboot_wdt_base + WDT_CTRL); | 93 | writel(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL); |
89 | 94 | ||
90 | while (1) { | 95 | while (1) { |
91 | mdelay(5); | 96 | mdelay(5); |
92 | writel(WDT_MODE_EN | WDT_MODE_RST_EN, | 97 | writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE); |
93 | reboot_wdt_base + WDT_MODE); | ||
94 | } | 98 | } |
99 | return NOTIFY_DONE; | ||
95 | } | 100 | } |
96 | 101 | ||
97 | static int sunxi_wdt_ping(struct watchdog_device *wdt_dev) | 102 | static int sunxi_wdt_ping(struct watchdog_device *wdt_dev) |
@@ -205,8 +210,12 @@ static int sunxi_wdt_probe(struct platform_device *pdev) | |||
205 | if (unlikely(err)) | 210 | if (unlikely(err)) |
206 | return err; | 211 | return err; |
207 | 212 | ||
208 | reboot_wdt_base = sunxi_wdt->wdt_base; | 213 | sunxi_wdt->restart_handler.notifier_call = sunxi_restart_handle; |
209 | arm_pm_restart = sun4i_wdt_restart; | 214 | sunxi_wdt->restart_handler.priority = 128; |
215 | err = register_restart_handler(&sunxi_wdt->restart_handler); | ||
216 | if (err) | ||
217 | dev_err(&pdev->dev, | ||
218 | "cannot register restart handler (err=%d)\n", err); | ||
210 | 219 | ||
211 | dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", | 220 | dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", |
212 | sunxi_wdt->wdt_dev.timeout, nowayout); | 221 | sunxi_wdt->wdt_dev.timeout, nowayout); |
@@ -218,7 +227,7 @@ static int sunxi_wdt_remove(struct platform_device *pdev) | |||
218 | { | 227 | { |
219 | struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); | 228 | struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); |
220 | 229 | ||
221 | arm_pm_restart = NULL; | 230 | unregister_restart_handler(&sunxi_wdt->restart_handler); |
222 | 231 | ||
223 | watchdog_unregister_device(&sunxi_wdt->wdt_dev); | 232 | watchdog_unregister_device(&sunxi_wdt->wdt_dev); |
224 | watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL); | 233 | watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL); |
diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 48bf152761c7..67fc8fcdc4b0 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h | |||
@@ -38,6 +38,9 @@ extern int reboot_force; | |||
38 | extern int register_reboot_notifier(struct notifier_block *); | 38 | extern int register_reboot_notifier(struct notifier_block *); |
39 | extern int unregister_reboot_notifier(struct notifier_block *); | 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 | * Architecture-specific implementations of sys_reboot commands. | 46 | * Architecture-specific implementations of sys_reboot commands. |
diff --git a/kernel/reboot.c b/kernel/reboot.c index a3a9e240fcdb..5925f5ae8dff 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c | |||
@@ -104,6 +104,87 @@ int unregister_reboot_notifier(struct notifier_block *nb) | |||
104 | } | 104 | } |
105 | EXPORT_SYMBOL(unregister_reboot_notifier); | 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 | void migrate_to_reboot_cpu(void) | 188 | void migrate_to_reboot_cpu(void) |
108 | { | 189 | { |
109 | /* The boot cpu is always logical cpu 0 */ | 190 | /* The boot cpu is always logical cpu 0 */ |