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