1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ec9b2065SIsaku Yamahata /* 3ec9b2065SIsaku Yamahata * Handle extern requests for shutdown, reboot and sysrq 4ec9b2065SIsaku Yamahata */ 5283c0972SJoe Perches 6283c0972SJoe Perches #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 7283c0972SJoe Perches 8ec9b2065SIsaku Yamahata #include <linux/kernel.h> 9ec9b2065SIsaku Yamahata #include <linux/err.h> 105a0e3ad6STejun Heo #include <linux/slab.h> 11ec9b2065SIsaku Yamahata #include <linux/reboot.h> 12ec9b2065SIsaku Yamahata #include <linux/sysrq.h> 130e91398fSJeremy Fitzhardinge #include <linux/stop_machine.h> 140e91398fSJeremy Fitzhardinge #include <linux/freezer.h> 1519234c08SRafael J. Wysocki #include <linux/syscore_ops.h> 1663c9744bSPaul Gortmaker #include <linux/export.h> 17ec9b2065SIsaku Yamahata 18016b6f5fSStefano Stabellini #include <xen/xen.h> 19ec9b2065SIsaku Yamahata #include <xen/xenbus.h> 200e91398fSJeremy Fitzhardinge #include <xen/grant_table.h> 210e91398fSJeremy Fitzhardinge #include <xen/events.h> 220e91398fSJeremy Fitzhardinge #include <xen/hvc-console.h> 23a9fd60e2SJulien Grall #include <xen/page.h> 240e91398fSJeremy Fitzhardinge #include <xen/xen-ops.h> 25ec9b2065SIsaku Yamahata 260e91398fSJeremy Fitzhardinge #include <asm/xen/hypercall.h> 27016b6f5fSStefano Stabellini #include <asm/xen/hypervisor.h> 280e91398fSJeremy Fitzhardinge 290e91398fSJeremy Fitzhardinge enum shutdown_state { 300e91398fSJeremy Fitzhardinge SHUTDOWN_INVALID = -1, 310e91398fSJeremy Fitzhardinge SHUTDOWN_POWEROFF = 0, 320e91398fSJeremy Fitzhardinge SHUTDOWN_SUSPEND = 2, 33ec9b2065SIsaku Yamahata /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 340e91398fSJeremy Fitzhardinge report a crash, not be instructed to crash! 350e91398fSJeremy Fitzhardinge HALT is the same as POWEROFF, as far as we're concerned. The tools use 360e91398fSJeremy Fitzhardinge the distinction when we return the reason code to them. */ 370e91398fSJeremy Fitzhardinge SHUTDOWN_HALT = 4, 380e91398fSJeremy Fitzhardinge }; 39ec9b2065SIsaku Yamahata 40ec9b2065SIsaku Yamahata /* Ignore multiple shutdown requests. */ 410e91398fSJeremy Fitzhardinge static enum shutdown_state shutting_down = SHUTDOWN_INVALID; 420e91398fSJeremy Fitzhardinge 43ceb18029SIan Campbell struct suspend_info { 44ceb18029SIan Campbell int cancelled; 45ceb18029SIan Campbell }; 46ceb18029SIan Campbell 47cd979883SStanislaw Gruszka static RAW_NOTIFIER_HEAD(xen_resume_notifier); 48cd979883SStanislaw Gruszka 49cd979883SStanislaw Gruszka void xen_resume_notifier_register(struct notifier_block *nb) 50cd979883SStanislaw Gruszka { 51cd979883SStanislaw Gruszka raw_notifier_chain_register(&xen_resume_notifier, nb); 52cd979883SStanislaw Gruszka } 53cd979883SStanislaw Gruszka EXPORT_SYMBOL_GPL(xen_resume_notifier_register); 54cd979883SStanislaw Gruszka 55cd979883SStanislaw Gruszka void xen_resume_notifier_unregister(struct notifier_block *nb) 56cd979883SStanislaw Gruszka { 57cd979883SStanislaw Gruszka raw_notifier_chain_unregister(&xen_resume_notifier, nb); 58cd979883SStanislaw Gruszka } 59cd979883SStanislaw Gruszka EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister); 60cd979883SStanislaw Gruszka 6165e053a7SStefano Stabellini #ifdef CONFIG_HIBERNATE_CALLBACKS 620e91398fSJeremy Fitzhardinge static int xen_suspend(void *data) 630e91398fSJeremy Fitzhardinge { 64ceb18029SIan Campbell struct suspend_info *si = data; 65359cdd3fSJeremy Fitzhardinge int err; 660e91398fSJeremy Fitzhardinge 670e91398fSJeremy Fitzhardinge BUG_ON(!irqs_disabled()); 680e91398fSJeremy Fitzhardinge 6919234c08SRafael J. Wysocki err = syscore_suspend(); 70770824bdSRafael J. Wysocki if (err) { 71283c0972SJoe Perches pr_err("%s: system core suspend failed: %d\n", __func__, err); 72770824bdSRafael J. Wysocki return err; 73770824bdSRafael J. Wysocki } 74359cdd3fSJeremy Fitzhardinge 75aa8532c3SDavid Vrabel gnttab_suspend(); 765e25f5dbSDongli Zhang xen_manage_runstate_time(-1); 77aa8532c3SDavid Vrabel xen_arch_pre_suspend(); 780e91398fSJeremy Fitzhardinge 79aa8532c3SDavid Vrabel si->cancelled = HYPERVISOR_suspend(xen_pv_domain() 800df4f266SJulien Grall ? virt_to_gfn(xen_start_info) 81aa8532c3SDavid Vrabel : 0); 820e91398fSJeremy Fitzhardinge 83aa8532c3SDavid Vrabel xen_arch_post_suspend(si->cancelled); 845e25f5dbSDongli Zhang xen_manage_runstate_time(si->cancelled ? 1 : 0); 85aa8532c3SDavid Vrabel gnttab_resume(); 860e91398fSJeremy Fitzhardinge 87ceb18029SIan Campbell if (!si->cancelled) { 880e91398fSJeremy Fitzhardinge xen_irq_resume(); 89ad55db9fSIsaku Yamahata xen_timer_resume(); 900e91398fSJeremy Fitzhardinge } 910e91398fSJeremy Fitzhardinge 9219234c08SRafael J. Wysocki syscore_resume(); 931e6fcf84SIan Campbell 940e91398fSJeremy Fitzhardinge return 0; 950e91398fSJeremy Fitzhardinge } 960e91398fSJeremy Fitzhardinge 970e91398fSJeremy Fitzhardinge static void do_suspend(void) 980e91398fSJeremy Fitzhardinge { 990e91398fSJeremy Fitzhardinge int err; 100ceb18029SIan Campbell struct suspend_info si; 1010e91398fSJeremy Fitzhardinge 1020e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_SUSPEND; 1030e91398fSJeremy Fitzhardinge 1040e91398fSJeremy Fitzhardinge err = freeze_processes(); 1050e91398fSJeremy Fitzhardinge if (err) { 10672978b2fSRoss Lagerwall pr_err("%s: freeze processes failed %d\n", __func__, err); 1073fc1f1e2STejun Heo goto out; 1080e91398fSJeremy Fitzhardinge } 1090e91398fSJeremy Fitzhardinge 11072978b2fSRoss Lagerwall err = freeze_kernel_threads(); 11172978b2fSRoss Lagerwall if (err) { 11272978b2fSRoss Lagerwall pr_err("%s: freeze kernel threads failed %d\n", __func__, err); 11372978b2fSRoss Lagerwall goto out_thaw; 11472978b2fSRoss Lagerwall } 11572978b2fSRoss Lagerwall 116b3e96c0cSShriram Rajagopalan err = dpm_suspend_start(PMSG_FREEZE); 1170e91398fSJeremy Fitzhardinge if (err) { 118283c0972SJoe Perches pr_err("%s: dpm_suspend_start %d\n", __func__, err); 11965f63384SIan Campbell goto out_thaw; 1200e91398fSJeremy Fitzhardinge } 1210e91398fSJeremy Fitzhardinge 122c5cae661SIan Campbell printk(KERN_DEBUG "suspending xenstore...\n"); 123c5cae661SIan Campbell xs_suspend(); 124c5cae661SIan Campbell 125cf579dfbSRafael J. Wysocki err = dpm_suspend_end(PMSG_FREEZE); 1262ed8d2b3SRafael J. Wysocki if (err) { 127283c0972SJoe Perches pr_err("dpm_suspend_end failed: %d\n", err); 128186bab1cSKonrad Rzeszutek Wilk si.cancelled = 0; 12965f63384SIan Campbell goto out_resume; 1302ed8d2b3SRafael J. Wysocki } 1312ed8d2b3SRafael J. Wysocki 1322b953a5eSBoris Ostrovsky xen_arch_suspend(); 1332b953a5eSBoris Ostrovsky 134ceb18029SIan Campbell si.cancelled = 1; 135ceb18029SIan Campbell 136ceb18029SIan Campbell err = stop_machine(xen_suspend, &si, cpumask_of(0)); 137922cc38aSJeremy Fitzhardinge 1381b647823SDavid Vrabel /* Resume console as early as possible. */ 1391b647823SDavid Vrabel if (!si.cancelled) 1401b647823SDavid Vrabel xen_console_resume(); 1411b647823SDavid Vrabel 142cd979883SStanislaw Gruszka raw_notifier_call_chain(&xen_resume_notifier, 0, NULL); 143cd979883SStanislaw Gruszka 144*ff32baa1SJakub Kądziołka xen_arch_resume(); 145*ff32baa1SJakub Kądziołka 146cf579dfbSRafael J. Wysocki dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 147922cc38aSJeremy Fitzhardinge 1480e91398fSJeremy Fitzhardinge if (err) { 149283c0972SJoe Perches pr_err("failed to start xen_suspend: %d\n", err); 150ceb18029SIan Campbell si.cancelled = 1; 1510e91398fSJeremy Fitzhardinge } 1520e91398fSJeremy Fitzhardinge 1532b953a5eSBoris Ostrovsky out_resume: 1542b953a5eSBoris Ostrovsky if (!si.cancelled) 155de5b31bdSIan Campbell xs_resume(); 1562b953a5eSBoris Ostrovsky else 157de5b31bdSIan Campbell xs_suspend_cancel(); 1580e91398fSJeremy Fitzhardinge 159b3e96c0cSShriram Rajagopalan dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE); 1600e91398fSJeremy Fitzhardinge 16165f63384SIan Campbell out_thaw: 1620e91398fSJeremy Fitzhardinge thaw_processes(); 16365f63384SIan Campbell out: 1640e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 1650e91398fSJeremy Fitzhardinge } 1661f112ceeSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 167ec9b2065SIsaku Yamahata 16855271723SIan Campbell struct shutdown_handler { 16944b3c7afSJuergen Gross #define SHUTDOWN_CMD_SIZE 11 17044b3c7afSJuergen Gross const char command[SHUTDOWN_CMD_SIZE]; 17144b3c7afSJuergen Gross bool flag; 17255271723SIan Campbell void (*cb)(void); 17355271723SIan Campbell }; 17455271723SIan Campbell 175eb47f712SKonrad Rzeszutek Wilk static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused) 176eb47f712SKonrad Rzeszutek Wilk { 177eb47f712SKonrad Rzeszutek Wilk switch (code) { 178eb47f712SKonrad Rzeszutek Wilk case SYS_DOWN: 179eb47f712SKonrad Rzeszutek Wilk case SYS_HALT: 180eb47f712SKonrad Rzeszutek Wilk case SYS_POWER_OFF: 181eb47f712SKonrad Rzeszutek Wilk shutting_down = SHUTDOWN_POWEROFF; 1825e65f524SGustavo A. R. Silva break; 183eb47f712SKonrad Rzeszutek Wilk default: 184eb47f712SKonrad Rzeszutek Wilk break; 185eb47f712SKonrad Rzeszutek Wilk } 186eb47f712SKonrad Rzeszutek Wilk return NOTIFY_DONE; 187eb47f712SKonrad Rzeszutek Wilk } 18855271723SIan Campbell static void do_poweroff(void) 18955271723SIan Campbell { 190eb47f712SKonrad Rzeszutek Wilk switch (system_state) { 191eb47f712SKonrad Rzeszutek Wilk case SYSTEM_BOOTING: 19269a78ff2SThomas Gleixner case SYSTEM_SCHEDULING: 193eb47f712SKonrad Rzeszutek Wilk orderly_poweroff(true); 194eb47f712SKonrad Rzeszutek Wilk break; 195eb47f712SKonrad Rzeszutek Wilk case SYSTEM_RUNNING: 19655271723SIan Campbell orderly_poweroff(false); 197eb47f712SKonrad Rzeszutek Wilk break; 198eb47f712SKonrad Rzeszutek Wilk default: 199eb47f712SKonrad Rzeszutek Wilk /* Don't do it when we are halting/rebooting. */ 200eb47f712SKonrad Rzeszutek Wilk pr_info("Ignoring Xen toolstack shutdown.\n"); 201eb47f712SKonrad Rzeszutek Wilk break; 202eb47f712SKonrad Rzeszutek Wilk } 20355271723SIan Campbell } 20455271723SIan Campbell 20555271723SIan Campbell static void do_reboot(void) 20655271723SIan Campbell { 20755271723SIan Campbell shutting_down = SHUTDOWN_POWEROFF; /* ? */ 20855271723SIan Campbell ctrl_alt_del(); 20955271723SIan Campbell } 21055271723SIan Campbell 21144b3c7afSJuergen Gross static struct shutdown_handler shutdown_handlers[] = { 21244b3c7afSJuergen Gross { "poweroff", true, do_poweroff }, 21344b3c7afSJuergen Gross { "halt", false, do_poweroff }, 21444b3c7afSJuergen Gross { "reboot", true, do_reboot }, 21544b3c7afSJuergen Gross #ifdef CONFIG_HIBERNATE_CALLBACKS 21644b3c7afSJuergen Gross { "suspend", true, do_suspend }, 21744b3c7afSJuergen Gross #endif 21844b3c7afSJuergen Gross }; 21944b3c7afSJuergen Gross 220ec9b2065SIsaku Yamahata static void shutdown_handler(struct xenbus_watch *watch, 2215584ea25SJuergen Gross const char *path, const char *token) 222ec9b2065SIsaku Yamahata { 223ec9b2065SIsaku Yamahata char *str; 224ec9b2065SIsaku Yamahata struct xenbus_transaction xbt; 225ec9b2065SIsaku Yamahata int err; 22644b3c7afSJuergen Gross int idx; 227ec9b2065SIsaku Yamahata 228ec9b2065SIsaku Yamahata if (shutting_down != SHUTDOWN_INVALID) 229ec9b2065SIsaku Yamahata return; 230ec9b2065SIsaku Yamahata 231ec9b2065SIsaku Yamahata again: 232ec9b2065SIsaku Yamahata err = xenbus_transaction_start(&xbt); 233ec9b2065SIsaku Yamahata if (err) 234ec9b2065SIsaku Yamahata return; 235ec9b2065SIsaku Yamahata 236ec9b2065SIsaku Yamahata str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); 237ec9b2065SIsaku Yamahata /* Ignore read errors and empty reads. */ 238ec9b2065SIsaku Yamahata if (XENBUS_IS_ERR_READ(str)) { 239ec9b2065SIsaku Yamahata xenbus_transaction_end(xbt, 1); 240ec9b2065SIsaku Yamahata return; 241ec9b2065SIsaku Yamahata } 242ec9b2065SIsaku Yamahata 24344b3c7afSJuergen Gross for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) { 24444b3c7afSJuergen Gross if (strcmp(str, shutdown_handlers[idx].command) == 0) 24555271723SIan Campbell break; 24655271723SIan Campbell } 24755271723SIan Campbell 24855271723SIan Campbell /* Only acknowledge commands which we are prepared to handle. */ 24944b3c7afSJuergen Gross if (idx < ARRAY_SIZE(shutdown_handlers)) 250ec9b2065SIsaku Yamahata xenbus_write(xbt, "control", "shutdown", ""); 251ec9b2065SIsaku Yamahata 252ec9b2065SIsaku Yamahata err = xenbus_transaction_end(xbt, 0); 253ec9b2065SIsaku Yamahata if (err == -EAGAIN) { 254ec9b2065SIsaku Yamahata kfree(str); 255ec9b2065SIsaku Yamahata goto again; 256ec9b2065SIsaku Yamahata } 257ec9b2065SIsaku Yamahata 25844b3c7afSJuergen Gross if (idx < ARRAY_SIZE(shutdown_handlers)) { 25944b3c7afSJuergen Gross shutdown_handlers[idx].cb(); 2600e91398fSJeremy Fitzhardinge } else { 261283c0972SJoe Perches pr_info("Ignoring shutdown request: %s\n", str); 262ec9b2065SIsaku Yamahata shutting_down = SHUTDOWN_INVALID; 263ec9b2065SIsaku Yamahata } 264ec9b2065SIsaku Yamahata 265ec9b2065SIsaku Yamahata kfree(str); 266ec9b2065SIsaku Yamahata } 267ec9b2065SIsaku Yamahata 268f3bc3189SRandy Dunlap #ifdef CONFIG_MAGIC_SYSRQ 2695584ea25SJuergen Gross static void sysrq_handler(struct xenbus_watch *watch, const char *path, 2705584ea25SJuergen Gross const char *token) 271ec9b2065SIsaku Yamahata { 272ec9b2065SIsaku Yamahata char sysrq_key = '\0'; 273ec9b2065SIsaku Yamahata struct xenbus_transaction xbt; 274ec9b2065SIsaku Yamahata int err; 275ec9b2065SIsaku Yamahata 276ec9b2065SIsaku Yamahata again: 277ec9b2065SIsaku Yamahata err = xenbus_transaction_start(&xbt); 278ec9b2065SIsaku Yamahata if (err) 279ec9b2065SIsaku Yamahata return; 2804e93b648SJuergen Gross err = xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key); 2814e93b648SJuergen Gross if (err < 0) { 2824e93b648SJuergen Gross /* 2834e93b648SJuergen Gross * The Xenstore watch fires directly after registering it and 2844e93b648SJuergen Gross * after a suspend/resume cycle. So ENOENT is no error but 28587dffe86SVitaly Kuznetsov * might happen in those cases. ERANGE is observed when we get 28687dffe86SVitaly Kuznetsov * an empty value (''), this happens when we acknowledge the 28787dffe86SVitaly Kuznetsov * request by writing '\0' below. 2884e93b648SJuergen Gross */ 28987dffe86SVitaly Kuznetsov if (err != -ENOENT && err != -ERANGE) 2904e93b648SJuergen Gross pr_err("Error %d reading sysrq code in control/sysrq\n", 2914e93b648SJuergen Gross err); 292ec9b2065SIsaku Yamahata xenbus_transaction_end(xbt, 1); 293ec9b2065SIsaku Yamahata return; 294ec9b2065SIsaku Yamahata } 295ec9b2065SIsaku Yamahata 29684c029a7SZhouyang Jia if (sysrq_key != '\0') { 29784c029a7SZhouyang Jia err = xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); 29884c029a7SZhouyang Jia if (err) { 29984c029a7SZhouyang Jia pr_err("%s: Error %d writing sysrq in control/sysrq\n", 30084c029a7SZhouyang Jia __func__, err); 30184c029a7SZhouyang Jia xenbus_transaction_end(xbt, 1); 30284c029a7SZhouyang Jia return; 30384c029a7SZhouyang Jia } 30484c029a7SZhouyang Jia } 305ec9b2065SIsaku Yamahata 306ec9b2065SIsaku Yamahata err = xenbus_transaction_end(xbt, 0); 307ec9b2065SIsaku Yamahata if (err == -EAGAIN) 308ec9b2065SIsaku Yamahata goto again; 309ec9b2065SIsaku Yamahata 310ec9b2065SIsaku Yamahata if (sysrq_key != '\0') 311f335397dSDmitry Torokhov handle_sysrq(sysrq_key); 312ec9b2065SIsaku Yamahata } 313ec9b2065SIsaku Yamahata 314ec9b2065SIsaku Yamahata static struct xenbus_watch sysrq_watch = { 315ec9b2065SIsaku Yamahata .node = "control/sysrq", 316ec9b2065SIsaku Yamahata .callback = sysrq_handler 317ec9b2065SIsaku Yamahata }; 318f3bc3189SRandy Dunlap #endif 319f3bc3189SRandy Dunlap 320f3bc3189SRandy Dunlap static struct xenbus_watch shutdown_watch = { 321f3bc3189SRandy Dunlap .node = "control/shutdown", 322f3bc3189SRandy Dunlap .callback = shutdown_handler 323f3bc3189SRandy Dunlap }; 324ec9b2065SIsaku Yamahata 325eb47f712SKonrad Rzeszutek Wilk static struct notifier_block xen_reboot_nb = { 326eb47f712SKonrad Rzeszutek Wilk .notifier_call = poweroff_nb, 327eb47f712SKonrad Rzeszutek Wilk }; 328eb47f712SKonrad Rzeszutek Wilk 329ec9b2065SIsaku Yamahata static int setup_shutdown_watcher(void) 330ec9b2065SIsaku Yamahata { 331ec9b2065SIsaku Yamahata int err; 33244b3c7afSJuergen Gross int idx; 33344b3c7afSJuergen Gross #define FEATURE_PATH_SIZE (SHUTDOWN_CMD_SIZE + sizeof("feature-")) 33444b3c7afSJuergen Gross char node[FEATURE_PATH_SIZE]; 335ec9b2065SIsaku Yamahata 336ec9b2065SIsaku Yamahata err = register_xenbus_watch(&shutdown_watch); 337ec9b2065SIsaku Yamahata if (err) { 338283c0972SJoe Perches pr_err("Failed to set shutdown watcher\n"); 339ec9b2065SIsaku Yamahata return err; 340ec9b2065SIsaku Yamahata } 341ec9b2065SIsaku Yamahata 342eb47f712SKonrad Rzeszutek Wilk 343f3bc3189SRandy Dunlap #ifdef CONFIG_MAGIC_SYSRQ 344ec9b2065SIsaku Yamahata err = register_xenbus_watch(&sysrq_watch); 345ec9b2065SIsaku Yamahata if (err) { 346283c0972SJoe Perches pr_err("Failed to set sysrq watcher\n"); 347ec9b2065SIsaku Yamahata return err; 348ec9b2065SIsaku Yamahata } 349f3bc3189SRandy Dunlap #endif 350ec9b2065SIsaku Yamahata 35144b3c7afSJuergen Gross for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) { 35244b3c7afSJuergen Gross if (!shutdown_handlers[idx].flag) 35344b3c7afSJuergen Gross continue; 35444b3c7afSJuergen Gross snprintf(node, FEATURE_PATH_SIZE, "feature-%s", 35544b3c7afSJuergen Gross shutdown_handlers[idx].command); 35684c029a7SZhouyang Jia err = xenbus_printf(XBT_NIL, "control", node, "%u", 1); 35784c029a7SZhouyang Jia if (err) { 35884c029a7SZhouyang Jia pr_err("%s: Error %d writing %s\n", __func__, 35984c029a7SZhouyang Jia err, node); 36084c029a7SZhouyang Jia return err; 36184c029a7SZhouyang Jia } 36244b3c7afSJuergen Gross } 36344b3c7afSJuergen Gross 364ec9b2065SIsaku Yamahata return 0; 365ec9b2065SIsaku Yamahata } 366ec9b2065SIsaku Yamahata 367ec9b2065SIsaku Yamahata static int shutdown_event(struct notifier_block *notifier, 368ec9b2065SIsaku Yamahata unsigned long event, 369ec9b2065SIsaku Yamahata void *data) 370ec9b2065SIsaku Yamahata { 371ec9b2065SIsaku Yamahata setup_shutdown_watcher(); 372ec9b2065SIsaku Yamahata return NOTIFY_DONE; 373ec9b2065SIsaku Yamahata } 374ec9b2065SIsaku Yamahata 375016b6f5fSStefano Stabellini int xen_setup_shutdown_event(void) 376ec9b2065SIsaku Yamahata { 377ec9b2065SIsaku Yamahata static struct notifier_block xenstore_notifier = { 378ec9b2065SIsaku Yamahata .notifier_call = shutdown_event 379ec9b2065SIsaku Yamahata }; 380702d4eb9SStefano Stabellini 381702d4eb9SStefano Stabellini if (!xen_domain()) 382702d4eb9SStefano Stabellini return -ENODEV; 383ec9b2065SIsaku Yamahata register_xenstore_notifier(&xenstore_notifier); 384eb47f712SKonrad Rzeszutek Wilk register_reboot_notifier(&xen_reboot_nb); 385ec9b2065SIsaku Yamahata 386ec9b2065SIsaku Yamahata return 0; 387ec9b2065SIsaku Yamahata } 388183d03ccSStefano Stabellini EXPORT_SYMBOL_GPL(xen_setup_shutdown_event); 389ec9b2065SIsaku Yamahata 390702d4eb9SStefano Stabellini subsys_initcall(xen_setup_shutdown_event); 391