1ec9b2065SIsaku Yamahata /* 2ec9b2065SIsaku Yamahata * Handle extern requests for shutdown, reboot and sysrq 3ec9b2065SIsaku Yamahata */ 4ec9b2065SIsaku Yamahata #include <linux/kernel.h> 5ec9b2065SIsaku Yamahata #include <linux/err.h> 6ec9b2065SIsaku Yamahata #include <linux/reboot.h> 7ec9b2065SIsaku Yamahata #include <linux/sysrq.h> 80e91398fSJeremy Fitzhardinge #include <linux/stop_machine.h> 90e91398fSJeremy Fitzhardinge #include <linux/freezer.h> 10ec9b2065SIsaku Yamahata 11ec9b2065SIsaku Yamahata #include <xen/xenbus.h> 120e91398fSJeremy Fitzhardinge #include <xen/grant_table.h> 130e91398fSJeremy Fitzhardinge #include <xen/events.h> 140e91398fSJeremy Fitzhardinge #include <xen/hvc-console.h> 150e91398fSJeremy Fitzhardinge #include <xen/xen-ops.h> 16ec9b2065SIsaku Yamahata 170e91398fSJeremy Fitzhardinge #include <asm/xen/hypercall.h> 180e91398fSJeremy Fitzhardinge #include <asm/xen/page.h> 190e91398fSJeremy Fitzhardinge 200e91398fSJeremy Fitzhardinge enum shutdown_state { 210e91398fSJeremy Fitzhardinge SHUTDOWN_INVALID = -1, 220e91398fSJeremy Fitzhardinge SHUTDOWN_POWEROFF = 0, 230e91398fSJeremy Fitzhardinge SHUTDOWN_SUSPEND = 2, 24ec9b2065SIsaku Yamahata /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 250e91398fSJeremy Fitzhardinge report a crash, not be instructed to crash! 260e91398fSJeremy Fitzhardinge HALT is the same as POWEROFF, as far as we're concerned. The tools use 270e91398fSJeremy Fitzhardinge the distinction when we return the reason code to them. */ 280e91398fSJeremy Fitzhardinge SHUTDOWN_HALT = 4, 290e91398fSJeremy Fitzhardinge }; 30ec9b2065SIsaku Yamahata 31ec9b2065SIsaku Yamahata /* Ignore multiple shutdown requests. */ 320e91398fSJeremy Fitzhardinge static enum shutdown_state shutting_down = SHUTDOWN_INVALID; 330e91398fSJeremy Fitzhardinge 34c7827728SJeremy Fitzhardinge #ifdef CONFIG_PM_SLEEP 350e91398fSJeremy Fitzhardinge static int xen_suspend(void *data) 360e91398fSJeremy Fitzhardinge { 370e91398fSJeremy Fitzhardinge int *cancelled = data; 38359cdd3fSJeremy Fitzhardinge int err; 390e91398fSJeremy Fitzhardinge 400e91398fSJeremy Fitzhardinge BUG_ON(!irqs_disabled()); 410e91398fSJeremy Fitzhardinge 42359cdd3fSJeremy Fitzhardinge err = device_power_down(PMSG_SUSPEND); 43359cdd3fSJeremy Fitzhardinge if (err) { 44359cdd3fSJeremy Fitzhardinge printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n", 45359cdd3fSJeremy Fitzhardinge err); 46359cdd3fSJeremy Fitzhardinge return err; 47359cdd3fSJeremy Fitzhardinge } 48770824bdSRafael J. Wysocki err = sysdev_suspend(PMSG_SUSPEND); 49770824bdSRafael J. Wysocki if (err) { 50770824bdSRafael J. Wysocki printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", 51770824bdSRafael J. Wysocki err); 52770824bdSRafael J. Wysocki device_power_up(PMSG_RESUME); 53770824bdSRafael J. Wysocki return err; 54770824bdSRafael J. Wysocki } 55359cdd3fSJeremy Fitzhardinge 560e91398fSJeremy Fitzhardinge xen_mm_pin_all(); 570e91398fSJeremy Fitzhardinge gnttab_suspend(); 580e91398fSJeremy Fitzhardinge xen_pre_suspend(); 590e91398fSJeremy Fitzhardinge 600e91398fSJeremy Fitzhardinge /* 610e91398fSJeremy Fitzhardinge * This hypercall returns 1 if suspend was cancelled 620e91398fSJeremy Fitzhardinge * or the domain was merely checkpointed, and 0 if it 630e91398fSJeremy Fitzhardinge * is resuming in a new domain. 640e91398fSJeremy Fitzhardinge */ 650e91398fSJeremy Fitzhardinge *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); 660e91398fSJeremy Fitzhardinge 670e91398fSJeremy Fitzhardinge xen_post_suspend(*cancelled); 680e91398fSJeremy Fitzhardinge gnttab_resume(); 690e91398fSJeremy Fitzhardinge xen_mm_unpin_all(); 700e91398fSJeremy Fitzhardinge 710e91398fSJeremy Fitzhardinge if (!*cancelled) { 720e91398fSJeremy Fitzhardinge xen_irq_resume(); 730e91398fSJeremy Fitzhardinge xen_console_resume(); 74ad55db9fSIsaku Yamahata xen_timer_resume(); 750e91398fSJeremy Fitzhardinge } 760e91398fSJeremy Fitzhardinge 771e6fcf84SIan Campbell sysdev_resume(); 781e6fcf84SIan Campbell device_power_up(PMSG_RESUME); 791e6fcf84SIan Campbell 800e91398fSJeremy Fitzhardinge return 0; 810e91398fSJeremy Fitzhardinge } 820e91398fSJeremy Fitzhardinge 830e91398fSJeremy Fitzhardinge static void do_suspend(void) 840e91398fSJeremy Fitzhardinge { 850e91398fSJeremy Fitzhardinge int err; 860e91398fSJeremy Fitzhardinge int cancelled = 1; 870e91398fSJeremy Fitzhardinge 880e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_SUSPEND; 890e91398fSJeremy Fitzhardinge 900e91398fSJeremy Fitzhardinge #ifdef CONFIG_PREEMPT 910e91398fSJeremy Fitzhardinge /* If the kernel is preemptible, we need to freeze all the processes 920e91398fSJeremy Fitzhardinge to prevent them from being in the middle of a pagetable update 930e91398fSJeremy Fitzhardinge during suspend. */ 940e91398fSJeremy Fitzhardinge err = freeze_processes(); 950e91398fSJeremy Fitzhardinge if (err) { 960e91398fSJeremy Fitzhardinge printk(KERN_ERR "xen suspend: freeze failed %d\n", err); 970e91398fSJeremy Fitzhardinge return; 980e91398fSJeremy Fitzhardinge } 990e91398fSJeremy Fitzhardinge #endif 1000e91398fSJeremy Fitzhardinge 1010e91398fSJeremy Fitzhardinge err = device_suspend(PMSG_SUSPEND); 1020e91398fSJeremy Fitzhardinge if (err) { 1030e91398fSJeremy Fitzhardinge printk(KERN_ERR "xen suspend: device_suspend %d\n", err); 1040e91398fSJeremy Fitzhardinge goto out; 1050e91398fSJeremy Fitzhardinge } 1060e91398fSJeremy Fitzhardinge 1070e91398fSJeremy Fitzhardinge printk("suspending xenbus...\n"); 1080e91398fSJeremy Fitzhardinge /* XXX use normal device tree? */ 1090e91398fSJeremy Fitzhardinge xenbus_suspend(); 1100e91398fSJeremy Fitzhardinge 111f7df8ed1SRusty Russell err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); 1120e91398fSJeremy Fitzhardinge if (err) { 1130e91398fSJeremy Fitzhardinge printk(KERN_ERR "failed to start xen_suspend: %d\n", err); 1140e91398fSJeremy Fitzhardinge goto out; 1150e91398fSJeremy Fitzhardinge } 1160e91398fSJeremy Fitzhardinge 117ad55db9fSIsaku Yamahata if (!cancelled) { 118ad55db9fSIsaku Yamahata xen_arch_resume(); 1190e91398fSJeremy Fitzhardinge xenbus_resume(); 120ad55db9fSIsaku Yamahata } else 1210e91398fSJeremy Fitzhardinge xenbus_suspend_cancel(); 1220e91398fSJeremy Fitzhardinge 12355ca089eSStephen Rothwell device_resume(PMSG_RESUME); 1240e91398fSJeremy Fitzhardinge 125359cdd3fSJeremy Fitzhardinge /* Make sure timer events get retriggered on all CPUs */ 126359cdd3fSJeremy Fitzhardinge clock_was_set(); 1270e91398fSJeremy Fitzhardinge out: 1280e91398fSJeremy Fitzhardinge #ifdef CONFIG_PREEMPT 1290e91398fSJeremy Fitzhardinge thaw_processes(); 1300e91398fSJeremy Fitzhardinge #endif 1310e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_INVALID; 1320e91398fSJeremy Fitzhardinge } 133c7827728SJeremy Fitzhardinge #endif /* CONFIG_PM_SLEEP */ 134ec9b2065SIsaku Yamahata 135ec9b2065SIsaku Yamahata static void shutdown_handler(struct xenbus_watch *watch, 136ec9b2065SIsaku Yamahata const char **vec, unsigned int len) 137ec9b2065SIsaku Yamahata { 138ec9b2065SIsaku Yamahata char *str; 139ec9b2065SIsaku Yamahata struct xenbus_transaction xbt; 140ec9b2065SIsaku Yamahata int err; 141ec9b2065SIsaku Yamahata 142ec9b2065SIsaku Yamahata if (shutting_down != SHUTDOWN_INVALID) 143ec9b2065SIsaku Yamahata return; 144ec9b2065SIsaku Yamahata 145ec9b2065SIsaku Yamahata again: 146ec9b2065SIsaku Yamahata err = xenbus_transaction_start(&xbt); 147ec9b2065SIsaku Yamahata if (err) 148ec9b2065SIsaku Yamahata return; 149ec9b2065SIsaku Yamahata 150ec9b2065SIsaku Yamahata str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); 151ec9b2065SIsaku Yamahata /* Ignore read errors and empty reads. */ 152ec9b2065SIsaku Yamahata if (XENBUS_IS_ERR_READ(str)) { 153ec9b2065SIsaku Yamahata xenbus_transaction_end(xbt, 1); 154ec9b2065SIsaku Yamahata return; 155ec9b2065SIsaku Yamahata } 156ec9b2065SIsaku Yamahata 157ec9b2065SIsaku Yamahata xenbus_write(xbt, "control", "shutdown", ""); 158ec9b2065SIsaku Yamahata 159ec9b2065SIsaku Yamahata err = xenbus_transaction_end(xbt, 0); 160ec9b2065SIsaku Yamahata if (err == -EAGAIN) { 161ec9b2065SIsaku Yamahata kfree(str); 162ec9b2065SIsaku Yamahata goto again; 163ec9b2065SIsaku Yamahata } 164ec9b2065SIsaku Yamahata 165ec9b2065SIsaku Yamahata if (strcmp(str, "poweroff") == 0 || 1660e91398fSJeremy Fitzhardinge strcmp(str, "halt") == 0) { 1670e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_POWEROFF; 168ec9b2065SIsaku Yamahata orderly_poweroff(false); 1690e91398fSJeremy Fitzhardinge } else if (strcmp(str, "reboot") == 0) { 1700e91398fSJeremy Fitzhardinge shutting_down = SHUTDOWN_POWEROFF; /* ? */ 171ec9b2065SIsaku Yamahata ctrl_alt_del(); 1720e91398fSJeremy Fitzhardinge #ifdef CONFIG_PM_SLEEP 1730e91398fSJeremy Fitzhardinge } else if (strcmp(str, "suspend") == 0) { 1740e91398fSJeremy Fitzhardinge do_suspend(); 1750e91398fSJeremy Fitzhardinge #endif 1760e91398fSJeremy Fitzhardinge } else { 177ec9b2065SIsaku Yamahata printk(KERN_INFO "Ignoring shutdown request: %s\n", str); 178ec9b2065SIsaku Yamahata shutting_down = SHUTDOWN_INVALID; 179ec9b2065SIsaku Yamahata } 180ec9b2065SIsaku Yamahata 181ec9b2065SIsaku Yamahata kfree(str); 182ec9b2065SIsaku Yamahata } 183ec9b2065SIsaku Yamahata 184ec9b2065SIsaku Yamahata static void sysrq_handler(struct xenbus_watch *watch, const char **vec, 185ec9b2065SIsaku Yamahata unsigned int len) 186ec9b2065SIsaku Yamahata { 187ec9b2065SIsaku Yamahata char sysrq_key = '\0'; 188ec9b2065SIsaku Yamahata struct xenbus_transaction xbt; 189ec9b2065SIsaku Yamahata int err; 190ec9b2065SIsaku Yamahata 191ec9b2065SIsaku Yamahata again: 192ec9b2065SIsaku Yamahata err = xenbus_transaction_start(&xbt); 193ec9b2065SIsaku Yamahata if (err) 194ec9b2065SIsaku Yamahata return; 195ec9b2065SIsaku Yamahata if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { 196ec9b2065SIsaku Yamahata printk(KERN_ERR "Unable to read sysrq code in " 197ec9b2065SIsaku Yamahata "control/sysrq\n"); 198ec9b2065SIsaku Yamahata xenbus_transaction_end(xbt, 1); 199ec9b2065SIsaku Yamahata return; 200ec9b2065SIsaku Yamahata } 201ec9b2065SIsaku Yamahata 202ec9b2065SIsaku Yamahata if (sysrq_key != '\0') 203ec9b2065SIsaku Yamahata xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); 204ec9b2065SIsaku Yamahata 205ec9b2065SIsaku Yamahata err = xenbus_transaction_end(xbt, 0); 206ec9b2065SIsaku Yamahata if (err == -EAGAIN) 207ec9b2065SIsaku Yamahata goto again; 208ec9b2065SIsaku Yamahata 209ec9b2065SIsaku Yamahata if (sysrq_key != '\0') 210ec9b2065SIsaku Yamahata handle_sysrq(sysrq_key, NULL); 211ec9b2065SIsaku Yamahata } 212ec9b2065SIsaku Yamahata 213ec9b2065SIsaku Yamahata static struct xenbus_watch shutdown_watch = { 214ec9b2065SIsaku Yamahata .node = "control/shutdown", 215ec9b2065SIsaku Yamahata .callback = shutdown_handler 216ec9b2065SIsaku Yamahata }; 217ec9b2065SIsaku Yamahata 218ec9b2065SIsaku Yamahata static struct xenbus_watch sysrq_watch = { 219ec9b2065SIsaku Yamahata .node = "control/sysrq", 220ec9b2065SIsaku Yamahata .callback = sysrq_handler 221ec9b2065SIsaku Yamahata }; 222ec9b2065SIsaku Yamahata 223ec9b2065SIsaku Yamahata static int setup_shutdown_watcher(void) 224ec9b2065SIsaku Yamahata { 225ec9b2065SIsaku Yamahata int err; 226ec9b2065SIsaku Yamahata 227ec9b2065SIsaku Yamahata err = register_xenbus_watch(&shutdown_watch); 228ec9b2065SIsaku Yamahata if (err) { 229ec9b2065SIsaku Yamahata printk(KERN_ERR "Failed to set shutdown watcher\n"); 230ec9b2065SIsaku Yamahata return err; 231ec9b2065SIsaku Yamahata } 232ec9b2065SIsaku Yamahata 233ec9b2065SIsaku Yamahata err = register_xenbus_watch(&sysrq_watch); 234ec9b2065SIsaku Yamahata if (err) { 235ec9b2065SIsaku Yamahata printk(KERN_ERR "Failed to set sysrq watcher\n"); 236ec9b2065SIsaku Yamahata return err; 237ec9b2065SIsaku Yamahata } 238ec9b2065SIsaku Yamahata 239ec9b2065SIsaku Yamahata return 0; 240ec9b2065SIsaku Yamahata } 241ec9b2065SIsaku Yamahata 242ec9b2065SIsaku Yamahata static int shutdown_event(struct notifier_block *notifier, 243ec9b2065SIsaku Yamahata unsigned long event, 244ec9b2065SIsaku Yamahata void *data) 245ec9b2065SIsaku Yamahata { 246ec9b2065SIsaku Yamahata setup_shutdown_watcher(); 247ec9b2065SIsaku Yamahata return NOTIFY_DONE; 248ec9b2065SIsaku Yamahata } 249ec9b2065SIsaku Yamahata 250ec9b2065SIsaku Yamahata static int __init setup_shutdown_event(void) 251ec9b2065SIsaku Yamahata { 252ec9b2065SIsaku Yamahata static struct notifier_block xenstore_notifier = { 253ec9b2065SIsaku Yamahata .notifier_call = shutdown_event 254ec9b2065SIsaku Yamahata }; 255ec9b2065SIsaku Yamahata register_xenstore_notifier(&xenstore_notifier); 256ec9b2065SIsaku Yamahata 257ec9b2065SIsaku Yamahata return 0; 258ec9b2065SIsaku Yamahata } 259ec9b2065SIsaku Yamahata 260ec9b2065SIsaku Yamahata subsys_initcall(setup_shutdown_event); 261