Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'tags/restart-handler-for-v3.18' into v3.18-next/cpuclk

Immutable branch with restart handler patches for v3.18

+165 -42
+5 -7
arch/arm/kernel/process.c
··· 114 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 118 * Function pointers to optional machine specific functions 123 119 */ 124 120 void (*pm_power_off)(void); 125 121 EXPORT_SYMBOL(pm_power_off); 126 122 127 - void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd) = null_restart; 128 - EXPORT_SYMBOL_GPL(arm_pm_restart); 123 + void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); 129 124 130 125 /* 131 126 * This is our default idle handler. ··· 225 230 local_irq_disable(); 226 231 smp_send_stop(); 227 232 228 - arm_pm_restart(reboot_mode, cmd); 233 + if (arm_pm_restart) 234 + arm_pm_restart(reboot_mode, cmd); 235 + else 236 + do_kernel_restart(cmd); 229 237 230 238 /* Give a grace period for failure to restart of 1s */ 231 239 mdelay(1000);
+2 -1
arch/arm64/kernel/process.c
··· 98 98 EXPORT_SYMBOL_GPL(pm_power_off); 99 99 100 100 void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); 101 - EXPORT_SYMBOL_GPL(arm_pm_restart); 102 101 103 102 /* 104 103 * This is our default idle handler. ··· 179 180 /* Now call the architecture specific reboot code. */ 180 181 if (arm_pm_restart) 181 182 arm_pm_restart(reboot_mode, cmd); 183 + else 184 + do_kernel_restart(cmd); 182 185 183 186 /* 184 187 * Whoops - the architecture was unable to reboot.
+2 -1
drivers/power/reset/restart-poweroff.c
··· 20 20 21 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 27 static int restart_poweroff_probe(struct platform_device *pdev)
+32 -10
drivers/watchdog/alim7101_wdt.c
··· 301 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 327 * Notifier for system down 306 328 */ ··· 333 311 if (code == SYS_DOWN || code == SYS_HALT) 334 312 wdt_turnoff(); 335 313 336 - if (code == SYS_RESTART) { 337 - /* 338 - * Cobalt devices have no way of rebooting themselves other 339 - * than getting the watchdog to pull reset, so we restart the 340 - * watchdog on reboot with no heartbeat 341 - */ 342 - wdt_change(WDT_ENABLE); 343 - pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n"); 344 - } 345 314 return NOTIFY_DONE; 346 315 } 347 316 ··· 351 338 /* Deregister */ 352 339 misc_deregister(&wdt_miscdev); 353 340 unregister_reboot_notifier(&wdt_notifier); 341 + unregister_restart_handler(&wdt_restart_handler); 354 342 pci_dev_put(alim7101_pmu); 355 343 } 356 344 ··· 404 390 goto err_out; 405 391 } 406 392 393 + rc = register_restart_handler(&wdt_restart_handler); 394 + if (rc) { 395 + pr_err("cannot register restart handler (err=%d)\n", rc); 396 + goto err_out_reboot; 397 + } 398 + 407 399 rc = misc_register(&wdt_miscdev); 408 400 if (rc) { 409 401 pr_err("cannot register miscdev on minor=%d (err=%d)\n", 410 402 wdt_miscdev.minor, rc); 411 - goto err_out_reboot; 403 + goto err_out_restart; 412 404 } 413 405 414 406 if (nowayout) ··· 424 404 timeout, nowayout); 425 405 return 0; 426 406 407 + err_out_restart: 408 + unregister_restart_handler(&wdt_restart_handler); 427 409 err_out_reboot: 428 410 unregister_reboot_notifier(&wdt_notifier); 429 411 err_out:
+20 -12
drivers/watchdog/moxart_wdt.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/err.h> 17 17 #include <linux/kernel.h> 18 + #include <linux/notifier.h> 18 19 #include <linux/platform_device.h> 20 + #include <linux/reboot.h> 19 21 #include <linux/watchdog.h> 20 22 #include <linux/moduleparam.h> 21 - 22 - #include <asm/system_misc.h> 23 23 24 24 #define REG_COUNT 0x4 25 25 #define REG_MODE 0x8 ··· 29 29 struct watchdog_device dev; 30 30 void __iomem *base; 31 31 unsigned int clock_frequency; 32 + struct notifier_block restart_handler; 32 33 }; 33 - 34 - static struct moxart_wdt_dev *moxart_restart_ctx; 35 34 36 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); 41 - writel(0x5ab9, moxart_restart_ctx->base + REG_MODE); 42 - writel(0x03, moxart_restart_ctx->base + REG_ENABLE); 40 + struct moxart_wdt_dev *moxart_wdt = container_of(this, 41 + struct moxart_wdt_dev, 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 50 static int moxart_wdt_stop(struct watchdog_device *wdt_dev) ··· 141 136 if (err) 142 137 return err; 143 138 144 - moxart_restart_ctx = moxart_wdt; 145 - arm_pm_restart = moxart_wdt_restart; 139 + moxart_wdt->restart_handler.notifier_call = moxart_restart_handle; 140 + moxart_wdt->restart_handler.priority = 128; 141 + err = register_restart_handler(&moxart_wdt->restart_handler); 142 + if (err) 143 + dev_err(dev, "cannot register restart notifier (err=%d)\n", 144 + err); 146 145 147 146 dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n", 148 147 moxart_wdt->dev.timeout, nowayout); ··· 158 149 { 159 150 struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev); 160 151 161 - arm_pm_restart = NULL; 152 + unregister_restart_handler(&moxart_wdt->restart_handler); 162 153 moxart_wdt_stop(&moxart_wdt->dev); 163 - watchdog_unregister_device(&moxart_wdt->dev); 164 154 165 155 return 0; 166 156 }
+20 -11
drivers/watchdog/sunxi_wdt.c
··· 21 21 #include <linux/kernel.h> 22 22 #include <linux/module.h> 23 23 #include <linux/moduleparam.h> 24 + #include <linux/notifier.h> 24 25 #include <linux/of.h> 25 26 #include <linux/platform_device.h> 26 27 #include <linux/reboot.h> 27 28 #include <linux/types.h> 28 29 #include <linux/watchdog.h> 29 - 30 - #include <asm/system_misc.h> 31 30 32 31 #define WDT_MAX_TIMEOUT 16 33 32 #define WDT_MIN_TIMEOUT 1 ··· 49 50 struct sunxi_wdt_dev { 50 51 struct watchdog_device wdt_dev; 51 52 void __iomem *wdt_base; 53 + struct notifier_block restart_handler; 52 54 }; 53 55 54 56 /* ··· 74 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 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 90 * Restart the watchdog. The default (and lowest) interval 86 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 95 while (1) { 91 96 mdelay(5); 92 - writel(WDT_MODE_EN | WDT_MODE_RST_EN, 93 - reboot_wdt_base + WDT_MODE); 97 + writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE); 94 98 } 99 + return NOTIFY_DONE; 95 100 } 96 101 97 102 static int sunxi_wdt_ping(struct watchdog_device *wdt_dev) ··· 210 205 if (unlikely(err)) 211 206 return err; 212 207 213 - reboot_wdt_base = sunxi_wdt->wdt_base; 214 - arm_pm_restart = sun4i_wdt_restart; 208 + sunxi_wdt->restart_handler.notifier_call = sunxi_restart_handle; 209 + sunxi_wdt->restart_handler.priority = 128; 210 + err = register_restart_handler(&sunxi_wdt->restart_handler); 211 + if (err) 212 + dev_err(&pdev->dev, 213 + "cannot register restart handler (err=%d)\n", err); 215 214 216 215 dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", 217 216 sunxi_wdt->wdt_dev.timeout, nowayout); ··· 227 218 { 228 219 struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); 229 220 230 - arm_pm_restart = NULL; 221 + unregister_restart_handler(&sunxi_wdt->restart_handler); 231 222 232 223 watchdog_unregister_device(&sunxi_wdt->wdt_dev); 233 224 watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
+3
include/linux/reboot.h
··· 38 38 extern int register_reboot_notifier(struct notifier_block *); 39 39 extern int unregister_reboot_notifier(struct notifier_block *); 40 40 41 + extern int register_restart_handler(struct notifier_block *); 42 + extern int unregister_restart_handler(struct notifier_block *); 43 + extern void do_kernel_restart(char *cmd); 41 44 42 45 /* 43 46 * Architecture-specific implementations of sys_reboot commands.
+81
kernel/reboot.c
··· 104 104 } 105 105 EXPORT_SYMBOL(unregister_reboot_notifier); 106 106 107 + /* 108 + * Notifier list for kernel code which wants to be called 109 + * to restart the system. 110 + */ 111 + static ATOMIC_NOTIFIER_HEAD(restart_handler_list); 112 + 113 + /** 114 + * register_restart_handler - Register function to be called to reset 115 + * the system 116 + * @nb: Info about handler function to be called 117 + * @nb->priority: Handler priority. Handlers should follow the 118 + * following guidelines for setting priorities. 119 + * 0: Restart handler of last resort, 120 + * with limited restart capabilities 121 + * 128: Default restart handler; use if no other 122 + * restart handler is expected to be available, 123 + * and/or if restart functionality is 124 + * sufficient to restart the entire system 125 + * 255: Highest priority restart handler, will 126 + * preempt all other restart handlers 127 + * 128 + * Registers a function with code to be called to restart the 129 + * system. 130 + * 131 + * Registered functions will be called from machine_restart as last 132 + * step of the restart sequence (if the architecture specific 133 + * machine_restart function calls do_kernel_restart - see below 134 + * for details). 135 + * Registered functions are expected to restart the system immediately. 136 + * If more than one function is registered, the restart handler priority 137 + * selects which function will be called first. 138 + * 139 + * Restart handlers are expected to be registered from non-architecture 140 + * code, typically from drivers. A typical use case would be a system 141 + * where restart functionality is provided through a watchdog. Multiple 142 + * restart handlers may exist; for example, one restart handler might 143 + * restart the entire system, while another only restarts the CPU. 144 + * In such cases, the restart handler which only restarts part of the 145 + * hardware is expected to register with low priority to ensure that 146 + * it only runs if no other means to restart the system is available. 147 + * 148 + * Currently always returns zero, as atomic_notifier_chain_register() 149 + * always returns zero. 150 + */ 151 + int register_restart_handler(struct notifier_block *nb) 152 + { 153 + return atomic_notifier_chain_register(&restart_handler_list, nb); 154 + } 155 + EXPORT_SYMBOL(register_restart_handler); 156 + 157 + /** 158 + * unregister_restart_handler - Unregister previously registered 159 + * restart handler 160 + * @nb: Hook to be unregistered 161 + * 162 + * Unregisters a previously registered restart handler function. 163 + * 164 + * Returns zero on success, or %-ENOENT on failure. 165 + */ 166 + int unregister_restart_handler(struct notifier_block *nb) 167 + { 168 + return atomic_notifier_chain_unregister(&restart_handler_list, nb); 169 + } 170 + EXPORT_SYMBOL(unregister_restart_handler); 171 + 172 + /** 173 + * do_kernel_restart - Execute kernel restart handler call chain 174 + * 175 + * Calls functions registered with register_restart_handler. 176 + * 177 + * Expected to be called from machine_restart as last step of the restart 178 + * sequence. 179 + * 180 + * Restarts the system immediately if a restart handler function has been 181 + * registered. Otherwise does nothing. 182 + */ 183 + void do_kernel_restart(char *cmd) 184 + { 185 + atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd); 186 + } 187 + 107 188 void migrate_to_reboot_cpu(void) 108 189 { 109 190 /* The boot cpu is always logical cpu 0 */