1ec9b2065SIsaku Yamahata /* 2ec9b2065SIsaku Yamahata * Handle extern requests for shutdown, reboot and sysrq 3ec9b2065SIsaku Yamahata */ 4283c0972SJoe Perches 5283c0972SJoe Perches #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 6283c0972SJoe Perches 7ec9b2065SIsaku Yamahata #include <linux/kernel.h> 8ec9b2065SIsaku Yamahata #include <linux/err.h> 95a0e3ad6STejun Heo #include <linux/slab.h> 10ec9b2065SIsaku Yamahata #include <linux/reboot.h> 11ec9b2065SIsaku Yamahata #include <linux/sysrq.h> 120e91398fSJeremy Fitzhardinge #include <linux/stop_machine.h> 130e91398fSJeremy Fitzhardinge #include <linux/freezer.h> 1419234c08SRafael J. Wysocki #include <linux/syscore_ops.h> 1563c9744bSPaul Gortmaker #include <linux/export.h> 16ec9b2065SIsaku Yamahata 17016b6f5fSStefano Stabellini #include <xen/xen.h> 18ec9b2065SIsaku Yamahata #include <xen/xenbus.h> 190e91398fSJeremy Fitzhardinge #include <xen/grant_table.h> 200e91398fSJeremy Fitzhardinge #include <xen/events.h> 210e91398fSJeremy Fitzhardinge #include <xen/hvc-console.h> 22a9fd60e2SJulien Grall #include <xen/page.h> 230e91398fSJeremy Fitzhardinge #include <xen/xen-ops.h> 24ec9b2065SIsaku Yamahata 250e91398fSJeremy Fitzhardinge #include <asm/xen/hypercall.h> 26016b6f5fSStefano Stabellini #include <asm/xen/hypervisor.h> 270e91398fSJeremy Fitzhardinge 280e91398fSJeremy Fitzhardinge enum shutdown_state { 290e91398fSJeremy Fitzhardinge SHUTDOWN_INVALID = -1, 300e91398fSJeremy Fitzhardinge SHUTDOWN_POWEROFF = 0, 310e91398fSJeremy Fitzhardinge SHUTDOWN_SUSPEND = 2, 32ec9b2065SIsaku Yamahata /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 330e91398fSJeremy Fitzhardinge report a crash, not be instructed to crash! 340e91398fSJeremy Fitzhardinge HALT is the same as POWEROFF, as far as we're concerned. The tools use 350e91398fSJeremy Fitzhardinge the distinction when we return the reason code to them. */ 360e91398fSJeremy Fitzhardinge SHUTDOWN_HALT = 4, 370e91398fSJeremy Fitzhardinge }; 38ec9b2065SIsaku Yamahata 39ec9b2065SIsaku Yamahata /* Ignore multiple shutdown requests. */ 400e91398fSJeremy Fitzhardinge static enum shutdown_state shutting_down = SHUTDOWN_INVALID; 410e91398fSJeremy Fitzhardinge 42ceb18029SIan Campbell struct suspend_info { 43ceb18029SIan Campbell int cancelled; 44ceb18029SIan Campbell }; 45ceb18029SIan Campbell 46cd979883SStanislaw Gruszka static RAW_NOTIFIER_HEAD(xen_resume_notifier); 47cd979883SStanislaw Gruszka 48cd979883SStanislaw Gruszka void xen_resume_notifier_register(struct notifier_block *nb) 49cd979883SStanislaw Gruszka { 50cd979883SStanislaw Gruszka raw_notifier_chain_register(&xen_resume_notifier, nb); 51cd979883SStanislaw Gruszka } 52cd979883SStanislaw Gruszka EXPORT_SYMBOL_GPL(xen_resume_notifier_register); 53cd979883SStanislaw Gruszka 54cd979883SStanislaw Gruszka void xen_resume_notifier_unregister(struct notifier_block *nb) 55cd979883SStanislaw Gruszka { 56cd979883SStanislaw Gruszka raw_notifier_chain_unregister(&xen_resume_notifier, nb); 57cd979883SStanislaw Gruszka } 58cd979883SStanislaw Gruszka EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister); 59cd979883SStanislaw Gruszka 6065e053a7SStefano Stabellini #ifdef CONFIG_HIBERNATE_CALLBACKS 610e91398fSJeremy Fitzhardinge static int xen_suspend(void *data) 620e91398fSJeremy Fitzhardinge { 63ceb18029SIan Campbell struct suspend_info *si = data; 64359cdd3fSJeremy Fitzhardinge int err; 650e91398fSJeremy Fitzhardinge 660e91398fSJeremy Fitzhardinge BUG_ON(!irqs_disabled()); 670e91398fSJeremy Fitzhardinge 6819234c08SRafael J. Wysocki err = syscore_suspend(); 69770824bdSRafael J. Wysocki if (err) { 70283c0972SJoe Perches pr_err("%s: system core suspend failed: %d\n", __func__, err); 71770824bdSRafael J. Wysocki return err; 72770824bdSRafael J. Wysocki } 73359cdd3fSJeremy Fitzhardinge 74aa8532c3SDavid Vrabel gnttab_suspend(); 755e25f5dbSDongli Zhang xen_manage_runstate_time(-1); 76aa8532c3SDavid Vrabel xen_arch_pre_suspend(); 770e91398fSJeremy Fitzhardinge 78aa8532c3SDavid Vrabel si->cancelled = HYPERVISOR_suspend(xen_pv_domain() 790df4f266SJulien Grall ? virt_to_gfn(xen_start_info) 80aa8532c3SDavid Vrabel : 0); 810e91398fSJeremy Fitzhardinge 82aa8532c3SDavid Vrabel xen_arch_post_suspend(si->cancelled); 835e25f5dbSDongli Zhang xen_manage_runstate_time(si->cancelled ? 1 : 0); 84aa8532c3SDavid Vrabel gnttab_resume(); 850e91398fSJeremy Fitzhardinge 86ceb18029SIan Campbell if (!si->cancelled) { 870e91398fSJeremy Fitzhardinge xen_irq_resume(); 88ad55db9fSIsaku Yamahata xen_timer_resume(); 890e91398fSJeremy Fitzhardinge } 900e91398fSJeremy Fitzhardinge 9119234c08SRafael J. Wysocki syscore_resume(); 921e6fcf84SIan Campbell 930e91398fSJeremy Fitzhardinge return 0; 940e91398fSJeremy Fitzhardinge } 950e91398fSJeremy Fitzhardinge 960e91398fSJeremy Fitzhardinge static void do_suspend(void) 970e91398fSJeremy Fitzhardinge { 980e91398fSJeremy Fitzhardinge int err; 99ceb18029SIan Campbell struct suspend_info si; 1000e91398fSJeremy Fitzhardinge 1010e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_SUSPEND; 1020e91398fSJeremy Fitzhardinge 1030e91398fSJeremy Fitzhardinge err = freeze_processes(); 1040e91398fSJeremy Fitzhardinge if (err) { 10572978b2fSRoss Lagerwall pr_err("%s: freeze processes failed %d\n", __func__, err); 1063fc1f1e2STejun Heo goto out; 1070e91398fSJeremy Fitzhardinge } 1080e91398fSJeremy Fitzhardinge 10972978b2fSRoss Lagerwall err = freeze_kernel_threads(); 11072978b2fSRoss Lagerwall if (err) { 11172978b2fSRoss Lagerwall pr_err("%s: freeze kernel threads failed %d\n", __func__, err); 11272978b2fSRoss Lagerwall goto out_thaw; 11372978b2fSRoss Lagerwall } 11472978b2fSRoss Lagerwall 115b3e96c0cSShriram Rajagopalan err = dpm_suspend_start(PMSG_FREEZE); 1160e91398fSJeremy Fitzhardinge if (err) { 117283c0972SJoe Perches pr_err("%s: dpm_suspend_start %d\n", __func__, err); 11865f63384SIan Campbell goto out_thaw; 1190e91398fSJeremy Fitzhardinge } 1200e91398fSJeremy Fitzhardinge 121c5cae661SIan Campbell printk(KERN_DEBUG "suspending xenstore...\n"); 122c5cae661SIan Campbell xs_suspend(); 123c5cae661SIan Campbell 124cf579dfbSRafael J. Wysocki err = dpm_suspend_end(PMSG_FREEZE); 1252ed8d2b3SRafael J. Wysocki if (err) { 126283c0972SJoe Perches pr_err("dpm_suspend_end failed: %d\n", err); 127186bab1cSKonrad Rzeszutek Wilk si.cancelled = 0; 12865f63384SIan Campbell goto out_resume; 1292ed8d2b3SRafael J. Wysocki } 1302ed8d2b3SRafael J. Wysocki 1312b953a5eSBoris Ostrovsky xen_arch_suspend(); 1322b953a5eSBoris Ostrovsky 133ceb18029SIan Campbell si.cancelled = 1; 134ceb18029SIan Campbell 135ceb18029SIan Campbell err = stop_machine(xen_suspend, &si, cpumask_of(0)); 136922cc38aSJeremy Fitzhardinge 1371b647823SDavid Vrabel /* Resume console as early as possible. */ 1381b647823SDavid Vrabel if (!si.cancelled) 1391b647823SDavid Vrabel xen_console_resume(); 1401b647823SDavid Vrabel 141cd979883SStanislaw Gruszka raw_notifier_call_chain(&xen_resume_notifier, 0, NULL); 142cd979883SStanislaw Gruszka 143cf579dfbSRafael J. Wysocki dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 144922cc38aSJeremy Fitzhardinge 1450e91398fSJeremy Fitzhardinge if (err) { 146283c0972SJoe Perches pr_err("failed to start xen_suspend: %d\n", err); 147ceb18029SIan Campbell si.cancelled = 1; 1480e91398fSJeremy Fitzhardinge } 1490e91398fSJeremy Fitzhardinge 150ad55db9fSIsaku Yamahata xen_arch_resume(); 1512b953a5eSBoris Ostrovsky 1522b953a5eSBoris Ostrovsky out_resume: 1532b953a5eSBoris Ostrovsky if (!si.cancelled) 154de5b31bdSIan Campbell xs_resume(); 1552b953a5eSBoris Ostrovsky else 156de5b31bdSIan Campbell xs_suspend_cancel(); 1570e91398fSJeremy Fitzhardinge 158b3e96c0cSShriram Rajagopalan dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 1590e91398fSJeremy Fitzhardinge 16065f63384SIan Campbell out_thaw: 1610e91398fSJeremy Fitzhardinge thaw_processes(); 16265f63384SIan Campbell out: 1630e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 1640e91398fSJeremy Fitzhardinge } 1651f112ceeSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 166ec9b2065SIsaku Yamahata 16755271723SIan Campbell struct shutdown_handler { 16844b3c7afSJuergen Gross #define SHUTDOWN_CMD_SIZE 11 16944b3c7afSJuergen Gross const char command[SHUTDOWN_CMD_SIZE]; 17044b3c7afSJuergen Gross bool flag; 17155271723SIan Campbell void (*cb)(void); 17255271723SIan Campbell }; 17355271723SIan Campbell 174eb47f712SKonrad Rzeszutek Wilk static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused) 175eb47f712SKonrad Rzeszutek Wilk { 176eb47f712SKonrad Rzeszutek Wilk switch (code) { 177eb47f712SKonrad Rzeszutek Wilk case SYS_DOWN: 178eb47f712SKonrad Rzeszutek Wilk case SYS_HALT: 179eb47f712SKonrad Rzeszutek Wilk case SYS_POWER_OFF: 180eb47f712SKonrad Rzeszutek Wilk shutting_down = SHUTDOWN_POWEROFF; 181eb47f712SKonrad Rzeszutek Wilk default: 182eb47f712SKonrad Rzeszutek Wilk break; 183eb47f712SKonrad Rzeszutek Wilk } 184eb47f712SKonrad Rzeszutek Wilk return NOTIFY_DONE; 185eb47f712SKonrad Rzeszutek Wilk } 18655271723SIan Campbell static void do_poweroff(void) 18755271723SIan Campbell { 188eb47f712SKonrad Rzeszutek Wilk switch (system_state) { 189eb47f712SKonrad Rzeszutek Wilk case SYSTEM_BOOTING: 19069a78ff2SThomas Gleixner case SYSTEM_SCHEDULING: 191eb47f712SKonrad Rzeszutek Wilk orderly_poweroff(true); 192eb47f712SKonrad Rzeszutek Wilk break; 193eb47f712SKonrad Rzeszutek Wilk case SYSTEM_RUNNING: 19455271723SIan Campbell orderly_poweroff(false); 195eb47f712SKonrad Rzeszutek Wilk break; 196eb47f712SKonrad Rzeszutek Wilk default: 197eb47f712SKonrad Rzeszutek Wilk /* Don't do it when we are halting/rebooting. */ 198eb47f712SKonrad Rzeszutek Wilk pr_info("Ignoring Xen toolstack shutdown.\n"); 199eb47f712SKonrad Rzeszutek Wilk break; 200eb47f712SKonrad Rzeszutek Wilk } 20155271723SIan Campbell } 20255271723SIan Campbell 20355271723SIan Campbell static void do_reboot(void) 20455271723SIan Campbell { 20555271723SIan Campbell shutting_down = SHUTDOWN_POWEROFF; /* ? */ 20655271723SIan Campbell ctrl_alt_del(); 20755271723SIan Campbell } 20855271723SIan Campbell 20944b3c7afSJuergen Gross static struct shutdown_handler shutdown_handlers[] = { 21044b3c7afSJuergen Gross { "poweroff", true, do_poweroff }, 21144b3c7afSJuergen Gross { "halt", false, do_poweroff }, 21244b3c7afSJuergen Gross { "reboot", true, do_reboot }, 21344b3c7afSJuergen Gross #ifdef CONFIG_HIBERNATE_CALLBACKS 21444b3c7afSJuergen Gross { "suspend", true, do_suspend }, 21544b3c7afSJuergen Gross #endif 21644b3c7afSJuergen Gross }; 21744b3c7afSJuergen Gross 218ec9b2065SIsaku Yamahata static void shutdown_handler(struct xenbus_watch *watch, 2195584ea25SJuergen Gross const char *path, const char *token) 220ec9b2065SIsaku Yamahata { 221ec9b2065SIsaku Yamahata char *str; 222ec9b2065SIsaku Yamahata struct xenbus_transaction xbt; 223ec9b2065SIsaku Yamahata int err; 22444b3c7afSJuergen Gross int idx; 225ec9b2065SIsaku Yamahata 226ec9b2065SIsaku Yamahata if (shutting_down != SHUTDOWN_INVALID) 227ec9b2065SIsaku Yamahata return; 228ec9b2065SIsaku Yamahata 229ec9b2065SIsaku Yamahata again: 230ec9b2065SIsaku Yamahata err = xenbus_transaction_start(&xbt); 231ec9b2065SIsaku Yamahata if (err) 232ec9b2065SIsaku Yamahata return; 233ec9b2065SIsaku Yamahata 234ec9b2065SIsaku Yamahata str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); 235ec9b2065SIsaku Yamahata /* Ignore read errors and empty reads. */ 236ec9b2065SIsaku Yamahata if (XENBUS_IS_ERR_READ(str)) { 237ec9b2065SIsaku Yamahata xenbus_transaction_end(xbt, 1); 238ec9b2065SIsaku Yamahata return; 239ec9b2065SIsaku Yamahata } 240ec9b2065SIsaku Yamahata 24144b3c7afSJuergen Gross for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) { 24244b3c7afSJuergen Gross if (strcmp(str, shutdown_handlers[idx].command) == 0) 24355271723SIan Campbell break; 24455271723SIan Campbell } 24555271723SIan Campbell 24655271723SIan Campbell /* Only acknowledge commands which we are prepared to handle. */ 24744b3c7afSJuergen Gross if (idx < ARRAY_SIZE(shutdown_handlers)) 248ec9b2065SIsaku Yamahata xenbus_write(xbt, "control", "shutdown", ""); 249ec9b2065SIsaku Yamahata 250ec9b2065SIsaku Yamahata err = xenbus_transaction_end(xbt, 0); 251ec9b2065SIsaku Yamahata if (err == -EAGAIN) { 252ec9b2065SIsaku Yamahata kfree(str); 253ec9b2065SIsaku Yamahata goto again; 254ec9b2065SIsaku Yamahata } 255ec9b2065SIsaku Yamahata 25644b3c7afSJuergen Gross if (idx < ARRAY_SIZE(shutdown_handlers)) { 25744b3c7afSJuergen Gross shutdown_handlers[idx].cb(); 2580e91398fSJeremy Fitzhardinge } else { 259283c0972SJoe Perches pr_info("Ignoring shutdown request: %s\n", str); 260ec9b2065SIsaku Yamahata shutting_down = SHUTDOWN_INVALID; 261ec9b2065SIsaku Yamahata } 262ec9b2065SIsaku Yamahata 263ec9b2065SIsaku Yamahata kfree(str); 264ec9b2065SIsaku Yamahata } 265ec9b2065SIsaku Yamahata 266f3bc3189SRandy Dunlap #ifdef CONFIG_MAGIC_SYSRQ 2675584ea25SJuergen Gross static void sysrq_handler(struct xenbus_watch *watch, const char *path, 2685584ea25SJuergen Gross const char *token) 269ec9b2065SIsaku Yamahata { 270ec9b2065SIsaku Yamahata char sysrq_key = '\0'; 271ec9b2065SIsaku Yamahata struct xenbus_transaction xbt; 272ec9b2065SIsaku Yamahata int err; 273ec9b2065SIsaku Yamahata 274ec9b2065SIsaku Yamahata again: 275ec9b2065SIsaku Yamahata err = xenbus_transaction_start(&xbt); 276ec9b2065SIsaku Yamahata if (err) 277ec9b2065SIsaku Yamahata return; 2784e93b648SJuergen Gross err = xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key); 2794e93b648SJuergen Gross if (err < 0) { 2804e93b648SJuergen Gross /* 2814e93b648SJuergen Gross * The Xenstore watch fires directly after registering it and 2824e93b648SJuergen Gross * after a suspend/resume cycle. So ENOENT is no error but 28387dffe86SVitaly Kuznetsov * might happen in those cases. ERANGE is observed when we get 28487dffe86SVitaly Kuznetsov * an empty value (''), this happens when we acknowledge the 28587dffe86SVitaly Kuznetsov * request by writing '\0' below. 2864e93b648SJuergen Gross */ 28787dffe86SVitaly Kuznetsov if (err != -ENOENT && err != -ERANGE) 2884e93b648SJuergen Gross pr_err("Error %d reading sysrq code in control/sysrq\n", 2894e93b648SJuergen Gross err); 290ec9b2065SIsaku Yamahata xenbus_transaction_end(xbt, 1); 291ec9b2065SIsaku Yamahata return; 292ec9b2065SIsaku Yamahata } 293ec9b2065SIsaku Yamahata 29484c029a7SZhouyang Jia if (sysrq_key != '\0') { 29584c029a7SZhouyang Jia err = xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); 29684c029a7SZhouyang Jia if (err) { 29784c029a7SZhouyang Jia pr_err("%s: Error %d writing sysrq in control/sysrq\n", 29884c029a7SZhouyang Jia __func__, err); 29984c029a7SZhouyang Jia xenbus_transaction_end(xbt, 1); 30084c029a7SZhouyang Jia return; 30184c029a7SZhouyang Jia } 30284c029a7SZhouyang Jia } 303ec9b2065SIsaku Yamahata 304ec9b2065SIsaku Yamahata err = xenbus_transaction_end(xbt, 0); 305ec9b2065SIsaku Yamahata if (err == -EAGAIN) 306ec9b2065SIsaku Yamahata goto again; 307ec9b2065SIsaku Yamahata 308ec9b2065SIsaku Yamahata if (sysrq_key != '\0') 309f335397dSDmitry Torokhov handle_sysrq(sysrq_key); 310ec9b2065SIsaku Yamahata } 311ec9b2065SIsaku Yamahata 312ec9b2065SIsaku Yamahata static struct xenbus_watch sysrq_watch = { 313ec9b2065SIsaku Yamahata .node = "control/sysrq", 314ec9b2065SIsaku Yamahata .callback = sysrq_handler 315ec9b2065SIsaku Yamahata }; 316f3bc3189SRandy Dunlap #endif 317f3bc3189SRandy Dunlap 318f3bc3189SRandy Dunlap static struct xenbus_watch shutdown_watch = { 319f3bc3189SRandy Dunlap .node = "control/shutdown", 320f3bc3189SRandy Dunlap .callback = shutdown_handler 321f3bc3189SRandy Dunlap }; 322ec9b2065SIsaku Yamahata 323eb47f712SKonrad Rzeszutek Wilk static struct notifier_block xen_reboot_nb = { 324eb47f712SKonrad Rzeszutek Wilk .notifier_call = poweroff_nb, 325eb47f712SKonrad Rzeszutek Wilk }; 326eb47f712SKonrad Rzeszutek Wilk 327ec9b2065SIsaku Yamahata static int setup_shutdown_watcher(void) 328ec9b2065SIsaku Yamahata { 329ec9b2065SIsaku Yamahata int err; 33044b3c7afSJuergen Gross int idx; 33144b3c7afSJuergen Gross #define FEATURE_PATH_SIZE (SHUTDOWN_CMD_SIZE + sizeof("feature-")) 33244b3c7afSJuergen Gross char node[FEATURE_PATH_SIZE]; 333ec9b2065SIsaku Yamahata 334ec9b2065SIsaku Yamahata err = register_xenbus_watch(&shutdown_watch); 335ec9b2065SIsaku Yamahata if (err) { 336283c0972SJoe Perches pr_err("Failed to set shutdown watcher\n"); 337ec9b2065SIsaku Yamahata return err; 338ec9b2065SIsaku Yamahata } 339ec9b2065SIsaku Yamahata 340eb47f712SKonrad Rzeszutek Wilk 341f3bc3189SRandy Dunlap #ifdef CONFIG_MAGIC_SYSRQ 342ec9b2065SIsaku Yamahata err = register_xenbus_watch(&sysrq_watch); 343ec9b2065SIsaku Yamahata if (err) { 344283c0972SJoe Perches pr_err("Failed to set sysrq watcher\n"); 345ec9b2065SIsaku Yamahata return err; 346ec9b2065SIsaku Yamahata } 347f3bc3189SRandy Dunlap #endif 348ec9b2065SIsaku Yamahata 34944b3c7afSJuergen Gross for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) { 35044b3c7afSJuergen Gross if (!shutdown_handlers[idx].flag) 35144b3c7afSJuergen Gross continue; 35244b3c7afSJuergen Gross snprintf(node, FEATURE_PATH_SIZE, "feature-%s", 35344b3c7afSJuergen Gross shutdown_handlers[idx].command); 35484c029a7SZhouyang Jia err = xenbus_printf(XBT_NIL, "control", node, "%u", 1); 35584c029a7SZhouyang Jia if (err) { 35684c029a7SZhouyang Jia pr_err("%s: Error %d writing %s\n", __func__, 35784c029a7SZhouyang Jia err, node); 35884c029a7SZhouyang Jia return err; 35984c029a7SZhouyang Jia } 36044b3c7afSJuergen Gross } 36144b3c7afSJuergen Gross 362ec9b2065SIsaku Yamahata return 0; 363ec9b2065SIsaku Yamahata } 364ec9b2065SIsaku Yamahata 365ec9b2065SIsaku Yamahata static int shutdown_event(struct notifier_block *notifier, 366ec9b2065SIsaku Yamahata unsigned long event, 367ec9b2065SIsaku Yamahata void *data) 368ec9b2065SIsaku Yamahata { 369ec9b2065SIsaku Yamahata setup_shutdown_watcher(); 370ec9b2065SIsaku Yamahata return NOTIFY_DONE; 371ec9b2065SIsaku Yamahata } 372ec9b2065SIsaku Yamahata 373016b6f5fSStefano Stabellini int xen_setup_shutdown_event(void) 374ec9b2065SIsaku Yamahata { 375ec9b2065SIsaku Yamahata static struct notifier_block xenstore_notifier = { 376ec9b2065SIsaku Yamahata .notifier_call = shutdown_event 377ec9b2065SIsaku Yamahata }; 378702d4eb9SStefano Stabellini 379702d4eb9SStefano Stabellini if (!xen_domain()) 380702d4eb9SStefano Stabellini return -ENODEV; 381ec9b2065SIsaku Yamahata register_xenstore_notifier(&xenstore_notifier); 382eb47f712SKonrad Rzeszutek Wilk register_reboot_notifier(&xen_reboot_nb); 383ec9b2065SIsaku Yamahata 384ec9b2065SIsaku Yamahata return 0; 385ec9b2065SIsaku Yamahata } 386183d03ccSStefano Stabellini EXPORT_SYMBOL_GPL(xen_setup_shutdown_event); 387ec9b2065SIsaku Yamahata 388702d4eb9SStefano Stabellini subsys_initcall(xen_setup_shutdown_event); 389