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 17static int hv_supports_soft_state; 18 19static 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 26static 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 41static const char booting_msg[32] __attribute__((aligned(32))) = 42 "Linux booting"; 43static const char running_msg[32] __attribute__((aligned(32))) = 44 "Linux running"; 45static const char halting_msg[32] __attribute__((aligned(32))) = 46 "Linux halting"; 47static const char poweroff_msg[32] __attribute__((aligned(32))) = 48 "Linux powering off"; 49static const char rebooting_msg[32] __attribute__((aligned(32))) = 50 "Linux rebooting"; 51static const char panicing_msg[32] __attribute__((aligned(32))) = 52 "Linux panicing"; 53 54static 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 78static struct notifier_block sstate_reboot_notifier = { 79 .notifier_call = sstate_reboot_call, 80}; 81 82static 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 89static struct notifier_block sstate_panic_block = { 90 .notifier_call = sstate_panic_event, 91 .priority = INT_MAX, 92}; 93 94static 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 119core_initcall(sstate_init); 120 121static int __init sstate_running(void) 122{ 123 do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); 124 return 0; 125} 126 127late_initcall(sstate_running); 128