1 /* sstate.c: System soft state support. 2 * 3 * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/notifier.h> 8 #include <linux/reboot.h> 9 #include <linux/init.h> 10 11 #include <asm/hypervisor.h> 12 #include <asm/spitfire.h> 13 #include <asm/oplib.h> 14 #include <asm/head.h> 15 #include <asm/io.h> 16 17 static int hv_supports_soft_state; 18 19 static unsigned long kimage_addr_to_ra(const char *p) 20 { 21 unsigned long val = (unsigned long) p; 22 23 return kern_base + (val - KERNBASE); 24 } 25 26 static void do_set_sstate(unsigned long state, const char *msg) 27 { 28 unsigned long err; 29 30 if (!hv_supports_soft_state) 31 return; 32 33 err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg)); 34 if (err) { 35 printk(KERN_WARNING "SSTATE: Failed to set soft-state to " 36 "state[%lx] msg[%s], err=%lu\n", 37 state, msg, err); 38 } 39 } 40 41 static const char booting_msg[32] __attribute__((aligned(32))) = 42 "Linux booting"; 43 static const char running_msg[32] __attribute__((aligned(32))) = 44 "Linux running"; 45 static const char halting_msg[32] __attribute__((aligned(32))) = 46 "Linux halting"; 47 static const char poweroff_msg[32] __attribute__((aligned(32))) = 48 "Linux powering off"; 49 static const char rebooting_msg[32] __attribute__((aligned(32))) = 50 "Linux rebooting"; 51 static const char panicing_msg[32] __attribute__((aligned(32))) = 52 "Linux panicing"; 53 54 static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused) 55 { 56 const char *msg; 57 58 switch (type) { 59 case SYS_DOWN: 60 default: 61 msg = rebooting_msg; 62 break; 63 64 case SYS_HALT: 65 msg = halting_msg; 66 break; 67 68 case SYS_POWER_OFF: 69 msg = poweroff_msg; 70 break; 71 } 72 73 do_set_sstate(HV_SOFT_STATE_TRANSITION, msg); 74 75 return NOTIFY_OK; 76 } 77 78 static struct notifier_block sstate_reboot_notifier = { 79 .notifier_call = sstate_reboot_call, 80 }; 81 82 static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) 83 { 84 do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg); 85 86 return NOTIFY_DONE; 87 } 88 89 static struct notifier_block sstate_panic_block = { 90 .notifier_call = sstate_panic_event, 91 .priority = INT_MAX, 92 }; 93 94 static int __init sstate_init(void) 95 { 96 unsigned long major, minor; 97 98 if (tlb_type != hypervisor) 99 return 0; 100 101 major = 1; 102 minor = 0; 103 if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor)) 104 return 0; 105 106 hv_supports_soft_state = 1; 107 108 prom_sun4v_guest_soft_state(); 109 110 do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); 111 112 atomic_notifier_chain_register(&panic_notifier_list, 113 &sstate_panic_block); 114 register_reboot_notifier(&sstate_reboot_notifier); 115 116 return 0; 117 } 118 119 core_initcall(sstate_init); 120 121 static int __init sstate_running(void) 122 { 123 do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); 124 return 0; 125 } 126 127 late_initcall(sstate_running); 128